diff --git a/assets/svg/exchange_icons/trocador.svg b/assets/svg/exchange_icons/trocador.svg
new file mode 100644
index 000000000..b3d9171ff
--- /dev/null
+++ b/assets/svg/exchange_icons/trocador.svg
@@ -0,0 +1,3 @@
+
diff --git a/assets/svg/trocador_rating_a.svg b/assets/svg/trocador_rating_a.svg
new file mode 100644
index 000000000..1e75af73b
--- /dev/null
+++ b/assets/svg/trocador_rating_a.svg
@@ -0,0 +1,10 @@
+
diff --git a/assets/svg/trocador_rating_b.svg b/assets/svg/trocador_rating_b.svg
new file mode 100644
index 000000000..5d678305a
--- /dev/null
+++ b/assets/svg/trocador_rating_b.svg
@@ -0,0 +1,10 @@
+
diff --git a/assets/svg/trocador_rating_c.svg b/assets/svg/trocador_rating_c.svg
new file mode 100644
index 000000000..87ecf6b24
--- /dev/null
+++ b/assets/svg/trocador_rating_c.svg
@@ -0,0 +1,10 @@
+
diff --git a/assets/svg/trocador_rating_d.svg b/assets/svg/trocador_rating_d.svg
new file mode 100644
index 000000000..8973c7e65
--- /dev/null
+++ b/assets/svg/trocador_rating_d.svg
@@ -0,0 +1,10 @@
+
diff --git a/lib/main.dart b/lib/main.dart
index e08324572..10d1c4a12 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -299,7 +299,8 @@ class _MaterialAppWithThemeState extends ConsumerState
await ref.read(prefsChangeNotifierProvider).isExternalCallsSet()) {
if (Constants.enableExchange) {
await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty(
- ref.read(exchangeFormStateProvider),
+ ref.read(efCurrencyPairProvider),
+ ref.read(efRateTypeProvider),
);
unawaited(ExchangeDataLoadingService.instance.loadAll());
}
diff --git a/lib/models/exchange/active_pair.dart b/lib/models/exchange/active_pair.dart
new file mode 100644
index 000000000..4a2e80eba
--- /dev/null
+++ b/lib/models/exchange/active_pair.dart
@@ -0,0 +1,35 @@
+import 'package:flutter/foundation.dart';
+import 'package:stackwallet/models/exchange/aggregate_currency.dart';
+
+class ActivePair extends ChangeNotifier {
+ AggregateCurrency? _send;
+ AggregateCurrency? _receive;
+
+ AggregateCurrency? get send => _send;
+ AggregateCurrency? get receive => _receive;
+
+ void setSend(
+ AggregateCurrency? newSend, {
+ bool notifyListeners = false,
+ }) {
+ _send = newSend;
+ if (notifyListeners) {
+ this.notifyListeners();
+ }
+ }
+
+ void setReceive(
+ AggregateCurrency? newReceive, {
+ bool notifyListeners = false,
+ }) {
+ _receive = newReceive;
+ if (notifyListeners) {
+ this.notifyListeners();
+ }
+ }
+
+ @override
+ String toString() {
+ return "ActivePair{ send: $send, receive: $receive }";
+ }
+}
diff --git a/lib/models/exchange/aggregate_currency.dart b/lib/models/exchange/aggregate_currency.dart
index 6cd1ef6cf..1bbc767a5 100644
--- a/lib/models/exchange/aggregate_currency.dart
+++ b/lib/models/exchange/aggregate_currency.dart
@@ -5,8 +5,9 @@ import 'package:tuple/tuple.dart';
class AggregateCurrency {
final Map _map = {};
- AggregateCurrency(
- {required List> exchangeCurrencyPairs}) {
+ AggregateCurrency({
+ required List> exchangeCurrencyPairs,
+ }) {
assert(exchangeCurrencyPairs.isNotEmpty);
for (final item in exchangeCurrencyPairs) {
diff --git a/lib/models/exchange/exchange_form_state.dart b/lib/models/exchange/exchange_form_state.dart
deleted file mode 100644
index 32578ebd9..000000000
--- a/lib/models/exchange/exchange_form_state.dart
+++ /dev/null
@@ -1,519 +0,0 @@
-import 'package:decimal/decimal.dart';
-import 'package:flutter/foundation.dart';
-import 'package:stackwallet/models/exchange/aggregate_currency.dart';
-import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
-import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
-import 'package:stackwallet/services/exchange/exchange.dart';
-import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart';
-import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart';
-import 'package:stackwallet/utilities/logger.dart';
-
-class ExchangeFormState extends ChangeNotifier {
- Exchange? _exchange;
- Exchange get exchange => _exchange ??= Exchange.defaultExchange;
-
- ExchangeRateType _exchangeRateType = ExchangeRateType.estimated;
- ExchangeRateType get exchangeRateType => _exchangeRateType;
- set exchangeRateType(ExchangeRateType exchangeRateType) {
- _exchangeRateType = exchangeRateType;
- //
- }
-
- Estimate? _estimate;
- Estimate? get estimate => _estimate;
-
- bool _reversed = false;
- bool get reversed => _reversed;
- set reversed(bool reversed) {
- _reversed = reversed;
- //
- }
-
- Decimal? _rate;
- Decimal? get rate => _rate;
- // set rate(Decimal? rate) {
- // _rate = rate;
- // //
- // }
-
- Decimal? _sendAmount;
- Decimal? get sendAmount => _sendAmount;
- // set sendAmount(Decimal? sendAmount) {
- // _sendAmount = sendAmount;
- // //
- // }
-
- Decimal? _receiveAmount;
- Decimal? get receiveAmount => _receiveAmount;
- set receiveAmount(Decimal? receiveAmount) {
- _receiveAmount = receiveAmount;
- //
- }
-
- AggregateCurrency? _sendCurrency;
- AggregateCurrency? get sendCurrency => _sendCurrency;
- // set sendCurrency(Currency? sendCurrency) {
- // _sendCurrency = sendCurrency;
- // //
- // }
-
- AggregateCurrency? _receiveCurrency;
- AggregateCurrency? get receiveCurrency => _receiveCurrency;
- // set receiveCurrency(Currency? receiveCurrency) {
- // _receiveCurrency = receiveCurrency;
- // //
- // }
-
- Decimal? _minSendAmount;
- Decimal? get minSendAmount => _minSendAmount;
- // set minSendAmount(Decimal? minSendAmount) {
- // _minSendAmount = minSendAmount;
- // //
- // }
-
- Decimal? _minReceiveAmount;
- Decimal? get minReceiveAmount => _minReceiveAmount;
- // set minReceiveAmount(Decimal? minReceiveAmount) {
- // _minReceiveAmount = minReceiveAmount;
- // //
- // }
-
- Decimal? _maxSendAmount;
- Decimal? get maxSendAmount => _maxSendAmount;
- // set maxSendAmount(Decimal? maxSendAmount) {
- // _maxSendAmount = maxSendAmount;
- // //
- // }
-
- Decimal? _maxReceiveAmount;
- Decimal? get maxReceiveAmount => _maxReceiveAmount;
- // set maxReceiveAmount(Decimal? maxReceiveAmount) {
- // _maxReceiveAmount = maxReceiveAmount;
- // //
- // }
-
- //============================================================================
- // computed properties
- //============================================================================
-
- String? get fromTicker => _sendCurrency?.ticker;
- String? get toTicker => _receiveCurrency?.ticker;
-
- String get fromAmountString => _sendAmount?.toStringAsFixed(8) ?? "";
- String get toAmountString => _receiveAmount?.toStringAsFixed(8) ?? "";
-
- bool get canExchange {
- return sendCurrency != null &&
- receiveCurrency != null &&
- sendAmount != null &&
- sendAmount! >= Decimal.zero &&
- receiveAmount != null &&
- rate != null &&
- rate! >= Decimal.zero &&
- sendCurrency!.forExchange(exchange.name) != null &&
- receiveCurrency!.forExchange(exchange.name) != null &&
- warning.isEmpty;
- }
-
- String get warning {
- if (reversed) {
- if (_receiveCurrency != null && _receiveAmount != null) {
- if (_minReceiveAmount != null &&
- _receiveAmount! < _minReceiveAmount! &&
- _receiveAmount! > Decimal.zero) {
- return "Min receive amount ${_minReceiveAmount!.toString()} ${_receiveCurrency!.ticker.toUpperCase()}";
- } else if (_maxReceiveAmount != null &&
- _receiveAmount! > _maxReceiveAmount!) {
- return "Max receive amount ${_maxReceiveAmount!.toString()} ${_receiveCurrency!.ticker.toUpperCase()}";
- }
- }
- } else {
- if (_sendCurrency != null && _sendAmount != null) {
- if (_minSendAmount != null &&
- _sendAmount! < _minSendAmount! &&
- _sendAmount! > Decimal.zero) {
- return "Min send amount ${_minSendAmount!.toString()} ${_sendCurrency!.ticker.toUpperCase()}";
- } else if (_maxSendAmount != null && _sendAmount! > _maxSendAmount!) {
- return "Max send amount ${_maxSendAmount!.toString()} ${_sendCurrency!.ticker.toUpperCase()}";
- }
- }
- }
-
- return "";
- }
-
- //============================================================================
- // public state updaters
- //============================================================================
-
- Future updateExchange({
- required Exchange exchange,
- required bool shouldUpdateData,
- required bool shouldNotifyListeners,
- }) async {
- _exchange = exchange;
- if (shouldUpdateData) {
- await _updateRangesAndEstimate(
- shouldNotifyListeners: false,
- );
- }
-
- if (shouldNotifyListeners) {
- _notify();
- }
- }
-
- void setCurrencies(AggregateCurrency? from, AggregateCurrency? to) {
- _sendCurrency = from;
- _receiveCurrency = to;
- }
-
- void reset({
- required bool shouldNotifyListeners,
- }) {
- _exchange = null;
- _reversed = false;
- _rate = null;
- _sendAmount = null;
- _receiveAmount = null;
- _sendCurrency = null;
- _receiveCurrency = null;
- _minSendAmount = null;
- _minReceiveAmount = null;
- _maxSendAmount = null;
- _maxReceiveAmount = null;
-
- if (shouldNotifyListeners) {
- _notify();
- }
- }
-
- Future setSendAmountAndCalculateReceiveAmount(
- Decimal? newSendAmount,
- bool shouldNotifyListeners,
- ) async {
- if (newSendAmount == null) {
- // todo: check if this breaks things and stuff
- _receiveAmount = null;
- _sendAmount = null;
- } else {
- if (newSendAmount <= Decimal.zero) {
- _receiveAmount = Decimal.zero;
- }
-
- _sendAmount = newSendAmount;
- _reversed = false;
-
- await _updateRangesAndEstimate(
- shouldNotifyListeners: false,
- );
- }
-
- if (shouldNotifyListeners) {
- _notify();
- }
- }
-
- Future setReceivingAmountAndCalculateSendAmount(
- Decimal? newReceiveAmount,
- bool shouldNotifyListeners,
- ) async {
- if (newReceiveAmount == null) {
- // todo: check if this breaks things and stuff
- _receiveAmount = null;
- _sendAmount = null;
- } else {
- if (newReceiveAmount <= Decimal.zero) {
- _sendAmount = Decimal.zero;
- }
-
- _receiveAmount = newReceiveAmount;
- _reversed = true;
-
- await _updateRangesAndEstimate(
- shouldNotifyListeners: false,
- );
- }
-
- if (shouldNotifyListeners) {
- _notify();
- }
- }
-
- Future updateSendCurrency(
- AggregateCurrency sendCurrency,
- bool shouldNotifyListeners,
- ) async {
- try {
- _sendCurrency = sendCurrency;
- _minSendAmount = null;
- _maxSendAmount = null;
-
- if (_receiveCurrency == null) {
- _rate = null;
- } else {
- await _updateRangesAndEstimate(
- shouldNotifyListeners: false,
- );
- }
- if (shouldNotifyListeners) {
- _notify();
- }
- } catch (e, s) {
- Logging.instance.log("$e\n$s", level: LogLevel.Error);
- }
- }
-
- Future updateReceivingCurrency(
- AggregateCurrency receiveCurrency,
- bool shouldNotifyListeners,
- ) async {
- try {
- _receiveCurrency = receiveCurrency;
- _minReceiveAmount = null;
- _maxReceiveAmount = null;
-
- if (_sendCurrency == null) {
- _rate = null;
- } else {
- await _updateRangesAndEstimate(
- shouldNotifyListeners: false,
- );
- }
- if (shouldNotifyListeners) {
- _notify();
- }
- } catch (e, s) {
- Logging.instance.log("$e\n$s", level: LogLevel.Error);
- }
- }
-
- Future swap({
- required bool shouldNotifyListeners,
- }) async {
- final Decimal? temp = sendAmount;
- _sendAmount = receiveAmount;
- _receiveAmount = temp;
-
- _minSendAmount = null;
- _maxSendAmount = null;
- _minReceiveAmount = null;
- _maxReceiveAmount = null;
-
- final AggregateCurrency? tmp = sendCurrency;
- _sendCurrency = receiveCurrency;
- _receiveCurrency = tmp;
-
- await _updateRangesAndEstimate(
- shouldNotifyListeners: false,
- );
-
- if (shouldNotifyListeners) {
- _notify();
- }
- }
-
- Future refresh() => _updateRangesAndEstimate(
- shouldNotifyListeners: true,
- );
-
- //============================================================================
- // private state updaters
- //============================================================================
-
- Future _updateRangesAndEstimate({
- required bool shouldNotifyListeners,
- }) async {
- try {
- switch (exchange.name) {
- case ChangeNowExchange.exchangeName:
- if (!_exchangeSupported(
- exchangeName: exchange.name,
- sendCurrency: sendCurrency,
- receiveCurrency: receiveCurrency,
- exchangeRateType: exchangeRateType,
- )) {
- _exchange = MajesticBankExchange.instance;
- }
- break;
- case MajesticBankExchange.exchangeName:
- if (!_exchangeSupported(
- exchangeName: exchange.name,
- sendCurrency: sendCurrency,
- receiveCurrency: receiveCurrency,
- exchangeRateType: exchangeRateType,
- )) {
- _exchange = ChangeNowExchange.instance;
- }
- break;
- }
-
- await _updateRanges(shouldNotifyListeners: false);
- await _updateEstimate(shouldNotifyListeners: false);
- if (shouldNotifyListeners) {
- _notify();
- }
- } catch (_) {
- //
- }
- }
-
- Future _updateRanges({
- required bool shouldNotifyListeners,
- }) async {
- // if (exchange?.name == SimpleSwapExchange.exchangeName) {
- // reversed = false;
- // }
- final _send = sendCurrency;
- final _receive = receiveCurrency;
- if (_send == null || _receive == null) {
- Logging.instance.log(
- "Tried to $runtimeType.updateRanges where ( $_send || $_receive) for: $exchange",
- level: LogLevel.Info,
- );
- return;
- }
- final response = await exchange.getRange(
- _send.ticker,
- _receive.ticker,
- exchangeRateType == ExchangeRateType.fixed,
- );
-
- if (response.value == null) {
- Logging.instance.log(
- "Tried to $runtimeType.updateRanges for: $exchange where response: $response",
- level: LogLevel.Info,
- );
- return;
- }
- final responseReversed = await exchange.getRange(
- _receive.ticker,
- _send.ticker,
- exchangeRateType == ExchangeRateType.fixed,
- );
-
- if (responseReversed.value == null) {
- Logging.instance.log(
- "Tried to $runtimeType.updateRanges for: $exchange where response: $responseReversed",
- level: LogLevel.Info,
- );
- return;
- }
-
- final range = response.value!;
- final rangeReversed = responseReversed.value!;
-
- _minSendAmount = range.min;
- _maxSendAmount = range.max;
- _minReceiveAmount = rangeReversed.min;
- _maxReceiveAmount = rangeReversed.max;
-
- //todo: check if print needed
- // debugPrint(
- // "updated range for: $exchange for $_fromTicker-$_toTicker: $range");
-
- if (shouldNotifyListeners) {
- _notify();
- }
- }
-
- Future _updateEstimate({
- required bool shouldNotifyListeners,
- }) async {
- // if (exchange?.name == SimpleSwapExchange.exchangeName) {
- // reversed = false;
- // }
- final amount = reversed ? receiveAmount : sendAmount;
- if (sendCurrency == null ||
- receiveCurrency == null ||
- amount == null ||
- amount <= Decimal.zero) {
- Logging.instance.log(
- "Tried to $runtimeType.updateEstimate for: $exchange where (from: $sendCurrency || to: $receiveCurrency || amount: $amount)",
- level: LogLevel.Info,
- );
- return;
- }
- final response = await exchange.getEstimate(
- sendCurrency!.ticker,
- receiveCurrency!.ticker,
- amount,
- exchangeRateType == ExchangeRateType.fixed,
- reversed,
- );
-
- if (response.value == null) {
- Logging.instance.log(
- "Tried to $runtimeType.updateEstimate for: $exchange where response: $response",
- level: LogLevel.Info,
- );
- return;
- }
-
- _estimate = response.value!;
-
- if (reversed) {
- _sendAmount = _estimate!.estimatedAmount;
- } else {
- _receiveAmount = _estimate!.estimatedAmount;
- }
-
- _rate =
- (receiveAmount! / sendAmount!).toDecimal(scaleOnInfinitePrecision: 12);
-
- //todo: check if print needed
- // debugPrint(
- // "updated estimate for: $exchange for $fromTicker-$toTicker: $estimate");
-
- if (shouldNotifyListeners) {
- _notify();
- }
- }
-
- //============================================================================
-
- void _notify() {
- debugPrint("ExFState NOTIFY: ${toString()}");
- notifyListeners();
- }
-
- bool _exchangeSupported({
- required String exchangeName,
- required AggregateCurrency? sendCurrency,
- required AggregateCurrency? receiveCurrency,
- required ExchangeRateType exchangeRateType,
- }) {
- final send = sendCurrency?.forExchange(exchangeName);
- if (send == null) return false;
-
- final rcv = receiveCurrency?.forExchange(exchangeName);
- if (rcv == null) return false;
-
- if (exchangeRateType == ExchangeRateType.fixed) {
- return send.supportsFixedRate && rcv.supportsFixedRate;
- } else {
- return send.supportsEstimatedRate && rcv.supportsEstimatedRate;
- }
- }
-
- @override
- String toString() {
- return "{"
- "\n\t exchange: $exchange,"
- "\n\t exchangeRateType: $exchangeRateType,"
- "\n\t sendCurrency: $sendCurrency,"
- "\n\t receiveCurrency: $receiveCurrency,"
- "\n\t rate: $rate,"
- "\n\t reversed: $reversed,"
- "\n\t sendAmount: $sendAmount,"
- "\n\t receiveAmount: $receiveAmount,"
- "\n\t estimate: $estimate,"
- "\n\t minSendAmount: $minSendAmount,"
- "\n\t maxSendAmount: $maxSendAmount,"
- "\n\t minReceiveAmount: $minReceiveAmount,"
- "\n\t maxReceiveAmount: $maxReceiveAmount,"
- "\n\t canExchange: $canExchange,"
- "\n\t warning: $warning,"
- "\n}";
- }
-}
diff --git a/lib/models/exchange/incomplete_exchange.dart b/lib/models/exchange/incomplete_exchange.dart
index 864a25490..2680b24e0 100644
--- a/lib/models/exchange/incomplete_exchange.dart
+++ b/lib/models/exchange/incomplete_exchange.dart
@@ -1,5 +1,6 @@
import 'package:decimal/decimal.dart';
import 'package:flutter/foundation.dart';
+import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart';
@@ -39,13 +40,13 @@ class IncompleteExchangeModel extends ChangeNotifier {
}
}
- String? _rateId;
+ Estimate? _estimate;
- String? get rateId => _rateId;
+ Estimate? get estimate => _estimate;
- set rateId(String? rateId) {
- if (_rateId != rateId) {
- _rateId = rateId;
+ set estimate(Estimate? estimate) {
+ if (_estimate != estimate) {
+ _estimate = estimate;
notifyListeners();
}
}
@@ -70,6 +71,6 @@ class IncompleteExchangeModel extends ChangeNotifier {
required this.rateType,
required this.reversed,
required this.walletInitiated,
- String? rateId,
- }) : _rateId = rateId;
+ Estimate? estimate,
+ }) : _estimate = estimate;
}
diff --git a/lib/models/exchange/response_objects/estimate.dart b/lib/models/exchange/response_objects/estimate.dart
index 7df490079..9284c8340 100644
--- a/lib/models/exchange/response_objects/estimate.dart
+++ b/lib/models/exchange/response_objects/estimate.dart
@@ -7,6 +7,8 @@ class Estimate {
final bool reversed;
final String? warningMessage;
final String? rateId;
+ final String exchangeProvider;
+ final String? kycRating;
Estimate({
required this.estimatedAmount,
@@ -14,9 +16,15 @@ class Estimate {
required this.reversed,
this.warningMessage,
this.rateId,
+ required this.exchangeProvider,
+ this.kycRating,
});
- factory Estimate.fromMap(Map map) {
+ factory Estimate.fromMap(
+ Map map, {
+ required String exchangeProvider,
+ String? kycRating,
+ }) {
try {
return Estimate(
estimatedAmount: Decimal.parse(map["estimatedAmount"] as String),
@@ -24,6 +32,8 @@ class Estimate {
reversed: map["reversed"] as bool,
warningMessage: map["warningMessage"] as String?,
rateId: map["rateId"] as String?,
+ exchangeProvider: exchangeProvider,
+ kycRating: kycRating,
);
} catch (e, s) {
Logging.instance.log("Estimate.fromMap(): $e\n$s", level: LogLevel.Error);
@@ -38,6 +48,8 @@ class Estimate {
"reversed": reversed,
"warningMessage": warningMessage,
"rateId": rateId,
+ "exchangeProvider": exchangeProvider,
+ "kycRating": kycRating,
};
}
diff --git a/lib/pages/exchange_view/exchange_form.dart b/lib/pages/exchange_view/exchange_form.dart
index 389bedd05..c4d11d162 100644
--- a/lib/pages/exchange_view/exchange_form.dart
+++ b/lib/pages/exchange_view/exchange_form.dart
@@ -9,6 +9,8 @@ import 'package:intl/intl.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/exchange/response_objects/estimate.dart';
+import 'package:stackwallet/models/exchange/response_objects/range.dart';
import 'package:stackwallet/models/isar/exchange_cache/currency.dart';
import 'package:stackwallet/models/isar/exchange_cache/pair.dart';
import 'package:stackwallet/models/isar/models/ethereum/eth_contract.dart';
@@ -21,6 +23,8 @@ import 'package:stackwallet/pages_desktop_specific/desktop_exchange/exchange_ste
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
import 'package:stackwallet/services/exchange/exchange_data_loading_service.dart';
+import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart';
+import 'package:stackwallet/services/exchange/trocador/trocador_exchange.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
@@ -39,6 +43,9 @@ import 'package:stackwallet/widgets/rounded_white_container.dart';
import 'package:stackwallet/widgets/stack_dialog.dart';
import 'package:stackwallet/widgets/textfields/exchange_textfield.dart';
import 'package:tuple/tuple.dart';
+import 'package:uuid/uuid.dart';
+
+import '../../services/exchange/exchange_response.dart';
class ExchangeForm extends ConsumerStatefulWidget {
const ExchangeForm({
@@ -61,6 +68,12 @@ class _ExchangeFormState extends ConsumerState {
late final Coin? coin;
late final bool walletInitiated;
+ final exchanges = [
+ MajesticBankExchange.instance,
+ ChangeNowExchange.instance,
+ TrocadorExchange.instance,
+ ];
+
late final TextEditingController _sendController;
late final TextEditingController _receiveController;
final isDesktop = Util.isDesktop;
@@ -70,7 +83,7 @@ class _ExchangeFormState extends ConsumerState {
bool _swapLock = false;
// todo: check and adjust this value?
- static const _valueCheckInterval = Duration(milliseconds: 300);
+ static const _valueCheckInterval = Duration(milliseconds: 1500);
Future showUpdatingExchangeRate({
required Future whileFuture,
@@ -105,16 +118,17 @@ class _ExchangeFormState extends ConsumerState {
}
Timer? _sendFieldOnChangedTimer;
- void sendFieldOnChanged(String value) async {
+ void sendFieldOnChanged(String value) {
if (_sendFocusNode.hasFocus) {
_sendFieldOnChangedTimer?.cancel();
_sendFieldOnChangedTimer = Timer(_valueCheckInterval, () async {
final newFromAmount = _localizedStringToNum(value);
- await ref
- .read(exchangeFormStateProvider)
- .setSendAmountAndCalculateReceiveAmount(newFromAmount, true);
+ ref.read(efSendAmountProvider.notifier).state = newFromAmount;
+ if (!_swapLock && !ref.read(efReversedProvider)) {
+ unawaited(update());
+ }
});
}
}
@@ -126,9 +140,10 @@ class _ExchangeFormState extends ConsumerState {
_receiveFieldOnChangedTimer = Timer(_valueCheckInterval, () async {
final newToAmount = _localizedStringToNum(value);
- await ref
- .read(exchangeFormStateProvider)
- .setReceivingAmountAndCalculateSendAmount(newToAmount, true);
+ ref.read(efReceiveAmountProvider.notifier).state = newToAmount;
+ if (!_swapLock && ref.read(efReversedProvider)) {
+ unawaited(update());
+ }
});
}
@@ -147,7 +162,7 @@ class _ExchangeFormState extends ConsumerState {
}
Future _getAggregateCurrency(Currency currency) async {
- final rateType = ref.read(exchangeFormStateProvider).exchangeRateType;
+ final rateType = ref.read(efRateTypeProvider);
final currencies = await ExchangeDataLoadingService.instance.isar.currencies
.filter()
.group((q) => rateType == ExchangeRateType.fixed
@@ -178,8 +193,8 @@ class _ExchangeFormState extends ConsumerState {
}
void selectSendCurrency() async {
- final type = (ref.read(exchangeFormStateProvider).exchangeRateType);
- final fromTicker = ref.read(exchangeFormStateProvider).fromTicker ?? "";
+ final type = ref.read(efRateTypeProvider);
+ final fromTicker = ref.read(efCurrencyPairProvider).send?.ticker ?? "";
if (walletInitiated) {
if (widget.contract != null &&
@@ -194,24 +209,26 @@ class _ExchangeFormState extends ConsumerState {
}
final selectedCurrency = await _showCurrencySelectionSheet(
- willChange: ref.read(exchangeFormStateProvider).sendCurrency?.ticker,
+ willChange: ref.read(efCurrencyPairProvider).send?.ticker,
willChangeIsSend: true,
- paired: ref.read(exchangeFormStateProvider).receiveCurrency?.ticker,
+ paired: ref.read(efCurrencyPairProvider).receive?.ticker,
isFixedRate: type == ExchangeRateType.fixed,
);
if (selectedCurrency != null) {
await showUpdatingExchangeRate(
whileFuture: _getAggregateCurrency(selectedCurrency).then(
- (aggregateSelected) => ref
- .read(exchangeFormStateProvider)
- .updateSendCurrency(aggregateSelected, true)),
+ (aggregateSelected) => ref.read(efCurrencyPairProvider).setSend(
+ aggregateSelected,
+ notifyListeners: true,
+ ),
+ ),
);
}
}
void selectReceiveCurrency() async {
- final toTicker = ref.read(exchangeFormStateProvider).toTicker ?? "";
+ final toTicker = ref.read(efCurrencyPairProvider).receive?.ticker ?? "";
if (walletInitiated &&
toTicker.toLowerCase() == coin!.ticker.toLowerCase()) {
// do not allow changing away from wallet coin
@@ -219,19 +236,20 @@ class _ExchangeFormState extends ConsumerState {
}
final selectedCurrency = await _showCurrencySelectionSheet(
- willChange: ref.read(exchangeFormStateProvider).receiveCurrency?.ticker,
+ willChange: ref.read(efCurrencyPairProvider).receive?.ticker,
willChangeIsSend: false,
- paired: ref.read(exchangeFormStateProvider).sendCurrency?.ticker,
- isFixedRate: ref.read(exchangeFormStateProvider).exchangeRateType ==
- ExchangeRateType.fixed,
+ paired: ref.read(efCurrencyPairProvider).send?.ticker,
+ isFixedRate: ref.read(efRateTypeProvider) == ExchangeRateType.fixed,
);
if (selectedCurrency != null) {
await showUpdatingExchangeRate(
whileFuture: _getAggregateCurrency(selectedCurrency).then(
- (aggregateSelected) => ref
- .read(exchangeFormStateProvider)
- .updateReceivingCurrency(aggregateSelected, true)),
+ (aggregateSelected) => ref.read(efCurrencyPairProvider).setReceive(
+ aggregateSelected,
+ notifyListeners: true,
+ ),
+ ),
);
}
}
@@ -241,10 +259,25 @@ class _ExchangeFormState extends ConsumerState {
_sendFocusNode.unfocus();
_receiveFocusNode.unfocus();
- await showUpdatingExchangeRate(
- whileFuture:
- ref.read(exchangeFormStateProvider).swap(shouldNotifyListeners: true),
- );
+ final temp = ref.read(efCurrencyPairProvider).send;
+ ref.read(efCurrencyPairProvider).setSend(
+ ref.read(efCurrencyPairProvider).receive,
+ notifyListeners: true,
+ );
+ ref.read(efCurrencyPairProvider).setReceive(
+ temp,
+ notifyListeners: true,
+ );
+
+ // final reversed = ref.read(efReversedProvider);
+
+ final amount = ref.read(efSendAmountProvider);
+ ref.read(efSendAmountProvider.notifier).state =
+ ref.read(efReceiveAmountProvider);
+
+ ref.read(efReceiveAmountProvider.notifier).state = amount;
+
+ unawaited(update());
_swapLock = false;
}
@@ -331,85 +364,20 @@ class _ExchangeFormState extends ConsumerState {
}
}
- void onRateTypeChanged(ExchangeRateType newType) async {
+ void onRateTypeChanged(ExchangeRateType newType) {
_receiveFocusNode.unfocus();
_sendFocusNode.unfocus();
- await showUpdatingExchangeRate(
- whileFuture: _onRateTypeChangedFuture(newType),
- );
- }
-
- Future _onRateTypeChangedFuture(ExchangeRateType newType) async {
- ref.read(exchangeFormStateProvider).exchangeRateType = newType;
-
- final fromTicker = ref.read(exchangeFormStateProvider).fromTicker ?? "-";
- final toTicker = ref.read(exchangeFormStateProvider).toTicker ?? "-";
-
- 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();
- 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;
- // }
- // }
- }
+ ref.read(efRateTypeProvider.notifier).state = newType;
+ update();
}
void onExchangePressed() async {
- final rateType = ref.read(exchangeFormStateProvider).exchangeRateType;
- final fromTicker = ref.read(exchangeFormStateProvider).fromTicker ?? "";
- final toTicker = ref.read(exchangeFormStateProvider).toTicker ?? "";
- final sendAmount = ref.read(exchangeFormStateProvider).sendAmount!;
- final estimate = ref.read(exchangeFormStateProvider).estimate!;
+ final rateType = ref.read(efRateTypeProvider);
+ final fromTicker = ref.read(efCurrencyPairProvider).send?.ticker ?? "";
+ final toTicker = ref.read(efCurrencyPairProvider).receive?.ticker ?? "";
+ final estimate = ref.read(efEstimateProvider)!;
+ final sendAmount = ref.read(efSendAmountProvider)!;
if (rateType == ExchangeRateType.fixed && toTicker.toUpperCase() == "WOW") {
await showDialog(
@@ -426,10 +394,16 @@ class _ExchangeFormState extends ConsumerState {
String rate;
+ final amountToSend =
+ estimate.reversed ? estimate.estimatedAmount : sendAmount;
+ final amountToReceive = estimate.reversed
+ ? ref.read(efReceiveAmountProvider)!
+ : estimate.estimatedAmount;
+
switch (rateType) {
case ExchangeRateType.estimated:
rate =
- "1 ${fromTicker.toUpperCase()} ~${(estimate.estimatedAmount / sendAmount).toDecimal(scaleOnInfinitePrecision: 8).toStringAsFixed(8)} ${toTicker.toUpperCase()}";
+ "1 ${fromTicker.toUpperCase()} ~${(amountToReceive / sendAmount).toDecimal(scaleOnInfinitePrecision: 8).toStringAsFixed(8)} ${toTicker.toUpperCase()}";
break;
case ExchangeRateType.fixed:
bool? shouldCancel;
@@ -541,7 +515,9 @@ class _ExchangeFormState extends ConsumerState {
return;
}
rate =
- "1 ${fromTicker.toUpperCase()} ~${ref.read(exchangeFormStateProvider).rate!.toStringAsFixed(8)} ${toTicker.toUpperCase()}";
+ "1 ${fromTicker.toUpperCase()} ~${(amountToReceive / amountToSend).toDecimal(
+ scaleOnInfinitePrecision: 12,
+ ).toStringAsFixed(8)} ${toTicker.toUpperCase()}";
break;
}
@@ -549,12 +525,10 @@ class _ExchangeFormState extends ConsumerState {
sendTicker: fromTicker.toUpperCase(),
receiveTicker: toTicker.toUpperCase(),
rateInfo: rate,
- sendAmount: estimate.reversed ? estimate.estimatedAmount : sendAmount,
- receiveAmount: estimate.reversed
- ? ref.read(exchangeFormStateProvider).receiveAmount!
- : estimate.estimatedAmount,
+ sendAmount: amountToSend,
+ receiveAmount: amountToReceive,
rateType: rateType,
- rateId: estimate.rateId,
+ estimate: estimate,
reversed: estimate.reversed,
walletInitiated: walletInitiated,
);
@@ -622,8 +596,8 @@ class _ExchangeFormState extends ConsumerState {
}
String? ticker = isSend
- ? ref.read(exchangeFormStateProvider).fromTicker
- : ref.read(exchangeFormStateProvider).toTicker;
+ ? ref.read(efCurrencyPairProvider).send?.ticker
+ : ref.read(efCurrencyPairProvider).receive?.ticker;
if (ticker == null) {
return false;
@@ -632,6 +606,97 @@ class _ExchangeFormState extends ConsumerState {
return coin.ticker.toUpperCase() == ticker.toUpperCase();
}
+ Future update() async {
+ final uuid = const Uuid().v1();
+ _latestUuid = uuid;
+ _addUpdate(uuid);
+ for (final exchange in exchanges) {
+ ref.read(efEstimatesListProvider(exchange.name).notifier).state = null;
+ }
+
+ final reversed = ref.read(efReversedProvider);
+ final amount = reversed
+ ? ref.read(efReceiveAmountProvider)
+ : ref.read(efSendAmountProvider);
+
+ final pair = ref.read(efCurrencyPairProvider);
+ if (amount == null ||
+ amount <= Decimal.zero ||
+ pair.send == null ||
+ pair.receive == null) {
+ _removeUpdate(uuid);
+ return;
+ }
+ final rateType = ref.read(efRateTypeProvider);
+ final Map>, Range?>>
+ results = {};
+
+ for (final exchange in exchanges) {
+ final sendCurrency = pair.send?.forExchange(exchange.name);
+ final receiveCurrency = pair.receive?.forExchange(exchange.name);
+
+ if (sendCurrency != null && receiveCurrency != null) {
+ final rangeResponse = await exchange.getRange(
+ reversed ? receiveCurrency.ticker : sendCurrency.ticker,
+ reversed ? sendCurrency.ticker : receiveCurrency.ticker,
+ rateType == ExchangeRateType.fixed,
+ );
+
+ final estimateResponse = await exchange.getEstimates(
+ sendCurrency.ticker,
+ receiveCurrency.ticker,
+ amount,
+ rateType == ExchangeRateType.fixed,
+ reversed,
+ );
+
+ results.addAll(
+ {
+ exchange.name: Tuple2(
+ estimateResponse,
+ rangeResponse.value,
+ ),
+ },
+ );
+ }
+ }
+
+ for (final exchange in exchanges) {
+ if (uuid == _latestUuid) {
+ ref.read(efEstimatesListProvider(exchange.name).notifier).state =
+ results[exchange.name];
+ }
+ }
+
+ _removeUpdate(uuid);
+ }
+
+ String? _latestUuid;
+ final Set _uuids = {};
+
+ void _addUpdate(String uuid) {
+ _uuids.add(uuid);
+ ref.read(efRefreshingProvider.notifier).state = true;
+ }
+
+ void _removeUpdate(String uuid) {
+ _uuids.remove(uuid);
+ if (_uuids.isEmpty) {
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ ref.read(efRefreshingProvider.notifier).state = false;
+ });
+ }
+ }
+
+ void updateSend(Estimate? estimate) {
+ ref.read(efSendAmountProvider.notifier).state = estimate?.estimatedAmount;
+ }
+
+ void updateReceive(Estimate? estimate) {
+ ref.read(efReceiveAmountProvider.notifier).state =
+ estimate?.estimatedAmount;
+ }
+
@override
void initState() {
_sendController = TextEditingController();
@@ -641,9 +706,40 @@ class _ExchangeFormState extends ConsumerState {
coin = widget.coin;
walletInitiated = walletId != null && coin != null;
+ _sendFocusNode.addListener(() {
+ if (_sendFocusNode.hasFocus) {
+ final reversed = ref.read(efReversedProvider);
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ ref.read(efReversedProvider.notifier).state = false;
+ if (reversed == true) {
+ update();
+ }
+ });
+ }
+ });
+ _receiveFocusNode.addListener(() {
+ if (_receiveFocusNode.hasFocus &&
+ ref.read(efExchangeProvider).name != ChangeNowExchange.exchangeName) {
+ final reversed = ref.read(efReversedProvider);
+ WidgetsBinding.instance.addPostFrameCallback((_) {
+ ref.read(efReversedProvider.notifier).state = true;
+ if (reversed != true) {
+ update();
+ }
+ });
+ }
+ });
+
if (walletInitiated) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
- ref.read(exchangeFormStateProvider).reset(shouldNotifyListeners: true);
+ ref.read(efSendAmountProvider.notifier).state = null;
+ ref.read(efReceiveAmountProvider.notifier).state = null;
+ ref.read(efReversedProvider.notifier).state = false;
+ ref.read(efRefreshingProvider.notifier).state = false;
+ ref.read(efCurrencyPairProvider).setSend(null, notifyListeners: true);
+ ref
+ .read(efCurrencyPairProvider)
+ .setReceive(null, notifyListeners: true);
ExchangeDataLoadingService.instance
.getAggregateCurrency(
widget.contract == null ? coin!.ticker : widget.contract!.symbol,
@@ -652,17 +748,17 @@ class _ExchangeFormState extends ConsumerState {
)
.then((value) {
if (value != null) {
- ref.read(exchangeFormStateProvider).updateSendCurrency(value, true);
+ ref.read(efCurrencyPairProvider).setSend(
+ value,
+ notifyListeners: true,
+ );
}
});
});
} else {
- _sendController.text =
- ref.read(exchangeFormStateProvider).fromAmountString;
- _receiveController.text =
- ref.read(exchangeFormStateProvider).toAmountString;
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
- ref.read(exchangeFormStateProvider).refresh();
+ _sendController.text = ref.read(efSendAmountStringProvider);
+ _receiveController.text = ref.read(efReceiveAmountStringProvider);
});
}
@@ -673,6 +769,8 @@ class _ExchangeFormState extends ConsumerState {
void dispose() {
_receiveController.dispose();
_sendController.dispose();
+ _receiveFocusNode.dispose();
+ _sendFocusNode.dispose();
super.dispose();
}
@@ -680,34 +778,42 @@ class _ExchangeFormState extends ConsumerState {
Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType");
- final rateType = ref.watch(
- exchangeFormStateProvider.select((value) => value.exchangeRateType));
+ final rateType = ref.watch(efRateTypeProvider);
final isEstimated = rateType == ExchangeRateType.estimated;
- ref.listen(
- exchangeFormStateProvider.select((value) => value.toAmountString),
- (previous, String next) {
+ ref.listen(efReceiveAmountStringProvider, (previous, String next) {
if (!_receiveFocusNode.hasFocus) {
_receiveController.text = isEstimated && next.isEmpty ? "-" : next;
- if (_swapLock) {
- _sendController.text =
- ref.read(exchangeFormStateProvider).fromAmountString;
- }
+ // if (_swapLock) {
+ _sendController.text = ref.read(efSendAmountStringProvider);
+ // }
}
});
- ref.listen(
- exchangeFormStateProvider.select((value) => value.fromAmountString),
- (previous, String next) {
+ ref.listen(efSendAmountStringProvider, (previous, String next) {
if (!_sendFocusNode.hasFocus) {
_sendController.text = next;
- if (_swapLock) {
- _receiveController.text = isEstimated
- ? ref.read(exchangeFormStateProvider).toAmountString.isEmpty
- ? "-"
- : ref.read(exchangeFormStateProvider).toAmountString
- : ref.read(exchangeFormStateProvider).toAmountString;
- }
+ // if (_swapLock) {
+ _receiveController.text =
+ isEstimated && ref.read(efReceiveAmountStringProvider).isEmpty
+ ? "-"
+ : ref.read(efReceiveAmountStringProvider);
+ // }
+ }
+ });
+
+ ref.listen(efEstimateProvider.notifier, (previous, next) {
+ final estimate = (next as StateController).state;
+ if (ref.read(efReversedProvider)) {
+ updateSend(estimate);
+ } else {
+ updateReceive(estimate);
+ }
+ });
+
+ ref.listen(efCurrencyPairProvider, (previous, next) {
+ if (!_swapLock) {
+ update();
}
});
@@ -725,8 +831,9 @@ class _ExchangeFormState extends ConsumerState {
height: isDesktop ? 10 : 4,
),
ExchangeTextField(
- key: Key(
- "exchangeTextFieldKeyFor_${Theme.of(context).extension()!.themeType.name}"),
+ key: Key("exchangeTextFieldKeyFor_"
+ "${Theme.of(context).extension()!.themeType.name}"
+ "${ref.watch(efCurrencyPairProvider.select((value) => value.send?.ticker))}"),
controller: _sendController,
focusNode: _sendFocusNode,
textStyle: STextStyles.smallMed14(context).copyWith(
@@ -745,8 +852,8 @@ class _ExchangeFormState extends ConsumerState {
onChanged: sendFieldOnChanged,
onButtonTap: selectSendCurrency,
isWalletCoin: isWalletCoin(coin, true),
- currency: ref.watch(
- exchangeFormStateProvider.select((value) => value.sendCurrency)),
+ currency:
+ ref.watch(efCurrencyPairProvider.select((value) => value.send)),
),
SizedBox(
height: isDesktop ? 10 : 4,
@@ -754,17 +861,6 @@ class _ExchangeFormState extends ConsumerState {
SizedBox(
height: isDesktop ? 10 : 4,
),
- if (ref
- .watch(
- exchangeFormStateProvider.select((value) => value.warning))
- .isNotEmpty &&
- !ref.watch(
- exchangeFormStateProvider.select((value) => value.reversed)))
- Text(
- ref.watch(
- exchangeFormStateProvider.select((value) => value.warning)),
- style: STextStyles.errorSmall(context),
- ),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -809,7 +905,7 @@ class _ExchangeFormState extends ConsumerState {
),
),
),
- )
+ ),
),
],
),
@@ -829,34 +925,24 @@ class _ExchangeFormState extends ConsumerState {
borderRadius: Constants.size.circularBorderRadius,
background:
Theme.of(context).extension()!.textFieldDefaultBG,
- onTap: () {
- if (!(ref.read(exchangeFormStateProvider).exchangeRateType ==
- ExchangeRateType.estimated) &&
- _receiveController.text == "-") {
- _receiveController.text = "";
- }
- },
+ onTap: rateType == ExchangeRateType.estimated &&
+ ref.watch(efExchangeProvider).name ==
+ ChangeNowExchange.exchangeName
+ ? null
+ : () {
+ if (_sendController.text == "-") {
+ _sendController.text = "";
+ }
+ },
onChanged: receiveFieldOnChanged,
onButtonTap: selectReceiveCurrency,
isWalletCoin: isWalletCoin(coin, true),
- currency: ref.watch(exchangeFormStateProvider
- .select((value) => value.receiveCurrency)),
- readOnly: (rateType) == ExchangeRateType.estimated &&
- ref.watch(exchangeFormStateProvider
- .select((value) => value.exchange.name)) ==
+ currency: ref
+ .watch(efCurrencyPairProvider.select((value) => value.receive)),
+ readOnly: rateType == ExchangeRateType.estimated &&
+ ref.watch(efExchangeProvider).name ==
ChangeNowExchange.exchangeName,
),
- if (ref
- .watch(
- exchangeFormStateProvider.select((value) => value.warning))
- .isNotEmpty &&
- ref.watch(
- exchangeFormStateProvider.select((value) => value.reversed)))
- Text(
- ref.watch(
- exchangeFormStateProvider.select((value) => value.warning)),
- style: STextStyles.errorSmall(context),
- ),
SizedBox(
height: isDesktop ? 20 : 12,
),
@@ -867,27 +953,19 @@ class _ExchangeFormState extends ConsumerState {
onChanged: onRateTypeChanged,
),
),
- // these reads should be watch
- if (ref.watch(exchangeFormStateProvider).sendAmount != null &&
- ref.watch(exchangeFormStateProvider).sendAmount != Decimal.zero)
- SizedBox(
- height: isDesktop ? 20 : 12,
- ),
- // these reads should be watch
- if (ref.watch(exchangeFormStateProvider).sendAmount != null &&
- ref.watch(exchangeFormStateProvider).sendAmount != Decimal.zero)
- ExchangeProviderOptions(
+ Padding(
+ padding: EdgeInsets.only(top: isDesktop ? 20 : 12),
+ child: ExchangeProviderOptions(
fixedRate: rateType == ExchangeRateType.fixed,
- reversed: ref.watch(
- exchangeFormStateProvider.select((value) => value.reversed)),
+ reversed: ref.watch(efReversedProvider),
),
+ ),
SizedBox(
height: isDesktop ? 20 : 12,
),
PrimaryButton(
buttonHeight: isDesktop ? ButtonHeight.l : null,
- enabled: ref.watch(
- exchangeFormStateProvider.select((value) => value.canExchange)),
+ enabled: ref.watch(efCanExchangeProvider),
onPressed: onExchangePressed,
label: "Swap",
)
diff --git a/lib/pages/exchange_view/exchange_step_views/step_2_view.dart b/lib/pages/exchange_view/exchange_step_views/step_2_view.dart
index a32df6e74..315228e13 100644
--- a/lib/pages/exchange_view/exchange_step_views/step_2_view.dart
+++ b/lib/pages/exchange_view/exchange_step_views/step_2_view.dart
@@ -124,9 +124,8 @@ class _Step2ViewState extends ConsumerState {
@override
Widget build(BuildContext context) {
- final supportsRefund = ref.watch(
- exchangeFormStateProvider.select((value) => value.exchange.name)) !=
- MajesticBankExchange.exchangeName;
+ final supportsRefund =
+ ref.watch(efExchangeProvider).name != MajesticBankExchange.exchangeName;
return Background(
child: Scaffold(
diff --git a/lib/pages/exchange_view/exchange_step_views/step_3_view.dart b/lib/pages/exchange_view/exchange_step_views/step_3_view.dart
index 22c356b5d..1079621e6 100644
--- a/lib/pages/exchange_view/exchange_step_views/step_3_view.dart
+++ b/lib/pages/exchange_view/exchange_step_views/step_3_view.dart
@@ -52,9 +52,8 @@ class _Step3ViewState extends ConsumerState {
@override
Widget build(BuildContext context) {
- final supportsRefund = ref.watch(
- exchangeFormStateProvider.select((value) => value.exchange.name)) !=
- MajesticBankExchange.exchangeName;
+ final supportsRefund =
+ ref.watch(efExchangeProvider).name != MajesticBankExchange.exchangeName;
return Background(
child: Scaffold(
@@ -254,8 +253,7 @@ class _Step3ViewState extends ConsumerState {
final ExchangeResponse response =
await ref
- .read(exchangeFormStateProvider)
- .exchange
+ .read(efExchangeProvider)
.createTrade(
from: model.sendTicker,
to: model.receiveTicker,
@@ -271,24 +269,26 @@ class _Step3ViewState extends ConsumerState {
? model.refundAddress!
: "",
refundExtraId: "",
- rateId: model.rateId,
+ estimate: model.estimate,
reversed: model.reversed,
);
if (response.value == null) {
if (mounted) {
Navigator.of(context).pop();
- }
- unawaited(showDialog(
- context: context,
- barrierDismissible: true,
- builder: (_) => StackDialog(
- title: "Failed to create trade",
- message:
- response.exception?.toString(),
- ),
- ));
+ unawaited(
+ showDialog(
+ context: context,
+ barrierDismissible: true,
+ builder: (_) => StackDialog(
+ title: "Failed to create trade",
+ message: response.exception
+ ?.toString(),
+ ),
+ ),
+ );
+ }
return;
}
diff --git a/lib/pages/exchange_view/exchange_step_views/step_4_view.dart b/lib/pages/exchange_view/exchange_step_views/step_4_view.dart
index b7bdf9e46..094e343d8 100644
--- a/lib/pages/exchange_view/exchange_step_views/step_4_view.dart
+++ b/lib/pages/exchange_view/exchange_step_views/step_4_view.dart
@@ -70,10 +70,8 @@ class _Step4ViewState extends ConsumerState {
}
Future _updateStatus() async {
- final statusResponse = await ref
- .read(exchangeFormStateProvider)
- .exchange
- .updateTrade(model.trade!);
+ final statusResponse =
+ await ref.read(efExchangeProvider).updateTrade(model.trade!);
String status = "Waiting";
if (statusResponse.value != null) {
status = statusResponse.value!.status;
diff --git a/lib/pages/exchange_view/exchange_view.dart b/lib/pages/exchange_view/exchange_view.dart
index 61cf2fe94..a17764b91 100644
--- a/lib/pages/exchange_view/exchange_view.dart
+++ b/lib/pages/exchange_view/exchange_view.dart
@@ -37,7 +37,8 @@ class _ExchangeViewState extends ConsumerState {
ExchangeDataLoadingService.instance.onLoadingComplete = () {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty(
- ref.read(exchangeFormStateProvider),
+ ref.read(efCurrencyPairProvider),
+ ref.read(efRateTypeProvider),
);
setState(() {
_initialCachePopulationUnderway = false;
@@ -53,7 +54,8 @@ class _ExchangeViewState extends ConsumerState {
ExchangeDataLoadingService.instance.onLoadingComplete = () {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty(
- ref.read(exchangeFormStateProvider),
+ ref.read(efCurrencyPairProvider),
+ ref.read(efRateTypeProvider),
);
setState(() {
_initialCachePopulationUnderway = false;
diff --git a/lib/pages/exchange_view/sub_widgets/exchange_provider_option.dart b/lib/pages/exchange_view/sub_widgets/exchange_provider_option.dart
new file mode 100644
index 000000000..1212caf49
--- /dev/null
+++ b/lib/pages/exchange_view/sub_widgets/exchange_provider_option.dart
@@ -0,0 +1,349 @@
+import 'package:decimal/decimal.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
+import 'package:stackwallet/providers/exchange/exchange_form_state_provider.dart';
+import 'package:stackwallet/providers/global/locale_provider.dart';
+import 'package:stackwallet/services/exchange/exchange.dart';
+import 'package:stackwallet/utilities/amount/amount.dart';
+import 'package:stackwallet/utilities/assets.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
+import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart';
+import 'package:stackwallet/utilities/logger.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/theme/stack_colors.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/widgets/animated_text.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/exchange/trocador/trocador_kyc_info_button.dart';
+import 'package:stackwallet/widgets/exchange/trocador/trocador_rating_type_enum.dart';
+
+class ExchangeOption extends ConsumerStatefulWidget {
+ const ExchangeOption({
+ Key? key,
+ required this.exchange,
+ required this.fixedRate,
+ required this.reversed,
+ }) : super(key: key);
+
+ final Exchange exchange;
+ final bool fixedRate;
+ final bool reversed;
+
+ @override
+ ConsumerState createState() => _ExchangeOptionState();
+}
+
+class _ExchangeOptionState extends ConsumerState {
+ final isDesktop = Util.isDesktop;
+
+ @override
+ Widget build(BuildContext context) {
+ final sendCurrency =
+ ref.watch(efCurrencyPairProvider.select((value) => value.send));
+ final receivingCurrency =
+ ref.watch(efCurrencyPairProvider.select((value) => value.receive));
+ final reversed = ref.watch(efReversedProvider);
+ final amount = reversed
+ ? ref.watch(efReceiveAmountProvider)
+ : ref.watch(efSendAmountProvider);
+
+ final data = ref.watch(efEstimatesListProvider(widget.exchange.name));
+ final estimates = data?.item1.value;
+
+ return AnimatedSize(
+ duration: const Duration(milliseconds: 500),
+ curve: Curves.easeInOutCubicEmphasized,
+ child: Builder(
+ builder: (_) {
+ if (ref.watch(efRefreshingProvider)) {
+ // show loading
+ return _ProviderOption(
+ exchange: widget.exchange,
+ estimate: null,
+ rateString: "",
+ loadingString: true,
+ );
+ } else if (sendCurrency != null &&
+ receivingCurrency != null &&
+ amount != null &&
+ amount > Decimal.zero) {
+ if (estimates != null && estimates.isNotEmpty) {
+ return Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ for (int i = 0; i < estimates.length; i++)
+ Builder(
+ builder: (context) {
+ final e = estimates[i];
+
+ int decimals;
+ try {
+ decimals = coinFromTickerCaseInsensitive(
+ receivingCurrency.ticker)
+ .decimals;
+ } catch (_) {
+ decimals = 8; // some reasonable alternative
+ }
+ Amount rate;
+ if (e.reversed) {
+ rate = (amount / e.estimatedAmount)
+ .toDecimal(scaleOnInfinitePrecision: 18)
+ .toAmount(fractionDigits: decimals);
+ } else {
+ rate = (e.estimatedAmount / amount)
+ .toDecimal(scaleOnInfinitePrecision: 18)
+ .toAmount(fractionDigits: decimals);
+ }
+
+ final rateString =
+ "1 ${sendCurrency.ticker.toUpperCase()} ~ ${rate.localizedStringAsFixed(
+ locale: ref.watch(
+ localeServiceChangeNotifierProvider
+ .select((value) => value.locale),
+ ),
+ )} ${receivingCurrency.ticker.toUpperCase()}";
+
+ return ConditionalParent(
+ condition: i > 0,
+ builder: (child) => Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ isDesktop
+ ? Container(
+ height: 1,
+ color: Theme.of(context)
+ .extension()!
+ .background,
+ )
+ : const SizedBox(
+ height: 16,
+ ),
+ child,
+ ],
+ ),
+ child: _ProviderOption(
+ key: Key(widget.exchange.name + e.exchangeProvider),
+ exchange: widget.exchange,
+ estimate: e,
+ rateString: rateString,
+ kycRating: e.kycRating,
+ ),
+ );
+ },
+ ),
+ ],
+ );
+ } else {
+ Logging.instance.log(
+ "$runtimeType rate unavailable for ${widget.exchange.name}: $data",
+ level: LogLevel.Warning,
+ );
+
+ return Consumer(
+ builder: (_, ref, __) {
+ String? message;
+
+ final range = data?.item2;
+ if (range != null) {
+ if (range.min != null && amount < range.min!) {
+ message ??= "Amount too small";
+ } else if (range.max != null && amount > range.max!) {
+ message ??= "Amount too large";
+ }
+ } else if (data?.item1.value == null) {
+ final rateType = ref.watch(efRateTypeProvider) ==
+ ExchangeRateType.estimated
+ ? "estimated"
+ : "fixed";
+ message ??= "Pair unavailable on $rateType rate flow";
+ }
+
+ return _ProviderOption(
+ exchange: widget.exchange,
+ estimate: null,
+ rateString: message ?? "Failed to fetch rate",
+ rateColor:
+ Theme.of(context).extension()!.textError,
+ );
+ },
+ );
+ }
+ } else {
+ // show n/a
+ return _ProviderOption(
+ exchange: widget.exchange,
+ estimate: null,
+ rateString: "n/a",
+ );
+ }
+ },
+ ),
+ );
+ }
+}
+
+class _ProviderOption extends ConsumerStatefulWidget {
+ const _ProviderOption({
+ Key? key,
+ required this.exchange,
+ required this.estimate,
+ required this.rateString,
+ this.kycRating,
+ this.loadingString = false,
+ this.rateColor,
+ }) : super(key: key);
+
+ final Exchange exchange;
+ final Estimate? estimate;
+ final String rateString;
+ final String? kycRating;
+ final bool loadingString;
+ final Color? rateColor;
+
+ @override
+ ConsumerState<_ProviderOption> createState() => _ProviderOptionState();
+}
+
+class _ProviderOptionState extends ConsumerState<_ProviderOption> {
+ final isDesktop = Util.isDesktop;
+
+ late final String _id;
+
+ @override
+ void initState() {
+ _id =
+ "${widget.exchange.name} (${widget.estimate?.exchangeProvider ?? widget.exchange.name})";
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ String groupValue = ref.watch(currentCombinedExchangeIdProvider);
+
+ if (ref.watch(efExchangeProvider).name ==
+ (widget.estimate?.exchangeProvider ?? widget.exchange.name)) {
+ groupValue = _id;
+ }
+
+ return ConditionalParent(
+ condition: isDesktop,
+ builder: (child) => MouseRegion(
+ cursor: SystemMouseCursors.click,
+ child: child,
+ ),
+ child: GestureDetector(
+ onTap: () {
+ ref.read(efExchangeProvider.notifier).state = widget.exchange;
+ ref.read(efExchangeProviderNameProvider.notifier).state =
+ widget.estimate?.exchangeProvider ?? widget.exchange.name;
+ },
+ child: Container(
+ color: Colors.transparent,
+ child: Padding(
+ padding:
+ isDesktop ? const EdgeInsets.all(16) : const EdgeInsets.all(0),
+ child: Row(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ SizedBox(
+ width: 20,
+ height: 20,
+ child: Padding(
+ padding: EdgeInsets.only(top: isDesktop ? 20.0 : 15.0),
+ child: Radio(
+ activeColor: Theme.of(context)
+ .extension()!
+ .radioButtonIconEnabled,
+ value: _id,
+ groupValue: groupValue,
+ onChanged: (_) {
+ ref.read(efExchangeProvider.notifier).state =
+ widget.exchange;
+ ref
+ .read(efExchangeProviderNameProvider.notifier)
+ .state =
+ widget.estimate?.exchangeProvider ??
+ widget.exchange.name;
+ },
+ ),
+ ),
+ ),
+ const SizedBox(
+ width: 14,
+ ),
+ Padding(
+ padding: const EdgeInsets.only(top: 5.0),
+ child: SizedBox(
+ width: isDesktop ? 32 : 24,
+ height: isDesktop ? 32 : 24,
+ child: SvgPicture.asset(
+ Assets.exchange.getIconFor(
+ exchangeName: widget.exchange.name,
+ ),
+ width: isDesktop ? 32 : 24,
+ height: isDesktop ? 32 : 24,
+ ),
+ ),
+ ),
+ const SizedBox(
+ width: 10,
+ ),
+ Expanded(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.start,
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ widget.estimate?.exchangeProvider ??
+ widget.exchange.name,
+ style: STextStyles.titleBold12(context).copyWith(
+ color: Theme.of(context)
+ .extension()!
+ .textDark2,
+ ),
+ ),
+ widget.loadingString
+ ? AnimatedText(
+ stringsToLoopThrough: const [
+ "Loading",
+ "Loading.",
+ "Loading..",
+ "Loading...",
+ ],
+ style:
+ STextStyles.itemSubtitle12(context).copyWith(
+ color: Theme.of(context)
+ .extension()!
+ .textSubtitle1,
+ ),
+ )
+ : Text(
+ widget.rateString,
+ style:
+ STextStyles.itemSubtitle12(context).copyWith(
+ color: widget.rateColor ??
+ Theme.of(context)
+ .extension()!
+ .textSubtitle1,
+ ),
+ ),
+ ],
+ ),
+ ),
+ if (widget.kycRating != null)
+ TrocadorKYCInfoButton(
+ kycType: TrocadorKYCType.fromString(
+ widget.kycRating!,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/pages/exchange_view/sub_widgets/exchange_provider_options.dart b/lib/pages/exchange_view/sub_widgets/exchange_provider_options.dart
index f770278f3..a145d36a4 100644
--- a/lib/pages/exchange_view/sub_widgets/exchange_provider_options.dart
+++ b/lib/pages/exchange_view/sub_widgets/exchange_provider_options.dart
@@ -1,24 +1,13 @@
-import 'package:decimal/decimal.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
-import 'package:flutter_svg/svg.dart';
-import 'package:stackwallet/exceptions/exchange/pair_unavailable_exception.dart';
import 'package:stackwallet/models/exchange/aggregate_currency.dart';
-import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
+import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_provider_option.dart';
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
-import 'package:stackwallet/services/exchange/exchange_response.dart';
import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart';
-import 'package:stackwallet/utilities/amount/amount.dart';
-import 'package:stackwallet/utilities/assets.dart';
-import 'package:stackwallet/utilities/enums/coin_enum.dart';
-import 'package:stackwallet/utilities/logger.dart';
-import 'package:stackwallet/utilities/show_loading.dart';
-import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/services/exchange/trocador/trocador_exchange.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
-import 'package:stackwallet/widgets/animated_text.dart';
-import 'package:stackwallet/widgets/conditional_parent.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
class ExchangeProviderOptions extends ConsumerStatefulWidget {
@@ -60,11 +49,10 @@ class _ExchangeProviderOptionsState
@override
Widget build(BuildContext context) {
- final sendCurrency = ref.watch(exchangeFormStateProvider).sendCurrency;
+ final sendCurrency =
+ ref.watch(efCurrencyPairProvider.select((value) => value.send));
final receivingCurrency =
- ref.watch(exchangeFormStateProvider).receiveCurrency;
- final fromAmount = ref.watch(exchangeFormStateProvider).sendAmount;
- final toAmount = ref.watch(exchangeFormStateProvider).receiveAmount;
+ ref.watch(efCurrencyPairProvider.select((value) => value.receive));
final showChangeNow = exchangeSupported(
exchangeName: ChangeNowExchange.exchangeName,
@@ -76,6 +64,11 @@ class _ExchangeProviderOptionsState
sendCurrency: sendCurrency,
receiveCurrency: receivingCurrency,
);
+ final showTrocador = exchangeSupported(
+ exchangeName: TrocadorExchange.exchangeName,
+ sendCurrency: sendCurrency,
+ receiveCurrency: receivingCurrency,
+ );
return RoundedWhiteContainer(
padding: isDesktop ? const EdgeInsets.all(0) : const EdgeInsets.all(12),
@@ -85,239 +78,11 @@ class _ExchangeProviderOptionsState
child: Column(
children: [
if (showChangeNow)
- ConditionalParent(
- condition: isDesktop,
- builder: (child) => MouseRegion(
- cursor: SystemMouseCursors.click,
- child: child,
- ),
- child: GestureDetector(
- onTap: () {
- if (ref.read(exchangeFormStateProvider).exchange.name !=
- ChangeNowExchange.exchangeName) {
- showLoading(
- whileFuture:
- ref.read(exchangeFormStateProvider).updateExchange(
- exchange: ChangeNowExchange.instance,
- shouldUpdateData: true,
- shouldNotifyListeners: true,
- ),
- context: context,
- message: "Updating rates",
- isDesktop: isDesktop,
- );
- }
- },
- child: Container(
- color: Colors.transparent,
- child: Padding(
- padding: isDesktop
- ? const EdgeInsets.all(16)
- : const EdgeInsets.all(0),
- child: Row(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- SizedBox(
- width: 20,
- height: 20,
- child: Padding(
- padding:
- EdgeInsets.only(top: isDesktop ? 20.0 : 15.0),
- child: Radio(
- activeColor: Theme.of(context)
- .extension()!
- .radioButtonIconEnabled,
- value: ChangeNowExchange.exchangeName,
- groupValue: ref.watch(exchangeFormStateProvider
- .select((value) => value.exchange.name)),
- onChanged: (_) {
- if (ref
- .read(exchangeFormStateProvider)
- .exchange
- .name !=
- ChangeNowExchange.exchangeName) {
- ref
- .read(exchangeFormStateProvider)
- .updateExchange(
- exchange: ChangeNowExchange.instance,
- shouldUpdateData: true,
- shouldNotifyListeners: true,
- );
- }
- },
- ),
- ),
- ),
- const SizedBox(
- width: 14,
- ),
- Padding(
- padding: const EdgeInsets.only(top: 5.0),
- child: SizedBox(
- width: isDesktop ? 32 : 24,
- height: isDesktop ? 32 : 24,
- child: SvgPicture.asset(
- Assets.exchange.changeNow,
- width: isDesktop ? 32 : 24,
- height: isDesktop ? 32 : 24,
- ),
- ),
- ),
- const SizedBox(
- width: 10,
- ),
- Expanded(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.start,
- mainAxisSize: MainAxisSize.min,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- ChangeNowExchange.exchangeName,
- style:
- STextStyles.titleBold12(context).copyWith(
- color: Theme.of(context)
- .extension()!
- .textDark2,
- ),
- ),
- if (sendCurrency != null &&
- receivingCurrency != null &&
- toAmount != null &&
- toAmount > Decimal.zero &&
- fromAmount != null &&
- fromAmount > Decimal.zero)
- FutureBuilder(
- future:
- ChangeNowExchange.instance.getEstimate(
- sendCurrency.ticker,
- receivingCurrency.ticker,
- widget.reversed ? toAmount : fromAmount,
- widget.fixedRate,
- widget.reversed,
- ),
- builder: (context,
- AsyncSnapshot>
- snapshot) {
- if (snapshot.connectionState ==
- ConnectionState.done &&
- snapshot.hasData) {
- final estimate = snapshot.data?.value;
- if (estimate != null) {
- Coin coin;
- try {
- coin = coinFromTickerCaseInsensitive(
- receivingCurrency.ticker);
- } catch (_) {
- coin = Coin.bitcoin;
- }
- Amount rate;
- if (estimate.reversed) {
- rate = (toAmount /
- estimate.estimatedAmount)
- .toDecimal(
- scaleOnInfinitePrecision: 18)
- .toAmount(
- fractionDigits:
- coin.decimals);
- } else {
- rate = (estimate.estimatedAmount /
- fromAmount)
- .toDecimal(
- scaleOnInfinitePrecision: 18)
- .toAmount(
- fractionDigits:
- coin.decimals);
- }
-
- return Text(
- "1 ${sendCurrency.ticker.toUpperCase()} ~ ${rate.localizedStringAsFixed(
- locale: ref.watch(
- localeServiceChangeNotifierProvider
- .select(
- (value) => value.locale),
- ),
- )} ${receivingCurrency.ticker.toUpperCase()}",
- style: STextStyles.itemSubtitle12(
- context)
- .copyWith(
- color: Theme.of(context)
- .extension()!
- .textSubtitle1,
- ),
- );
- } else if (snapshot.data?.exception
- is PairUnavailableException) {
- return Text(
- "Unsupported pair",
- style: STextStyles.itemSubtitle12(
- context)
- .copyWith(
- color: Theme.of(context)
- .extension()!
- .textSubtitle1,
- ),
- );
- } else {
- Logging.instance.log(
- "$runtimeType failed to fetch rate for ChangeNOW: ${snapshot.data}",
- level: LogLevel.Warning,
- );
- return Text(
- "Failed to fetch rate",
- style: STextStyles.itemSubtitle12(
- context)
- .copyWith(
- color: Theme.of(context)
- .extension()!
- .textSubtitle1,
- ),
- );
- }
- } else {
- return AnimatedText(
- stringsToLoopThrough: const [
- "Loading",
- "Loading.",
- "Loading..",
- "Loading...",
- ],
- style:
- STextStyles.itemSubtitle12(context)
- .copyWith(
- color: Theme.of(context)
- .extension()!
- .textSubtitle1,
- ),
- );
- }
- },
- ),
- if (!(sendCurrency != null &&
- receivingCurrency != null &&
- toAmount != null &&
- toAmount > Decimal.zero &&
- fromAmount != null &&
- fromAmount > Decimal.zero))
- Text(
- "n/a",
- style: STextStyles.itemSubtitle12(context)
- .copyWith(
- color: Theme.of(context)
- .extension()!
- .textSubtitle1,
- ),
- ),
- ],
- ),
- ),
- ],
- ),
- ),
- ),
- ),
+ ExchangeOption(
+ exchange: ChangeNowExchange.instance,
+ fixedRate: widget.fixedRate,
+ reversed: widget.reversed,
),
-
if (showChangeNow && showMajesticBank)
isDesktop
? Container(
@@ -328,446 +93,28 @@ class _ExchangeProviderOptionsState
: const SizedBox(
height: 16,
),
-
if (showMajesticBank)
- ConditionalParent(
- condition: isDesktop,
- builder: (child) => MouseRegion(
- cursor: SystemMouseCursors.click,
- child: child,
- ),
- child: GestureDetector(
- onTap: () {
- if (ref.read(exchangeFormStateProvider).exchange.name !=
- MajesticBankExchange.exchangeName) {
- showLoading(
- whileFuture:
- ref.read(exchangeFormStateProvider).updateExchange(
- exchange: MajesticBankExchange.instance,
- shouldUpdateData: true,
- shouldNotifyListeners: true,
- ),
- context: context,
- isDesktop: isDesktop,
- message: "Updating rates",
- );
- }
- },
- child: Container(
- color: Colors.transparent,
- child: Padding(
- padding: isDesktop
- ? const EdgeInsets.all(16)
- : const EdgeInsets.all(0),
- child: Row(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- SizedBox(
- width: 20,
- height: 20,
- child: Padding(
- padding:
- EdgeInsets.only(top: isDesktop ? 20.0 : 15.0),
- child: Radio(
- activeColor: Theme.of(context)
- .extension()!
- .radioButtonIconEnabled,
- value: MajesticBankExchange.exchangeName,
- groupValue: ref.watch(exchangeFormStateProvider
- .select((value) => value.exchange.name)),
- onChanged: (_) {
- if (ref
- .read(exchangeFormStateProvider)
- .exchange
- .name !=
- MajesticBankExchange.exchangeName) {
- ref
- .read(exchangeFormStateProvider)
- .updateExchange(
- exchange: MajesticBankExchange.instance,
- shouldUpdateData: true,
- shouldNotifyListeners: true,
- );
- }
- },
- ),
- ),
- ),
- const SizedBox(
- width: 14,
- ),
- Padding(
- padding: const EdgeInsets.only(top: 5.0),
- child: SizedBox(
- width: isDesktop ? 32 : 24,
- height: isDesktop ? 32 : 24,
- child: SvgPicture.asset(
- Assets.exchange.majesticBankBlue,
- width: isDesktop ? 32 : 24,
- height: isDesktop ? 32 : 24,
- ),
- ),
- ),
- const SizedBox(
- width: 10,
- ),
- Expanded(
- child: Column(
- mainAxisAlignment: MainAxisAlignment.start,
- mainAxisSize: MainAxisSize.min,
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- MajesticBankExchange.exchangeName,
- style:
- STextStyles.titleBold12(context).copyWith(
- color: Theme.of(context)
- .extension()!
- .textDark2,
- ),
- ),
- if (sendCurrency != null &&
- receivingCurrency != null &&
- toAmount != null &&
- toAmount > Decimal.zero &&
- fromAmount != null &&
- fromAmount > Decimal.zero)
- FutureBuilder(
- future:
- MajesticBankExchange.instance.getEstimate(
- sendCurrency.ticker,
- receivingCurrency.ticker,
- widget.reversed ? toAmount : fromAmount,
- widget.fixedRate,
- widget.reversed,
- ),
- builder: (context,
- AsyncSnapshot>
- snapshot) {
- if (snapshot.connectionState ==
- ConnectionState.done &&
- snapshot.hasData) {
- final estimate = snapshot.data?.value;
- if (estimate != null) {
- Coin coin;
- try {
- coin = coinFromTickerCaseInsensitive(
- receivingCurrency.ticker);
- } catch (_) {
- coin = Coin.bitcoin;
- }
- Amount rate;
- if (estimate.reversed) {
- rate = (toAmount /
- estimate.estimatedAmount)
- .toDecimal(
- scaleOnInfinitePrecision: 18)
- .toAmount(
- fractionDigits: coin.decimals,
- );
- } else {
- rate = (estimate.estimatedAmount /
- fromAmount)
- .toDecimal(
- scaleOnInfinitePrecision: 18)
- .toAmount(
- fractionDigits: coin.decimals,
- );
- }
-
- return Text(
- "1 ${sendCurrency.ticker.toUpperCase()} ~ ${rate.localizedStringAsFixed(
- locale: ref.watch(
- localeServiceChangeNotifierProvider
- .select(
- (value) => value.locale),
- ),
- )} ${receivingCurrency.ticker.toUpperCase()}",
- style: STextStyles.itemSubtitle12(
- context)
- .copyWith(
- color: Theme.of(context)
- .extension()!
- .textSubtitle1,
- ),
- );
- } else if (snapshot.data?.exception
- is PairUnavailableException) {
- return Text(
- "Unsupported pair",
- style: STextStyles.itemSubtitle12(
- context)
- .copyWith(
- color: Theme.of(context)
- .extension()!
- .textSubtitle1,
- ),
- );
- } else {
- Logging.instance.log(
- "$runtimeType failed to fetch rate for ChangeNOW: ${snapshot.data}",
- level: LogLevel.Warning,
- );
- return Text(
- "Failed to fetch rate",
- style: STextStyles.itemSubtitle12(
- context)
- .copyWith(
- color: Theme.of(context)
- .extension()!
- .textSubtitle1,
- ),
- );
- }
- } else {
- return AnimatedText(
- stringsToLoopThrough: const [
- "Loading",
- "Loading.",
- "Loading..",
- "Loading...",
- ],
- style:
- STextStyles.itemSubtitle12(context)
- .copyWith(
- color: Theme.of(context)
- .extension()!
- .textSubtitle1,
- ),
- );
- }
- },
- ),
- if (!(sendCurrency != null &&
- receivingCurrency != null &&
- toAmount != null &&
- toAmount > Decimal.zero &&
- fromAmount != null &&
- fromAmount > Decimal.zero))
- Text(
- "n/a",
- style: STextStyles.itemSubtitle12(context)
- .copyWith(
- color: Theme.of(context)
- .extension()!
- .textSubtitle1,
- ),
- ),
- ],
- ),
- ),
- ],
- ),
- ),
- ),
- ),
+ ExchangeOption(
+ exchange: MajesticBankExchange.instance,
+ fixedRate: widget.fixedRate,
+ reversed: widget.reversed,
+ ),
+ if ((showChangeNow || showMajesticBank) && showTrocador)
+ isDesktop
+ ? Container(
+ height: 1,
+ color:
+ Theme.of(context).extension()!.background,
+ )
+ : const SizedBox(
+ height: 16,
+ ),
+ if (showTrocador)
+ ExchangeOption(
+ fixedRate: widget.fixedRate,
+ reversed: widget.reversed,
+ exchange: TrocadorExchange.instance,
),
- // if (isDesktop)
- // Container(
- // height: 1,
- // color: Theme.of(context).extension()!.background,
- // ),
- // if (!isDesktop)
- // const SizedBox(
- // height: 16,
- // ),
- // ConditionalParent(
- // condition: isDesktop,
- // builder: (child) => MouseRegion(
- // cursor: SystemMouseCursors.click,
- // child: child,
- // ),
- // child: GestureDetector(
- // onTap: () {
- // if (ref.read(currentExchangeNameStateProvider.state).state !=
- // SimpleSwapExchange.exchangeName) {
- // // ref.read(currentExchangeNameStateProvider.state).state =
- // // SimpleSwapExchange.exchangeName;
- // ref.read(exchangeFormStateProvider).exchange =
- // Exchange.fromName(ref
- // .read(currentExchangeNameStateProvider.state)
- // .state);
- // }
- // },
- // child: Container(
- // color: Colors.transparent,
- // child: Padding(
- // padding: isDesktop
- // ? const EdgeInsets.all(16)
- // : const EdgeInsets.all(0),
- // child: Row(
- // crossAxisAlignment: CrossAxisAlignment.start,
- // children: [
- // SizedBox(
- // width: 20,
- // height: 20,
- // child: Radio(
- // activeColor: Theme.of(context)
- // .extension()!
- // .radioButtonIconEnabled,
- // value: SimpleSwapExchange.exchangeName,
- // groupValue: ref
- // .watch(currentExchangeNameStateProvider.state)
- // .state,
- // onChanged: (value) {
- // if (value is String) {
- // ref
- // .read(currentExchangeNameStateProvider.state)
- // .state = value;
- // ref.read(exchangeFormStateProvider).exchange =
- // Exchange.fromName(ref
- // .read(currentExchangeNameStateProvider
- // .state)
- // .state);
- // }
- // },
- // ),
- // ),
- // const SizedBox(
- // width: 14,
- // ),
- // // SvgPicture.asset(
- // // Assets.exchange.simpleSwap,
- // // width: isDesktop ? 32 : 24,
- // // height: isDesktop ? 32 : 24,
- // // ),
- // // const SizedBox(
- // // width: 10,
- // // ),
- // // Expanded(
- // // child: Column(
- // // mainAxisAlignment: MainAxisAlignment.start,
- // // mainAxisSize: MainAxisSize.min,
- // // crossAxisAlignment: CrossAxisAlignment.start,
- // // children: [
- // // Text(
- // // SimpleSwapExchange.exchangeName,
- // // style: STextStyles.titleBold12(context).copyWith(
- // // color: Theme.of(context)
- // // .extension()!
- // // .textDark2,
- // // ),
- // // ),
- // // if (from != null &&
- // // to != null &&
- // // toAmount != null &&
- // // toAmount! > Decimal.zero &&
- // // fromAmount != null &&
- // // fromAmount! > Decimal.zero)
- // // FutureBuilder(
- // // future: SimpleSwapExchange().getEstimate(
- // // from!,
- // // to!,
- // // // reversed ? toAmount! : fromAmount!,
- // // fromAmount!,
- // // fixedRate,
- // // // reversed,
- // // false,
- // // ),
- // // builder: (context,
- // // AsyncSnapshot>
- // // snapshot) {
- // // if (snapshot.connectionState ==
- // // ConnectionState.done &&
- // // snapshot.hasData) {
- // // final estimate = snapshot.data?.value;
- // // if (estimate != null) {
- // // Decimal rate = (estimate.estimatedAmount /
- // // fromAmount!)
- // // .toDecimal(
- // // scaleOnInfinitePrecision: 12);
- // //
- // // Coin coin;
- // // try {
- // // coin =
- // // coinFromTickerCaseInsensitive(to!);
- // // } catch (_) {
- // // coin = Coin.bitcoin;
- // // }
- // // return Text(
- // // "1 ${from!.toUpperCase()} ~ ${Format.localizedStringAsFixed(
- // // value: rate,
- // // locale: ref.watch(
- // // localeServiceChangeNotifierProvider
- // // .select(
- // // (value) => value.locale),
- // // ),
- // // decimalPlaces:
- // // Constants.decimalPlacesForCoin(
- // // coin),
- // // )} ${to!.toUpperCase()}",
- // // style:
- // // STextStyles.itemSubtitle12(context)
- // // .copyWith(
- // // color: Theme.of(context)
- // // .extension()!
- // // .textSubtitle1,
- // // ),
- // // );
- // // } else {
- // // Logging.instance.log(
- // // "$runtimeType failed to fetch rate for SimpleSwap: ${snapshot.data}",
- // // level: LogLevel.Warning,
- // // );
- // // return Text(
- // // "Failed to fetch rate",
- // // style:
- // // STextStyles.itemSubtitle12(context)
- // // .copyWith(
- // // color: Theme.of(context)
- // // .extension()!
- // // .textSubtitle1,
- // // ),
- // // );
- // // }
- // // } else {
- // // return AnimatedText(
- // // stringsToLoopThrough: const [
- // // "Loading",
- // // "Loading.",
- // // "Loading..",
- // // "Loading...",
- // // ],
- // // style: STextStyles.itemSubtitle12(context)
- // // .copyWith(
- // // color: Theme.of(context)
- // // .extension()!
- // // .textSubtitle1,
- // // ),
- // // );
- // // }
- // // },
- // // ),
- // // // if (!(from != null &&
- // // // to != null &&
- // // // (reversed
- // // // ? toAmount != null && toAmount! > Decimal.zero
- // // // : fromAmount != null &&
- // // // fromAmount! > Decimal.zero)))
- // // if (!(from != null &&
- // // to != null &&
- // // toAmount != null &&
- // // toAmount! > Decimal.zero &&
- // // fromAmount != null &&
- // // fromAmount! > Decimal.zero))
- // // Text(
- // // "n/a",
- // // style: STextStyles.itemSubtitle12(context)
- // // .copyWith(
- // // color: Theme.of(context)
- // // .extension()!
- // // .textSubtitle1,
- // // ),
- // // ),
- // // ],
- // // ),
- // // ),
- // ],
- // ),
- // ),
- // ),
- // ),
- // ),
],
),
);
diff --git a/lib/pages/exchange_view/sub_widgets/rate_type_toggle.dart b/lib/pages/exchange_view/sub_widgets/rate_type_toggle.dart
index f85c0cfcd..b83883509 100644
--- a/lib/pages/exchange_view/sub_widgets/rate_type_toggle.dart
+++ b/lib/pages/exchange_view/sub_widgets/rate_type_toggle.dart
@@ -29,9 +29,7 @@ class RateTypeToggle extends ConsumerWidget {
onChanged?.call(ExchangeRateType.estimated);
}
},
- isOn: ref.watch(exchangeFormStateProvider
- .select((value) => value.exchangeRateType)) ==
- ExchangeRateType.fixed,
+ isOn: ref.watch(efRateTypeProvider) == ExchangeRateType.fixed,
onColor: isDesktop
? Theme.of(context)
.extension()!
diff --git a/lib/pages/exchange_view/trade_details_view.dart b/lib/pages/exchange_view/trade_details_view.dart
index f0cb7b7a8..5f8e9d471 100644
--- a/lib/pages/exchange_view/trade_details_view.dart
+++ b/lib/pages/exchange_view/trade_details_view.dart
@@ -20,6 +20,7 @@ import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dar
import 'package:stackwallet/services/exchange/exchange.dart';
import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart';
import 'package:stackwallet/services/exchange/simpleswap/simpleswap_exchange.dart';
+import 'package:stackwallet/services/exchange/trocador/trocador_exchange.dart';
import 'package:stackwallet/utilities/amount/amount.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/clipboard_interface.dart';
@@ -1205,6 +1206,13 @@ class _TradeDetailsViewState extends ConsumerState {
url =
"https://majesticbank.sc/track?trx=${trade.tradeId}";
break;
+
+ default:
+ if (trade.exchangeName
+ .startsWith(TrocadorExchange.exchangeName)) {
+ url =
+ "https://trocador.app/en/checkout${trade.tradeId}";
+ }
}
return ConditionalParent(
condition: isDesktop,
diff --git a/lib/pages/exchange_view/wallet_initiated_exchange_view.dart b/lib/pages/exchange_view/wallet_initiated_exchange_view.dart
index 3c726b702..7085bd8aa 100644
--- a/lib/pages/exchange_view/wallet_initiated_exchange_view.dart
+++ b/lib/pages/exchange_view/wallet_initiated_exchange_view.dart
@@ -54,7 +54,8 @@ class _WalletInitiatedExchangeViewState
ExchangeDataLoadingService.instance.onLoadingComplete = () {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty(
- ref.read(exchangeFormStateProvider),
+ ref.read(efCurrencyPairProvider),
+ ref.read(efRateTypeProvider),
);
setState(() {
_initialCachePopulationUnderway = false;
@@ -70,7 +71,8 @@ class _WalletInitiatedExchangeViewState
ExchangeDataLoadingService.instance.onLoadingComplete = () {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty(
- ref.read(exchangeFormStateProvider),
+ ref.read(efCurrencyPairProvider),
+ ref.read(efRateTypeProvider),
);
setState(() {
_initialCachePopulationUnderway = false;
diff --git a/lib/pages_desktop_specific/desktop_exchange/desktop_all_trades_view.dart b/lib/pages_desktop_specific/desktop_exchange/desktop_all_trades_view.dart
index 34d688b21..7d344f47d 100644
--- a/lib/pages_desktop_specific/desktop_exchange/desktop_all_trades_view.dart
+++ b/lib/pages_desktop_specific/desktop_exchange/desktop_all_trades_view.dart
@@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:isar/isar.dart';
+import 'package:stackwallet/db/isar/main_db.dart';
import 'package:stackwallet/models/exchange/change_now/exchange_transaction_status.dart';
import 'package:stackwallet/models/exchange/response_objects/trade.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart';
@@ -29,8 +30,6 @@ import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:stackwallet/widgets/textfield_icon_button.dart';
import 'package:tuple/tuple.dart';
-import '../../db/isar/main_db.dart';
-
class DesktopAllTradesView extends ConsumerStatefulWidget {
const DesktopAllTradesView({Key? key}) : super(key: key);
diff --git a/lib/pages_desktop_specific/desktop_exchange/desktop_exchange_view.dart b/lib/pages_desktop_specific/desktop_exchange/desktop_exchange_view.dart
index 17cd1c778..36006b7c1 100644
--- a/lib/pages_desktop_specific/desktop_exchange/desktop_exchange_view.dart
+++ b/lib/pages_desktop_specific/desktop_exchange/desktop_exchange_view.dart
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/pages/exchange_view/exchange_form.dart';
+import 'package:stackwallet/pages_desktop_specific/desktop_exchange/desktop_all_trades_view.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_exchange/subwidgets/desktop_trade_history.dart';
import 'package:stackwallet/providers/exchange/exchange_form_state_provider.dart';
import 'package:stackwallet/providers/global/prefs_provider.dart';
@@ -14,8 +15,6 @@ import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
-import 'desktop_all_trades_view.dart';
-
class DesktopExchangeView extends ConsumerStatefulWidget {
const DesktopExchangeView({Key? key}) : super(key: key);
@@ -38,7 +37,8 @@ class _DesktopExchangeViewState extends ConsumerState {
ExchangeDataLoadingService.instance.onLoadingComplete = () {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty(
- ref.read(exchangeFormStateProvider),
+ ref.read(efCurrencyPairProvider),
+ ref.read(efRateTypeProvider),
);
setState(() {
_initialCachePopulationUnderway = false;
@@ -54,7 +54,8 @@ class _DesktopExchangeViewState extends ConsumerState {
ExchangeDataLoadingService.instance.onLoadingComplete = () {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty(
- ref.read(exchangeFormStateProvider),
+ ref.read(efCurrencyPairProvider),
+ ref.read(efRateTypeProvider),
);
setState(() {
_initialCachePopulationUnderway = false;
diff --git a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/step_scaffold.dart b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/step_scaffold.dart
index 203ae2d9b..e99c63821 100644
--- a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/step_scaffold.dart
+++ b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/step_scaffold.dart
@@ -84,8 +84,7 @@ class _StepScaffoldState extends ConsumerState {
);
final ExchangeResponse response = await ref
- .read(exchangeFormStateProvider)
- .exchange
+ .read(efExchangeProvider)
.createTrade(
from: ref.read(desktopExchangeModelProvider)!.sendTicker,
to: ref.read(desktopExchangeModelProvider)!.receiveTicker,
@@ -98,24 +97,24 @@ class _StepScaffoldState extends ConsumerState {
extraId: null,
addressRefund: ref.read(desktopExchangeModelProvider)!.refundAddress!,
refundExtraId: "",
- rateId: ref.read(desktopExchangeModelProvider)!.rateId,
+ estimate: ref.read(desktopExchangeModelProvider)!.estimate,
reversed: ref.read(desktopExchangeModelProvider)!.reversed,
);
if (response.value == null) {
if (mounted) {
Navigator.of(context).pop();
- }
- unawaited(
- showDialog(
- context: context,
- barrierDismissible: true,
- builder: (_) => SimpleDesktopDialog(
- title: "Failed to create trade",
- message: response.exception?.toString() ?? ""),
- ),
- );
+ unawaited(
+ showDialog(
+ context: context,
+ barrierDismissible: true,
+ builder: (_) => SimpleDesktopDialog(
+ title: "Failed to create trade",
+ message: response.exception?.toString() ?? ""),
+ ),
+ );
+ }
return false;
}
diff --git a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_1.dart b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_1.dart
index 16c3b8116..dffe71bb9 100644
--- a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_1.dart
+++ b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_1.dart
@@ -38,8 +38,7 @@ class DesktopStep1 extends ConsumerWidget {
children: [
DesktopStepItem(
label: "Swap",
- value: ref.watch(exchangeFormStateProvider
- .select((value) => value.exchange.name)),
+ value: ref.watch(efExchangeProviderNameProvider),
),
Container(
height: 1,
diff --git a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_3.dart b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_3.dart
index ef72553fa..a5d3fba43 100644
--- a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_3.dart
+++ b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_3.dart
@@ -36,8 +36,7 @@ class _DesktopStep3State extends ConsumerState {
children: [
DesktopStepItem(
label: "Swap",
- value: ref.watch(exchangeFormStateProvider
- .select((value) => value.exchange.name)),
+ value: ref.watch(efExchangeProviderNameProvider),
),
Container(
height: 1,
diff --git a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_4.dart b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_4.dart
index 2654c2cea..bbc3fd30c 100644
--- a/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_4.dart
+++ b/lib/pages_desktop_specific/desktop_exchange/exchange_steps/subwidgets/desktop_step_4.dart
@@ -46,7 +46,7 @@ class _DesktopStep4State extends ConsumerState {
}
final statusResponse =
- await ref.read(exchangeFormStateProvider).exchange.updateTrade(trade);
+ await ref.read(efExchangeProvider).updateTrade(trade);
String status = "Waiting";
if (statusResponse.value != null) {
status = statusResponse.value!.status;
diff --git a/lib/pages_desktop_specific/desktop_exchange/subwidgets/desktop_trade_history.dart b/lib/pages_desktop_specific/desktop_exchange/subwidgets/desktop_trade_history.dart
index 707976425..d369a61df 100644
--- a/lib/pages_desktop_specific/desktop_exchange/subwidgets/desktop_trade_history.dart
+++ b/lib/pages_desktop_specific/desktop_exchange/subwidgets/desktop_trade_history.dart
@@ -269,13 +269,6 @@ class _DesktopTradeHistoryState extends ConsumerState {
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- Text(
- "Recent trades",
- style: STextStyles.desktopTextExtraExtraSmall(context),
- ),
- const SizedBox(
- height: 16,
- ),
RoundedWhiteContainer(
child: Center(
child: Text(
diff --git a/lib/providers/exchange/exchange_form_state_provider.dart b/lib/providers/exchange/exchange_form_state_provider.dart
index cb7d32bfe..7828e2771 100644
--- a/lib/providers/exchange/exchange_form_state_provider.dart
+++ b/lib/providers/exchange/exchange_form_state_provider.dart
@@ -1,5 +1,91 @@
+import 'package:decimal/decimal.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
-import 'package:stackwallet/models/exchange/exchange_form_state.dart';
+import 'package:stackwallet/models/exchange/active_pair.dart';
+import 'package:stackwallet/models/exchange/response_objects/estimate.dart';
+import 'package:stackwallet/models/exchange/response_objects/range.dart';
+import 'package:stackwallet/services/exchange/exchange.dart';
+import 'package:stackwallet/services/exchange/exchange_response.dart';
+import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart';
+import 'package:tuple/tuple.dart';
-final exchangeFormStateProvider =
- ChangeNotifierProvider((ref) => ExchangeFormState());
+final efEstimatesListProvider = StateProvider.family<
+ Tuple2>, Range?>?,
+ String>((ref, exchangeName) => null);
+
+final efRateTypeProvider =
+ StateProvider((ref) => ExchangeRateType.estimated);
+
+final efExchangeProvider =
+ StateProvider((ref) => Exchange.defaultExchange);
+final efExchangeProviderNameProvider =
+ StateProvider((ref) => Exchange.defaultExchange.name);
+
+final currentCombinedExchangeIdProvider = Provider((ref) {
+ return "${ref.watch(efExchangeProvider).name}"
+ " (${ref.watch(efExchangeProviderNameProvider)})";
+});
+
+final efSendAmountProvider = StateProvider((ref) => null);
+final efReceiveAmountProvider = StateProvider((ref) => null);
+
+final efSendAmountStringProvider = StateProvider((ref) {
+ final refreshing = ref.watch(efRefreshingProvider);
+ final reversed = ref.watch(efReversedProvider);
+ if (refreshing && reversed) {
+ return "-";
+ } else {
+ return ref.watch(efSendAmountProvider)?.toStringAsFixed(8) ?? "";
+ }
+});
+final efReceiveAmountStringProvider = StateProvider((ref) {
+ final refreshing = ref.watch(efRefreshingProvider);
+ final reversed = ref.watch(efReversedProvider);
+
+ if (refreshing && reversed == false) {
+ return "-";
+ } else {
+ return ref.watch(efReceiveAmountProvider)?.toStringAsFixed(8) ?? "";
+ }
+});
+
+final efReversedProvider = StateProvider((ref) => false);
+
+final efCurrencyPairProvider = ChangeNotifierProvider(
+ (ref) => ActivePair(),
+);
+
+final efEstimateProvider = StateProvider((ref) {
+ final exchange = ref.watch(efExchangeProvider);
+ final provider = ref.watch(efExchangeProviderNameProvider);
+ final reversed = ref.watch(efReversedProvider);
+ final fixedRate = ref.watch(efRateTypeProvider) == ExchangeRateType.fixed;
+
+ final matches = ref
+ .watch(efEstimatesListProvider(exchange.name))
+ ?.item1
+ .value
+ ?.where((e) {
+ return e.exchangeProvider == provider &&
+ e.fixedRate == fixedRate &&
+ e.reversed == reversed;
+ });
+
+ Estimate? result;
+
+ if (matches != null && matches.isNotEmpty) {
+ result = matches.first;
+ } else {
+ result = null;
+ }
+
+ return result;
+});
+
+final efCanExchangeProvider = StateProvider((ref) {
+ final Estimate? estimate = ref.watch(efEstimateProvider);
+ final refreshing = ref.watch(efRefreshingProvider);
+
+ return !refreshing && estimate != null;
+});
+
+final efRefreshingProvider = StateProvider((ref) => false);
diff --git a/lib/services/exchange/TMP.dart b/lib/services/exchange/TMP.dart
deleted file mode 100644
index 868ace14e..000000000
--- a/lib/services/exchange/TMP.dart
+++ /dev/null
@@ -1,389 +0,0 @@
-// import 'package:decimal/decimal.dart';
-// import 'package:flutter/foundation.dart';
-// import 'package:stackwallet/models/exchange/response_objects/currency.dart';
-// import 'package:stackwallet/pages/exchange_view/sub_widgets/exchange_rate_sheet.dart';
-// import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
-// import 'package:stackwallet/services/exchange/exchange.dart';
-// import 'package:stackwallet/utilities/logger.dart';
-//
-// class ExchangeFormState extends ChangeNotifier {
-// ExchangeFormState(this.exchangeRateType);
-// final ExchangeRateType exchangeRateType;
-//
-// Exchange? _exchange;
-// Exchange get exchange =>
-// _exchange ??= ChangeNowExchange(); // default to change now
-// set exchange(Exchange value) {
-// _exchange = value;
-// _updateRangesAndEstimate(
-// shouldNotifyListeners: true,
-// );
-// }
-//
-// bool _reversed = false;
-// bool get reversed => _reversed;
-// // set reversed(bool reversed) {
-// // _reversed = reversed;
-// // //
-// // }
-//
-// Decimal? _rate;
-// Decimal? get rate => _rate;
-// // set rate(Decimal? rate) {
-// // _rate = rate;
-// // //
-// // }
-//
-// Decimal? _sendAmount;
-// Decimal? get sendAmount => _sendAmount;
-// // set sendAmount(Decimal? sendAmount) {
-// // _sendAmount = sendAmount;
-// // //
-// // }
-//
-// Decimal? _receiveAmount;
-// Decimal? get receiveAmount => _receiveAmount;
-// // set receiveAmount(Decimal? receiveAmount) {
-// // _receiveAmount = receiveAmount;
-// // //
-// // }
-//
-// Currency? _sendCurrency;
-// Currency? get sendCurrency => _sendCurrency;
-// // set sendCurrency(Currency? sendCurrency) {
-// // _sendCurrency = sendCurrency;
-// // //
-// // }
-//
-// Currency? _receiveCurrency;
-// Currency? get receiveCurrency => _receiveCurrency;
-// // set receiveCurrency(Currency? receiveCurrency) {
-// // _receiveCurrency = receiveCurrency;
-// // //
-// // }
-//
-// Decimal? _minSendAmount;
-// Decimal? get minSendAmount => _minSendAmount;
-// // set minSendAmount(Decimal? minSendAmount) {
-// // _minSendAmount = minSendAmount;
-// // //
-// // }
-//
-// Decimal? _minReceiveAmount;
-// Decimal? get minReceiveAmount => _minReceiveAmount;
-// // set minReceiveAmount(Decimal? minReceiveAmount) {
-// // _minReceiveAmount = minReceiveAmount;
-// // //
-// // }
-//
-// Decimal? _maxSendAmount;
-// Decimal? get maxSendAmount => _maxSendAmount;
-// // set maxSendAmount(Decimal? maxSendAmount) {
-// // _maxSendAmount = maxSendAmount;
-// // //
-// // }
-//
-// Decimal? _maxReceiveAmount;
-// Decimal? get maxReceiveAmount => _maxReceiveAmount;
-// // set maxReceiveAmount(Decimal? maxReceiveAmount) {
-// // _maxReceiveAmount = maxReceiveAmount;
-// // //
-// // }
-//
-// //============================================================================
-// // computed properties
-// //============================================================================
-//
-// String? get fromTicker => _sendCurrency?.ticker;
-//
-// String? get toTicker => _receiveCurrency?.ticker;
-//
-// String get warning {
-// if (reversed) {
-// if (_receiveCurrency != null && _receiveAmount != null) {
-// if (_minReceiveAmount != null &&
-// _receiveAmount! < _minReceiveAmount! &&
-// _receiveAmount! > Decimal.zero) {
-// return "Minimum amount ${_minReceiveAmount!.toString()} ${_receiveCurrency!.ticker.toUpperCase()}";
-// } else if (_maxReceiveAmount != null &&
-// _receiveAmount! > _maxReceiveAmount!) {
-// return "Maximum amount ${_maxReceiveAmount!.toString()} ${_receiveCurrency!.ticker.toUpperCase()}";
-// }
-// }
-// } else {
-// if (_sendCurrency != null && _sendAmount != null) {
-// if (_minSendAmount != null &&
-// _sendAmount! < _minSendAmount! &&
-// _sendAmount! > Decimal.zero) {
-// return "Minimum amount ${_minSendAmount!.toString()} ${_sendCurrency!.ticker.toUpperCase()}";
-// } else if (_maxSendAmount != null && _sendAmount! > _maxSendAmount!) {
-// return "Maximum amount ${_maxSendAmount!.toString()} ${_sendCurrency!.ticker.toUpperCase()}";
-// }
-// }
-// }
-//
-// return "";
-// }
-//
-// //============================================================================
-// // public state updaters
-// //============================================================================
-//
-// void reset(bool shouldNotifyListeners) {
-// _exchange = null;
-// _reversed = false;
-// _rate = null;
-// _sendAmount = null;
-// _receiveAmount = null;
-// _sendCurrency = null;
-// _receiveCurrency = null;
-// _minSendAmount = null;
-// _minReceiveAmount = null;
-// _maxSendAmount = null;
-// _maxReceiveAmount = null;
-//
-// if (shouldNotifyListeners) {
-// notifyListeners();
-// }
-// }
-//
-// Future setFromAmountAndCalculateToAmount(
-// Decimal? newSendAmount,
-// bool shouldNotifyListeners,
-// ) async {
-// if (newSendAmount == null) {
-// // todo: check if this breaks things and stuff
-// _receiveAmount = null;
-// _sendAmount = null;
-// } else {
-// if (newSendAmount <= Decimal.zero) {
-// _receiveAmount = Decimal.zero;
-// }
-//
-// _sendAmount = newSendAmount;
-// _reversed = false;
-//
-// await _updateRangesAndEstimate(
-// shouldNotifyListeners: false,
-// );
-// }
-//
-// if (shouldNotifyListeners) {
-// notifyListeners();
-// }
-// }
-//
-// Future setToAmountAndCalculateFromAmount(
-// Decimal? newReceiveAmount,
-// bool shouldNotifyListeners,
-// ) async {
-// if (newReceiveAmount == null) {
-// // todo: check if this breaks things and stuff
-// _receiveAmount = null;
-// _sendAmount = null;
-// } else {
-// if (newReceiveAmount <= Decimal.zero) {
-// _sendAmount = Decimal.zero;
-// }
-//
-// _receiveAmount = newReceiveAmount;
-// _reversed = true;
-//
-// await _updateRangesAndEstimate(
-// shouldNotifyListeners: false,
-// );
-// }
-//
-// if (shouldNotifyListeners) {
-// notifyListeners();
-// }
-// }
-//
-// Future updateFrom(
-// Currency sendCurrency,
-// bool shouldNotifyListeners,
-// ) async {
-// try {
-// _sendCurrency = sendCurrency;
-// if (_receiveCurrency == null) {
-// _rate = null;
-// } else {
-// await _updateRangesAndEstimate(
-// shouldNotifyListeners: false,
-// );
-// }
-// } catch (e, s) {
-// Logging.instance.log("$e\n$s", level: LogLevel.Error);
-// }
-// if (shouldNotifyListeners) {
-// notifyListeners();
-// }
-// }
-//
-// Future updateTo(
-// Currency receiveCurrency,
-// bool shouldNotifyListeners,
-// ) async {
-// try {
-// _receiveCurrency = receiveCurrency;
-//
-// if (_sendCurrency == null) {
-// _rate = null;
-// } else {
-// await _updateRangesAndEstimate(
-// shouldNotifyListeners: false,
-// );
-// }
-// } catch (e, s) {
-// Logging.instance.log("$e\n$s", level: LogLevel.Error);
-// }
-// if (shouldNotifyListeners) {
-// notifyListeners();
-// }
-// }
-//
-// Future swap(
-// {required bool shouldNotifyListeners,}) async {
-// final Decimal? temp = sendAmount;
-// _sendAmount = receiveAmount;
-// _receiveAmount = temp;
-//
-// _minSendAmount = null;
-// _maxSendAmount = null;
-// _minReceiveAmount = null;
-// _maxReceiveAmount = null;
-//
-// final Currency? tmp = sendCurrency;
-// _sendCurrency = receiveCurrency;
-// _receiveCurrency = tmp;
-//
-// await _updateRangesAndEstimate(
-// shouldNotifyListeners: false,
-// );
-// }
-//
-// //============================================================================
-// // private state updaters
-// //============================================================================
-//
-// Future _updateRangesAndEstimate(
-// {required bool shouldNotifyListeners,}) async {
-// await _updateRanges(shouldNotifyListeners: false);
-// await _updateEstimate(shouldNotifyListeners: false);
-// if (shouldNotifyListeners) {
-// notifyListeners();
-// }
-// }
-//
-// Future _updateRanges({required bool shouldNotifyListeners,}) async {
-// // if (exchange?.name == SimpleSwapExchange.exchangeName) {
-// // reversed = false;
-// // }
-// final _send = sendCurrency;
-// final _receive = receiveCurrency;
-// if (_send == null || _receive == null) {
-// Logging.instance.log(
-// "Tried to $runtimeType.updateRanges where ( $_send || $_receive) for: $exchange",
-// level: LogLevel.Info,
-// );
-// return;
-// }
-// final response = await exchange.getRange(
-// _send.ticker,
-// _receive.ticker,
-// exchangeRateType == ExchangeRateType.fixed,
-// );
-//
-// if (response.value == null) {
-// Logging.instance.log(
-// "Tried to $runtimeType.updateRanges for: $exchange where response: $response",
-// level: LogLevel.Info,
-// );
-// return;
-// }
-// final responseReversed = await exchange.getRange(
-// _receive.ticker,
-// _send.ticker,
-// exchangeRateType == ExchangeRateType.fixed,
-// );
-//
-// if (responseReversed.value == null) {
-// Logging.instance.log(
-// "Tried to $runtimeType.updateRanges for: $exchange where response: $responseReversed",
-// level: LogLevel.Info,
-// );
-// return;
-// }
-//
-// final range = response.value!;
-// final rangeReversed = responseReversed.value!;
-//
-// _minSendAmount = range.min;
-// _maxSendAmount = range.max;
-// _minReceiveAmount = rangeReversed.min;
-// _maxReceiveAmount = rangeReversed.max;
-//
-// //todo: check if print needed
-// // debugPrint(
-// // "updated range for: $exchange for $_fromTicker-$_toTicker: $range");
-//
-// if (shouldNotifyListeners) {
-// notifyListeners();
-// }
-// }
-//
-// Future _updateEstimate({
-// required bool shouldNotifyListeners,
-// }) async {
-// // if (exchange?.name == SimpleSwapExchange.exchangeName) {
-// // reversed = false;
-// // }
-// final amount = reversed ? receiveAmount : sendAmount;
-// if (sendCurrency == null ||
-// receiveCurrency == null ||
-// amount == null ||
-// amount <= Decimal.zero) {
-// Logging.instance.log(
-// "Tried to $runtimeType.updateEstimate for: $exchange where (from: $sendCurrency || to: $receiveCurrency || amount: $amount)",
-// level: LogLevel.Info,
-// );
-// return;
-// }
-// final response = await exchange.getEstimate(
-// sendCurrency!.ticker,
-// receiveCurrency!.ticker,
-// amount,
-// exchangeRateType == ExchangeRateType.fixed,
-// reversed,
-// );
-//
-// if (response.value == null) {
-// Logging.instance.log(
-// "Tried to $runtimeType.updateEstimate for: $exchange where response: $response",
-// level: LogLevel.Info,
-// );
-// return;
-// }
-//
-// final estimate = response.value!;
-//
-// if (reversed) {
-// _sendAmount = estimate.estimatedAmount;
-// } else {
-// _receiveAmount = estimate.estimatedAmount;
-// }
-//
-// _rate =
-// (receiveAmount! / sendAmount!).toDecimal(scaleOnInfinitePrecision: 12);
-//
-// //todo: check if print needed
-// // debugPrint(
-// // "updated estimate for: $exchange for $fromTicker-$toTicker: $estimate");
-//
-// if (shouldNotifyListeners) {
-// notifyListeners();
-// }
-// }
-//
-//
-// }
diff --git a/lib/services/exchange/change_now/change_now_api.dart b/lib/services/exchange/change_now/change_now_api.dart
index 57823a813..6f050d2e2 100644
--- a/lib/services/exchange/change_now/change_now_api.dart
+++ b/lib/services/exchange/change_now/change_now_api.dart
@@ -483,6 +483,7 @@ class ChangeNowAPI {
reversed: false,
rateId: value.rateId,
warningMessage: value.warningMessage,
+ exchangeProvider: ChangeNowExchange.exchangeName,
),
);
} catch (_) {
@@ -566,6 +567,7 @@ class ChangeNowAPI {
reversed: reversed,
rateId: value.rateId,
warningMessage: value.warningMessage,
+ exchangeProvider: ChangeNowExchange.exchangeName,
),
);
} catch (_) {
diff --git a/lib/services/exchange/change_now/change_now_exchange.dart b/lib/services/exchange/change_now/change_now_exchange.dart
index 3189ff84e..a6037b511 100644
--- a/lib/services/exchange/change_now/change_now_exchange.dart
+++ b/lib/services/exchange/change_now/change_now_exchange.dart
@@ -31,7 +31,7 @@ class ChangeNowExchange extends Exchange {
String? extraId,
required String addressRefund,
required String refundExtraId,
- String? rateId,
+ Estimate? estimate,
required bool reversed,
}) async {
late final ExchangeResponse response;
@@ -41,7 +41,7 @@ class ChangeNowExchange extends Exchange {
toTicker: to,
receivingAddress: addressTo,
amount: amount,
- rateId: rateId!,
+ rateId: estimate!.rateId!,
extraId: extraId ?? "",
refundAddress: addressRefund,
refundExtraId: refundExtraId,
@@ -128,7 +128,7 @@ class ChangeNowExchange extends Exchange {
}
@override
- Future> getEstimate(
+ Future>> getEstimates(
String from,
String to,
Decimal amount,
@@ -151,7 +151,10 @@ class ChangeNowExchange extends Exchange {
fromAmount: amount,
);
}
- return response;
+ return ExchangeResponse(
+ value: response.value == null ? null : [response.value!],
+ exception: response.exception,
+ );
}
@override
diff --git a/lib/services/exchange/exchange.dart b/lib/services/exchange/exchange.dart
index e4f5ce8d5..1db451457 100644
--- a/lib/services/exchange/exchange.dart
+++ b/lib/services/exchange/exchange.dart
@@ -8,6 +8,7 @@ import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dar
import 'package:stackwallet/services/exchange/exchange_response.dart';
import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart';
import 'package:stackwallet/services/exchange/simpleswap/simpleswap_exchange.dart';
+import 'package:stackwallet/services/exchange/trocador/trocador_exchange.dart';
abstract class Exchange {
static Exchange get defaultExchange => ChangeNowExchange.instance;
@@ -20,7 +21,14 @@ abstract class Exchange {
return SimpleSwapExchange.instance;
case MajesticBankExchange.exchangeName:
return MajesticBankExchange.instance;
+ case TrocadorExchange.exchangeName:
+ return TrocadorExchange.instance;
default:
+ final split = name.split(" ");
+ if (split.length >= 2) {
+ // silly way to check for 'Trocador ($providerName)'
+ return fromName(split.first);
+ }
throw ArgumentError("Unknown exchange name");
}
}
@@ -52,7 +60,7 @@ abstract class Exchange {
bool fixedRate,
);
- Future> getEstimate(
+ Future>> getEstimates(
String from,
String to,
Decimal amount,
@@ -69,7 +77,7 @@ abstract class Exchange {
String? extraId,
required String addressRefund,
required String refundExtraId,
- String? rateId,
+ Estimate? estimate,
required bool reversed,
});
}
diff --git a/lib/services/exchange/exchange_data_loading_service.dart b/lib/services/exchange/exchange_data_loading_service.dart
index 2da6016f4..c0aa2e2b0 100644
--- a/lib/services/exchange/exchange_data_loading_service.dart
+++ b/lib/services/exchange/exchange_data_loading_service.dart
@@ -1,12 +1,13 @@
import 'package:flutter/foundation.dart';
import 'package:isar/isar.dart';
import 'package:stackwallet/db/hive/db.dart';
+import 'package:stackwallet/models/exchange/active_pair.dart';
import 'package:stackwallet/models/exchange/aggregate_currency.dart';
-import 'package:stackwallet/models/exchange/exchange_form_state.dart';
import 'package:stackwallet/models/isar/exchange_cache/currency.dart';
import 'package:stackwallet/models/isar/exchange_cache/pair.dart';
import 'package:stackwallet/services/exchange/change_now/change_now_exchange.dart';
import 'package:stackwallet/services/exchange/majestic_bank/majestic_bank_exchange.dart';
+import 'package:stackwallet/services/exchange/trocador/trocador_exchange.dart';
import 'package:stackwallet/utilities/enums/exchange_rate_type_enum.dart';
import 'package:stackwallet/utilities/logger.dart';
import 'package:stackwallet/utilities/stack_file_system.dart';
@@ -56,20 +57,29 @@ class ExchangeDataLoadingService {
);
}
- Future setCurrenciesIfEmpty(ExchangeFormState state) async {
- if (state.sendCurrency == null && state.receiveCurrency == null) {
+ Future setCurrenciesIfEmpty(
+ ActivePair? pair,
+ ExchangeRateType rateType,
+ ) async {
+ if (pair?.send == null && pair?.receive == null) {
if (await isar.currencies.count() > 0) {
- final sendCurrency = await getAggregateCurrency(
- "BTC",
- state.exchangeRateType,
- null,
+ pair?.setSend(
+ await getAggregateCurrency(
+ "BTC",
+ rateType,
+ null,
+ ),
+ notifyListeners: false,
);
- final receiveCurrency = await getAggregateCurrency(
- "XMR",
- state.exchangeRateType,
- null,
+
+ pair?.setReceive(
+ await getAggregateCurrency(
+ "XMR",
+ rateType,
+ null,
+ ),
+ notifyListeners: false,
);
- state.setCurrencies(sendCurrency, receiveCurrency);
}
}
}
@@ -128,6 +138,7 @@ class ExchangeDataLoadingService {
// loadSimpleswapFixedRateCurrencies(ref),
// loadSimpleswapFloatingRateCurrencies(ref),
loadMajesticBankCurrencies(),
+ loadTrocadorCurrencies(),
]);
// quicker to load available currencies on the fly for a specific base currency
@@ -302,6 +313,28 @@ class ExchangeDataLoadingService {
}
}
+ Future loadTrocadorCurrencies() async {
+ final exchange = TrocadorExchange.instance;
+ final responseCurrencies = await exchange.getAllCurrencies(false);
+
+ if (responseCurrencies.value != null) {
+ await isar.writeTxn(() async {
+ final idsToDelete = await isar.currencies
+ .where()
+ .exchangeNameEqualTo(TrocadorExchange.exchangeName)
+ .idProperty()
+ .findAll();
+ await isar.currencies.deleteAll(idsToDelete);
+ await isar.currencies.putAll(responseCurrencies.value!);
+ });
+ } else {
+ Logging.instance.log(
+ "loadTrocadorCurrencies: $responseCurrencies",
+ level: LogLevel.Warning,
+ );
+ }
+ }
+
// Future loadMajesticBankPairs() async {
// final exchange = MajesticBankExchange.instance;
//
diff --git a/lib/services/exchange/exchange_service.dart b/lib/services/exchange/exchange_service.dart
deleted file mode 100644
index 036c522de..000000000
--- a/lib/services/exchange/exchange_service.dart
+++ /dev/null
@@ -1 +0,0 @@
-class ExchangeService {}
diff --git a/lib/services/exchange/majestic_bank/majestic_bank_exchange.dart b/lib/services/exchange/majestic_bank/majestic_bank_exchange.dart
index dcc63c68b..95031490c 100644
--- a/lib/services/exchange/majestic_bank/majestic_bank_exchange.dart
+++ b/lib/services/exchange/majestic_bank/majestic_bank_exchange.dart
@@ -44,7 +44,7 @@ class MajesticBankExchange extends Exchange {
String? extraId,
required String addressRefund,
required String refundExtraId,
- String? rateId,
+ Estimate? estimate,
required bool reversed,
}) async {
ExchangeResponse? response;
@@ -170,7 +170,7 @@ class MajesticBankExchange extends Exchange {
}
@override
- Future> getEstimate(
+ Future>> getEstimates(
String from,
String to,
Decimal amount,
@@ -192,8 +192,9 @@ class MajesticBankExchange extends Exchange {
estimatedAmount: reversed ? calc.fromAmount : calc.receiveAmount,
fixedRate: fixedRate,
reversed: reversed,
+ exchangeProvider: MajesticBankExchange.exchangeName,
);
- return ExchangeResponse(value: estimate);
+ return ExchangeResponse(value: [estimate]);
}
@override
diff --git a/lib/services/exchange/simpleswap/simpleswap_exchange.dart b/lib/services/exchange/simpleswap/simpleswap_exchange.dart
index 1157bd09e..0bfe93a38 100644
--- a/lib/services/exchange/simpleswap/simpleswap_exchange.dart
+++ b/lib/services/exchange/simpleswap/simpleswap_exchange.dart
@@ -30,7 +30,7 @@ class SimpleSwapExchange extends Exchange {
String? extraId,
required String addressRefund,
required String refundExtraId,
- String? rateId,
+ Estimate? estimate,
required bool reversed,
}) async {
return await SimpleSwapAPI.instance.createNewExchange(
@@ -89,7 +89,7 @@ class SimpleSwapExchange extends Exchange {
}
@override
- Future> getEstimate(
+ Future>> getEstimates(
String from,
String to,
Decimal amount,
@@ -109,11 +109,14 @@ class SimpleSwapExchange extends Exchange {
}
return ExchangeResponse(
- value: Estimate(
- estimatedAmount: Decimal.parse(response.value!),
- fixedRate: fixedRate,
- reversed: reversed,
- ),
+ value: [
+ Estimate(
+ estimatedAmount: Decimal.parse(response.value!),
+ fixedRate: fixedRate,
+ reversed: reversed,
+ exchangeProvider: SimpleSwapExchange.exchangeName,
+ ),
+ ],
);
}
diff --git a/lib/services/exchange/trocador/response_objects/trocador_coin.dart b/lib/services/exchange/trocador/response_objects/trocador_coin.dart
new file mode 100644
index 000000000..aea01d2f1
--- /dev/null
+++ b/lib/services/exchange/trocador/response_objects/trocador_coin.dart
@@ -0,0 +1,44 @@
+import 'package:decimal/decimal.dart';
+
+class TrocadorCoin {
+ final String name;
+ final String ticker;
+ final String network;
+ final bool memo;
+ final String image;
+ final Decimal minimum;
+ final Decimal maximum;
+
+ TrocadorCoin({
+ required this.name,
+ required this.ticker,
+ required this.network,
+ required this.memo,
+ required this.image,
+ required this.minimum,
+ required this.maximum,
+ });
+
+ factory TrocadorCoin.fromMap(Map json) => TrocadorCoin(
+ name: json['name'] as String,
+ ticker: json['ticker'] as String,
+ network: json['network'] as String,
+ memo: json['memo'] as bool,
+ image: json['image'] as String,
+ minimum: Decimal.parse(json['minimum'].toString()),
+ maximum: Decimal.parse(json['maximum'].toString()),
+ );
+
+ @override
+ String toString() {
+ return 'TrocadorCoin( '
+ 'name: $name, '
+ 'ticker: $ticker, '
+ 'network: $network, '
+ 'memo: $memo, '
+ 'image: $image, '
+ 'minimum: $minimum, '
+ 'maximum: $maximum '
+ ')';
+ }
+}
diff --git a/lib/services/exchange/trocador/response_objects/trocador_quote.dart b/lib/services/exchange/trocador/response_objects/trocador_quote.dart
new file mode 100644
index 000000000..ada8725f5
--- /dev/null
+++ b/lib/services/exchange/trocador/response_objects/trocador_quote.dart
@@ -0,0 +1,47 @@
+import 'package:decimal/decimal.dart';
+
+class TrocadorQuote {
+ final String provider;
+ final String kycRating;
+ final int insurance;
+ final bool fixed;
+ final Decimal? amountTo;
+ final Decimal? amountFrom;
+ final Decimal waste;
+
+ TrocadorQuote({
+ required this.provider,
+ required this.kycRating,
+ required this.insurance,
+ required this.fixed,
+ required this.amountTo,
+ required this.amountFrom,
+ required this.waste,
+ });
+
+ factory TrocadorQuote.fromMap(Map map) {
+ return TrocadorQuote(
+ provider: map['provider'] as String,
+ kycRating: map['kycrating'] as String,
+ insurance: map['insurance'] as int,
+ // wtf trocador?
+ fixed: map['fixed'] == "True",
+ amountTo: Decimal.tryParse(map['amount_to'].toString()),
+ amountFrom: Decimal.tryParse(map['amount_from'].toString()),
+ waste: Decimal.parse(map['waste'].toString()),
+ );
+ }
+
+ @override
+ String toString() {
+ return 'TrocadorQuote( '
+ 'provider: $provider, '
+ 'kycRating: $kycRating, '
+ 'insurance: $insurance, '
+ 'fixed: $fixed, '
+ 'amountTo: $amountTo, '
+ 'amountFrom: $amountFrom, '
+ 'waste: $waste '
+ ')';
+ }
+}
diff --git a/lib/services/exchange/trocador/response_objects/trocador_rate.dart b/lib/services/exchange/trocador/response_objects/trocador_rate.dart
new file mode 100644
index 000000000..5c3d18da2
--- /dev/null
+++ b/lib/services/exchange/trocador/response_objects/trocador_rate.dart
@@ -0,0 +1,84 @@
+import 'package:decimal/decimal.dart';
+import 'package:stackwallet/services/exchange/trocador/response_objects/trocador_quote.dart';
+
+class TrocadorRate {
+ final String tradeId;
+ final DateTime date;
+ final String tickerFrom;
+ final String tickerTo;
+ final String coinFrom;
+ final String coinTo;
+ final String networkFrom;
+ final String networkTo;
+ final Decimal amountFrom;
+ final Decimal amountTo;
+ final String provider;
+ final bool fixed;
+ final bool payment;
+ final String status;
+ final List quotes;
+
+ TrocadorRate({
+ required this.tradeId,
+ required this.date,
+ required this.tickerFrom,
+ required this.tickerTo,
+ required this.coinFrom,
+ required this.coinTo,
+ required this.networkFrom,
+ required this.networkTo,
+ required this.amountFrom,
+ required this.amountTo,
+ required this.provider,
+ required this.fixed,
+ required this.payment,
+ required this.status,
+ required this.quotes,
+ });
+
+ factory TrocadorRate.fromMap(Map map) {
+ final list =
+ List