mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-11-17 01:37:54 +00:00
WIP exchange screen state refactor
This commit is contained in:
parent
3564426248
commit
3a97623e5b
19 changed files with 1169 additions and 942 deletions
|
@ -299,7 +299,8 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
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());
|
||||
}
|
||||
|
|
35
lib/models/exchange/active_pair.dart
Normal file
35
lib/models/exchange/active_pair.dart
Normal file
|
@ -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 }";
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -9,6 +9,7 @@ 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/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,10 +22,13 @@ 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';
|
||||
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';
|
||||
|
@ -61,6 +65,12 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
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;
|
||||
|
@ -105,16 +115,17 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
}
|
||||
|
||||
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 +137,10 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
_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 +159,7 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
}
|
||||
|
||||
Future<AggregateCurrency> _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 +190,8 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
}
|
||||
|
||||
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 +206,26 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
}
|
||||
|
||||
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 +233,20 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
}
|
||||
|
||||
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 +256,25 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
_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,89 +361,20 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
}
|
||||
}
|
||||
|
||||
void onRateTypeChanged(ExchangeRateType newType) async {
|
||||
void onRateTypeChanged(ExchangeRateType newType) {
|
||||
_receiveFocusNode.unfocus();
|
||||
_sendFocusNode.unfocus();
|
||||
|
||||
await showUpdatingExchangeRate(
|
||||
whileFuture: _onRateTypeChangedFuture(newType),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _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).estimates.firstWhere(
|
||||
(e) =>
|
||||
e.exchangeProvider ==
|
||||
ref.read(exchangeFormStateProvider).providerName,
|
||||
);
|
||||
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<void>(
|
||||
|
@ -430,10 +391,16 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
|
||||
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;
|
||||
|
@ -545,7 +512,9 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -553,10 +522,8 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
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,
|
||||
estimate: estimate,
|
||||
reversed: estimate.reversed,
|
||||
|
@ -626,8 +593,8 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
}
|
||||
|
||||
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;
|
||||
|
@ -636,6 +603,85 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
return coin.ticker.toUpperCase() == ticker.toUpperCase();
|
||||
}
|
||||
|
||||
Future<void> update() async {
|
||||
ref.read(efRefreshingProvider.notifier).state = true;
|
||||
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);
|
||||
|
||||
if (amount == null || amount <= Decimal.zero) {
|
||||
ref.read(efRefreshingProvider.notifier).state = false;
|
||||
return;
|
||||
}
|
||||
|
||||
final rateType = ref.read(efRateTypeProvider);
|
||||
final pair = ref.read(efCurrencyPairProvider);
|
||||
|
||||
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,
|
||||
);
|
||||
|
||||
if (rangeResponse.value == null) {
|
||||
Logging.instance.log(
|
||||
"Tried to $runtimeType.update Range for:"
|
||||
" $exchange where response: $rangeResponse",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
}
|
||||
|
||||
final estimateResponse = await exchange.getEstimates(
|
||||
sendCurrency.ticker,
|
||||
receiveCurrency.ticker,
|
||||
amount,
|
||||
rateType == ExchangeRateType.fixed,
|
||||
reversed,
|
||||
);
|
||||
|
||||
if (estimateResponse.value == null) {
|
||||
Logging.instance.log(
|
||||
"Tried to $runtimeType._fetchEstimateAndRange Estimate for:"
|
||||
" $exchange where response: $estimateResponse",
|
||||
level: LogLevel.Info,
|
||||
);
|
||||
}
|
||||
|
||||
if (estimateResponse.value != null && rangeResponse.value != null) {
|
||||
ref.read(efEstimatesListProvider(exchange.name).notifier).state =
|
||||
Tuple2(estimateResponse.value!, rangeResponse.value!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
ref.read(efRefreshingProvider.notifier).state = false;
|
||||
});
|
||||
}
|
||||
|
||||
void updateSend(Estimate? estimate) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
ref.read(efSendAmountProvider.notifier).state = estimate?.estimatedAmount;
|
||||
});
|
||||
}
|
||||
|
||||
void updateReceive(Estimate? estimate) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
ref.read(efReceiveAmountProvider.notifier).state =
|
||||
estimate?.estimatedAmount;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_sendController = TextEditingController();
|
||||
|
@ -645,9 +691,32 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
coin = widget.coin;
|
||||
walletInitiated = walletId != null && coin != null;
|
||||
|
||||
_sendFocusNode.addListener(() {
|
||||
if (_sendFocusNode.hasFocus) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
ref.read(efReversedProvider.notifier).state = false;
|
||||
});
|
||||
}
|
||||
});
|
||||
_receiveFocusNode.addListener(() {
|
||||
if (_receiveFocusNode.hasFocus) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
ref.read(efReversedProvider.notifier).state = true;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
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(efWarningProvider.notifier).state = "";
|
||||
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,
|
||||
|
@ -656,17 +725,17 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
)
|
||||
.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);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -684,37 +753,42 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
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) {
|
||||
if (ref.read(efReversedProvider)) {
|
||||
updateSend((next as StateController<Estimate?>).state);
|
||||
} else {
|
||||
updateReceive((next as StateController<Estimate?>).state);
|
||||
}
|
||||
});
|
||||
|
||||
ref.listen(efCurrencyPairProvider, (previous, next) {
|
||||
update();
|
||||
});
|
||||
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
|
@ -729,8 +803,9 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
height: isDesktop ? 10 : 4,
|
||||
),
|
||||
ExchangeTextField(
|
||||
key: Key(
|
||||
"exchangeTextFieldKeyFor_${Theme.of(context).extension<StackColors>()!.themeType.name}"),
|
||||
key: Key("exchangeTextFieldKeyFor_"
|
||||
"${Theme.of(context).extension<StackColors>()!.themeType.name}"
|
||||
"${ref.watch(efCurrencyPairProvider.select((value) => value.send?.ticker))}"),
|
||||
controller: _sendController,
|
||||
focusNode: _sendFocusNode,
|
||||
textStyle: STextStyles.smallMed14(context).copyWith(
|
||||
|
@ -749,8 +824,8 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
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,
|
||||
|
@ -758,15 +833,10 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
SizedBox(
|
||||
height: isDesktop ? 10 : 4,
|
||||
),
|
||||
if (ref
|
||||
.watch(
|
||||
exchangeFormStateProvider.select((value) => value.warning))
|
||||
.isNotEmpty &&
|
||||
!ref.watch(
|
||||
exchangeFormStateProvider.select((value) => value.reversed)))
|
||||
if (ref.watch(efWarningProvider).isNotEmpty &&
|
||||
!ref.watch(efReversedProvider))
|
||||
Text(
|
||||
ref.watch(
|
||||
exchangeFormStateProvider.select((value) => value.warning)),
|
||||
ref.watch(efWarningProvider),
|
||||
style: STextStyles.errorSmall(context),
|
||||
),
|
||||
Row(
|
||||
|
@ -830,8 +900,7 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
background:
|
||||
Theme.of(context).extension<StackColors>()!.textFieldDefaultBG,
|
||||
onTap: () {
|
||||
if (!(ref.read(exchangeFormStateProvider).exchangeRateType ==
|
||||
ExchangeRateType.estimated) &&
|
||||
if (!(ref.read(efRateTypeProvider) == ExchangeRateType.estimated) &&
|
||||
_receiveController.text == "-") {
|
||||
_receiveController.text = "";
|
||||
}
|
||||
|
@ -839,22 +908,16 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
onChanged: receiveFieldOnChanged,
|
||||
onButtonTap: selectReceiveCurrency,
|
||||
isWalletCoin: isWalletCoin(coin, true),
|
||||
currency: ref.watch(exchangeFormStateProvider
|
||||
.select((value) => value.receiveCurrency)),
|
||||
currency: ref
|
||||
.watch(efCurrencyPairProvider.select((value) => value.receive)),
|
||||
readOnly: (rateType) == ExchangeRateType.estimated &&
|
||||
ref.watch(exchangeFormStateProvider
|
||||
.select((value) => value.exchange.name)) ==
|
||||
ref.watch(efExchangeProvider).name ==
|
||||
ChangeNowExchange.exchangeName,
|
||||
),
|
||||
if (ref
|
||||
.watch(
|
||||
exchangeFormStateProvider.select((value) => value.warning))
|
||||
.isNotEmpty &&
|
||||
ref.watch(
|
||||
exchangeFormStateProvider.select((value) => value.reversed)))
|
||||
if (ref.watch(efWarningProvider).isNotEmpty &&
|
||||
ref.watch(efReversedProvider))
|
||||
Text(
|
||||
ref.watch(
|
||||
exchangeFormStateProvider.select((value) => value.warning)),
|
||||
ref.watch(efWarningProvider),
|
||||
style: STextStyles.errorSmall(context),
|
||||
),
|
||||
SizedBox(
|
||||
|
@ -867,27 +930,28 @@ class _ExchangeFormState extends ConsumerState<ExchangeForm> {
|
|||
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(
|
||||
// AnimatedSize(
|
||||
// duration: const Duration(milliseconds: 250),
|
||||
// curve: Curves.easeInOutCirc,
|
||||
// child: ref.watch(efSendAmountProvider).sendAmount != null &&
|
||||
// ref.watch(exchangeFormStateProvider).sendAmount != Decimal.zero
|
||||
// ?
|
||||
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),
|
||||
),
|
||||
// : const SizedBox(
|
||||
// height: 0,
|
||||
// ),
|
||||
),
|
||||
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",
|
||||
)
|
||||
|
|
|
@ -124,9 +124,8 @@ class _Step2ViewState extends ConsumerState<Step2View> {
|
|||
|
||||
@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(
|
||||
|
|
|
@ -52,9 +52,8 @@ class _Step3ViewState extends ConsumerState<Step3View> {
|
|||
|
||||
@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<Step3View> {
|
|||
|
||||
final ExchangeResponse<Trade> response =
|
||||
await ref
|
||||
.read(exchangeFormStateProvider)
|
||||
.exchange
|
||||
.read(efExchangeProvider)
|
||||
.createTrade(
|
||||
from: model.sendTicker,
|
||||
to: model.receiveTicker,
|
||||
|
|
|
@ -70,10 +70,8 @@ class _Step4ViewState extends ConsumerState<Step4View> {
|
|||
}
|
||||
|
||||
Future<void> _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;
|
||||
|
|
|
@ -37,7 +37,8 @@ class _ExchangeViewState extends ConsumerState<ExchangeView> {
|
|||
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<ExchangeView> {
|
|||
ExchangeDataLoadingService.instance.onLoadingComplete = () {
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||
await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty(
|
||||
ref.read(exchangeFormStateProvider),
|
||||
ref.read(efCurrencyPairProvider),
|
||||
ref.read(efRateTypeProvider),
|
||||
);
|
||||
setState(() {
|
||||
_initialCachePopulationUnderway = false;
|
||||
|
|
|
@ -2,12 +2,10 @@ 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/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/services/exchange/exchange_response.dart';
|
||||
import 'package:stackwallet/utilities/amount/amount.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
|
@ -42,138 +40,121 @@ class _ExchangeMultiProviderOptionState extends ConsumerState<ExchangeOption> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final sendCurrency = ref
|
||||
.watch(exchangeFormStateProvider.select((value) => value.sendCurrency));
|
||||
final receivingCurrency = ref.watch(
|
||||
exchangeFormStateProvider.select((value) => value.receiveCurrency));
|
||||
final fromAmount = ref
|
||||
.watch(exchangeFormStateProvider.select((value) => value.sendAmount));
|
||||
final toAmount = ref.watch(
|
||||
exchangeFormStateProvider.select((value) => value.receiveAmount));
|
||||
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 estimates = ref.watch(efEstimatesListProvider(widget.exchange.name));
|
||||
|
||||
return AnimatedSize(
|
||||
duration: const Duration(milliseconds: 500),
|
||||
curve: Curves.easeInOutCubicEmphasized,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (sendCurrency != null &&
|
||||
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 &&
|
||||
toAmount != null &&
|
||||
toAmount > Decimal.zero &&
|
||||
fromAmount != null &&
|
||||
fromAmount > Decimal.zero)
|
||||
FutureBuilder(
|
||||
future: widget.exchange.getEstimates(
|
||||
sendCurrency.ticker,
|
||||
receivingCurrency.ticker,
|
||||
widget.reversed ? toAmount : fromAmount,
|
||||
widget.fixedRate,
|
||||
widget.reversed,
|
||||
),
|
||||
builder: (context,
|
||||
AsyncSnapshot<ExchangeResponse<List<Estimate>>> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done &&
|
||||
snapshot.hasData) {
|
||||
final estimates = snapshot.data?.value;
|
||||
amount != null &&
|
||||
amount > Decimal.zero) {
|
||||
if (estimates != null && estimates.item1.isNotEmpty) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
for (int i = 0; i < estimates.item1.length; i++)
|
||||
Builder(
|
||||
builder: (context) {
|
||||
final e = estimates.item1[i];
|
||||
|
||||
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 = (toAmount / e.estimatedAmount)
|
||||
.toDecimal(scaleOnInfinitePrecision: 18)
|
||||
.toAmount(fractionDigits: decimals);
|
||||
} else {
|
||||
rate = (e.estimatedAmount / fromAmount)
|
||||
.toDecimal(scaleOnInfinitePrecision: 18)
|
||||
.toAmount(fractionDigits: decimals);
|
||||
}
|
||||
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<StackColors>()!
|
||||
.background,
|
||||
)
|
||||
: const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
child,
|
||||
],
|
||||
),
|
||||
child: _ProviderOption(
|
||||
key: Key(widget.exchange.name +
|
||||
e.exchangeProvider),
|
||||
exchange: widget.exchange,
|
||||
providerName: e.exchangeProvider,
|
||||
rateString: rateString,
|
||||
kycRating: e.kycRating,
|
||||
),
|
||||
);
|
||||
},
|
||||
final rateString =
|
||||
"1 ${sendCurrency.ticker.toUpperCase()} ~ ${rate.localizedStringAsFixed(
|
||||
locale: ref.watch(
|
||||
localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale),
|
||||
),
|
||||
],
|
||||
);
|
||||
} else if (snapshot.data?.exception
|
||||
is PairUnavailableException) {
|
||||
return _ProviderOption(
|
||||
exchange: widget.exchange,
|
||||
providerName: widget.exchange.name,
|
||||
rateString: "Unsupported pair",
|
||||
);
|
||||
} else {
|
||||
Logging.instance.log(
|
||||
"$runtimeType failed to fetch rate for ${widget.exchange.name}: ${snapshot.data}",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
)} ${receivingCurrency.ticker.toUpperCase()}";
|
||||
|
||||
return _ProviderOption(
|
||||
exchange: widget.exchange,
|
||||
providerName: widget.exchange.name,
|
||||
rateString: "Failed to fetch rate",
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// show loading
|
||||
return _ProviderOption(
|
||||
exchange: widget.exchange,
|
||||
providerName: widget.exchange.name,
|
||||
rateString: "",
|
||||
loadingString: true,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
return ConditionalParent(
|
||||
condition: i > 0,
|
||||
builder: (child) => Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
isDesktop
|
||||
? Container(
|
||||
height: 1,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.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 failed to fetch rate for ${widget.exchange.name}: $estimates",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
|
||||
return _ProviderOption(
|
||||
exchange: widget.exchange,
|
||||
estimate: null,
|
||||
rateString: "Failed to fetch rate",
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// show n/a
|
||||
return _ProviderOption(
|
||||
exchange: widget.exchange,
|
||||
estimate: null,
|
||||
rateString: "n/a",
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -183,14 +164,14 @@ class _ProviderOption extends ConsumerStatefulWidget {
|
|||
const _ProviderOption({
|
||||
Key? key,
|
||||
required this.exchange,
|
||||
required this.providerName,
|
||||
required this.estimate,
|
||||
required this.rateString,
|
||||
this.kycRating,
|
||||
this.loadingString = false,
|
||||
}) : super(key: key);
|
||||
|
||||
final Exchange exchange;
|
||||
final String providerName;
|
||||
final Estimate? estimate;
|
||||
final String rateString;
|
||||
final String? kycRating;
|
||||
final bool loadingString;
|
||||
|
@ -206,25 +187,27 @@ class _ProviderOptionState extends ConsumerState<_ProviderOption> {
|
|||
|
||||
@override
|
||||
void initState() {
|
||||
_id = "${widget.exchange.name} (${widget.providerName})";
|
||||
_id =
|
||||
"${widget.exchange.name} (${widget.estimate?.exchangeProvider ?? widget.exchange.name})";
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
bool selected = ref.watch(exchangeFormStateProvider
|
||||
.select((value) => value.combinedExchangeId)) ==
|
||||
_id;
|
||||
String groupValue = ref.watch(
|
||||
exchangeFormStateProvider.select((value) => value.combinedExchangeId));
|
||||
String groupValue = ref.watch(currentCombinedExchangeIdProvider);
|
||||
|
||||
if (ref.watch(
|
||||
exchangeFormStateProvider.select((value) => value.exchange.name)) ==
|
||||
widget.providerName) {
|
||||
selected = true;
|
||||
if (ref.watch(efExchangeProvider).name ==
|
||||
(widget.estimate?.exchangeProvider ?? widget.exchange.name)) {
|
||||
groupValue = _id;
|
||||
}
|
||||
|
||||
bool selected = groupValue == _id;
|
||||
|
||||
print("========================================================");
|
||||
print("gourpValue: $groupValue");
|
||||
print("_id: $_id");
|
||||
print("========================================================");
|
||||
|
||||
return ConditionalParent(
|
||||
condition: isDesktop,
|
||||
builder: (child) => MouseRegion(
|
||||
|
@ -233,15 +216,20 @@ class _ProviderOptionState extends ConsumerState<_ProviderOption> {
|
|||
),
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
if (!selected) {
|
||||
ref.read(exchangeFormStateProvider).updateExchange(
|
||||
exchange: widget.exchange,
|
||||
shouldUpdateData: true,
|
||||
shouldNotifyListeners: true,
|
||||
providerName: widget.providerName,
|
||||
shouldAwait: false,
|
||||
);
|
||||
}
|
||||
ref.read(efExchangeProvider.notifier).state = widget.exchange;
|
||||
ref.read(efExchangeProviderNameProvider.notifier).state =
|
||||
widget.estimate?.exchangeProvider ?? widget.exchange.name;
|
||||
|
||||
// if (!selected) {
|
||||
// ref.read(exchangeFormStateProvider).updateExchange(
|
||||
// exchange: widget.exchange,
|
||||
// shouldUpdateData: false,
|
||||
// shouldNotifyListeners: false,
|
||||
// providerName:
|
||||
// widget.estimate?.exchangeProvider ?? widget.exchange.name,
|
||||
// shouldAwait: false,
|
||||
// );
|
||||
// }
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
|
@ -263,15 +251,26 @@ class _ProviderOptionState extends ConsumerState<_ProviderOption> {
|
|||
value: _id,
|
||||
groupValue: groupValue,
|
||||
onChanged: (_) {
|
||||
if (!selected) {
|
||||
ref.read(exchangeFormStateProvider).updateExchange(
|
||||
exchange: widget.exchange,
|
||||
shouldUpdateData: false,
|
||||
shouldNotifyListeners: true,
|
||||
providerName: widget.providerName,
|
||||
shouldAwait: false,
|
||||
);
|
||||
}
|
||||
ref.read(efExchangeProvider.notifier).state =
|
||||
widget.exchange;
|
||||
ref
|
||||
.read(efExchangeProviderNameProvider.notifier)
|
||||
.state =
|
||||
widget.estimate?.exchangeProvider ??
|
||||
widget.exchange.name;
|
||||
// if (!selected) {
|
||||
//
|
||||
//
|
||||
// ref.read(exchangeFormStateProvider).updateExchange(
|
||||
// exchange: widget.exchange,
|
||||
// shouldUpdateData: false,
|
||||
// shouldNotifyListeners: false,
|
||||
// providerName:
|
||||
// widget.estimate?.exchangeProvider ??
|
||||
// widget.exchange.name,
|
||||
// shouldAwait: false,
|
||||
// );
|
||||
// }
|
||||
},
|
||||
),
|
||||
),
|
||||
|
@ -303,7 +302,8 @@ class _ProviderOptionState extends ConsumerState<_ProviderOption> {
|
|||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
widget.providerName,
|
||||
widget.estimate?.exchangeProvider ??
|
||||
widget.exchange.name,
|
||||
style: STextStyles.titleBold12(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
|
|
|
@ -49,16 +49,10 @@ class _ExchangeProviderOptionsState
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final sendCurrency = ref.watch(
|
||||
exchangeFormStateProvider.select(
|
||||
(value) => value.sendCurrency,
|
||||
),
|
||||
);
|
||||
final receivingCurrency = ref.watch(
|
||||
exchangeFormStateProvider.select(
|
||||
(value) => value.receiveCurrency,
|
||||
),
|
||||
);
|
||||
final sendCurrency =
|
||||
ref.watch(efCurrencyPairProvider.select((value) => value.send));
|
||||
final receivingCurrency =
|
||||
ref.watch(efCurrencyPairProvider.select((value) => value.receive));
|
||||
|
||||
final showChangeNow = exchangeSupported(
|
||||
exchangeName: ChangeNowExchange.exchangeName,
|
||||
|
|
|
@ -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<StackColors>()!
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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<DesktopExchangeView> {
|
|||
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<DesktopExchangeView> {
|
|||
ExchangeDataLoadingService.instance.onLoadingComplete = () {
|
||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||
await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty(
|
||||
ref.read(exchangeFormStateProvider),
|
||||
ref.read(efCurrencyPairProvider),
|
||||
ref.read(efRateTypeProvider),
|
||||
);
|
||||
setState(() {
|
||||
_initialCachePopulationUnderway = false;
|
||||
|
|
|
@ -84,8 +84,7 @@ class _StepScaffoldState extends ConsumerState<StepScaffold> {
|
|||
);
|
||||
|
||||
final ExchangeResponse<Trade> response = await ref
|
||||
.read(exchangeFormStateProvider)
|
||||
.exchange
|
||||
.read(efExchangeProvider)
|
||||
.createTrade(
|
||||
from: ref.read(desktopExchangeModelProvider)!.sendTicker,
|
||||
to: ref.read(desktopExchangeModelProvider)!.receiveTicker,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -36,8 +36,7 @@ class _DesktopStep3State extends ConsumerState<DesktopStep3> {
|
|||
children: [
|
||||
DesktopStepItem(
|
||||
label: "Swap",
|
||||
value: ref.watch(exchangeFormStateProvider
|
||||
.select((value) => value.exchange.name)),
|
||||
value: ref.watch(efExchangeProviderNameProvider),
|
||||
),
|
||||
Container(
|
||||
height: 1,
|
||||
|
|
|
@ -46,7 +46,7 @@ class _DesktopStep4State extends ConsumerState<DesktopStep4> {
|
|||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -1,5 +1,116 @@
|
|||
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/utilities/enums/exchange_rate_type_enum.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
final exchangeFormStateProvider =
|
||||
ChangeNotifierProvider<ExchangeFormState>((ref) => ExchangeFormState());
|
||||
final efEstimatesListProvider =
|
||||
StateProvider.family<Tuple2<List<Estimate>, Range>?, String>(
|
||||
(ref, exchangeName) => null);
|
||||
|
||||
final efRateTypeProvider =
|
||||
StateProvider<ExchangeRateType>((ref) => ExchangeRateType.estimated);
|
||||
|
||||
final efExchangeProvider =
|
||||
StateProvider<Exchange>((ref) => Exchange.defaultExchange);
|
||||
final efExchangeProviderNameProvider =
|
||||
StateProvider<String>((ref) => Exchange.defaultExchange.name);
|
||||
|
||||
final currentCombinedExchangeIdProvider = Provider<String>((ref) {
|
||||
return "${ref.watch(efExchangeProvider).name}"
|
||||
" (${ref.watch(efExchangeProviderNameProvider)})";
|
||||
});
|
||||
|
||||
final efSendAmountProvider = StateProvider<Decimal?>((ref) => null);
|
||||
final efReceiveAmountProvider = StateProvider<Decimal?>((ref) => null);
|
||||
|
||||
final efSendAmountStringProvider = StateProvider<String>((ref) {
|
||||
return ref.watch(efSendAmountProvider)?.toStringAsFixed(8) ?? "";
|
||||
});
|
||||
final efReceiveAmountStringProvider = StateProvider<String>((ref) {
|
||||
return ref.watch(efReceiveAmountProvider)?.toStringAsFixed(8) ?? "";
|
||||
});
|
||||
|
||||
final efReversedProvider = StateProvider<bool>((ref) => false);
|
||||
|
||||
final efCurrencyPairProvider = ChangeNotifierProvider<ActivePair>(
|
||||
(ref) => ActivePair(),
|
||||
);
|
||||
|
||||
final efRangeProvider = StateProvider<Range?>((ref) {
|
||||
final exchange = ref.watch(efExchangeProvider);
|
||||
return ref.watch(efEstimatesListProvider(exchange.name))?.item2;
|
||||
});
|
||||
|
||||
final efEstimateProvider = StateProvider<Estimate?>((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.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<bool>((ref) {
|
||||
final Estimate? estimate = ref.watch(efEstimateProvider);
|
||||
// final Decimal? amount = ref.watch(efReversedProvider)
|
||||
// ? ref.watch(efSendAmountProvider)
|
||||
// : ref.watch(efReceiveAmountProvider);
|
||||
|
||||
return estimate != null;
|
||||
});
|
||||
|
||||
final efRefreshingProvider = StateProvider<bool>((ref) => false);
|
||||
|
||||
final efWarningProvider = StateProvider((ref) {
|
||||
// if (ref.watch(efReversedProvider)) {
|
||||
// final _receiveCurrency =
|
||||
// ref.watch(efCurrencyPairProvider.select((value) => value.receive));
|
||||
// final _receiveAmount = ref.watch(efReceiveAmountProvider);
|
||||
// if (_receiveCurrency != null && _receiveAmount != null) {
|
||||
// final range = ref.watch(efRangeProvider);
|
||||
// if (range?.min != null &&
|
||||
// _receiveAmount < range!.min! &&
|
||||
// _receiveAmount > Decimal.zero) {
|
||||
// return "Min receive amount ${range.min!.toString()} ${_receiveCurrency.ticker.toUpperCase()}";
|
||||
// } else if (range?.max != null &&
|
||||
// _receiveAmount > ref.watch(efRangeProvider)!.max!) {
|
||||
// return "Max receive amount $range!.max!.toString()} ${_receiveCurrency.ticker.toUpperCase()}";
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// final _sendCurrency =
|
||||
// ref.watch(efCurrencyPairProvider.select((value) => value.send));
|
||||
// final _sendAmount = ref.watch(efSendAmountProvider);
|
||||
// if (_sendCurrency != null && _sendAmount != null) {
|
||||
// final range = ref.watch(efRangeProvider);
|
||||
// if (range?.min != null &&
|
||||
// _sendAmount < range!.min! &&
|
||||
// _sendAmount > Decimal.zero) {
|
||||
// return "Min send amount ${range.min!.toString()} ${_sendCurrency.ticker.toUpperCase()}";
|
||||
// } else if (range?.max != null && _sendAmount > range!.max!) {
|
||||
// return "Max send amount ${range.max!.toString()} ${_sendCurrency.ticker.toUpperCase()}";
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
return "";
|
||||
});
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
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';
|
||||
|
@ -57,20 +57,29 @@ class ExchangeDataLoadingService {
|
|||
);
|
||||
}
|
||||
|
||||
Future<void> setCurrenciesIfEmpty(ExchangeFormState state) async {
|
||||
if (state.sendCurrency == null && state.receiveCurrency == null) {
|
||||
Future<void> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue