ui: show EUR offers for SEPA currencies on onramping screen

This commit is contained in:
Czarek Nakamoto 2025-04-09 13:54:39 +02:00
parent 494207290e
commit a8ff1e8a88

View file

@ -149,13 +149,12 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
@computed @computed
bool get isReadyToTrade { bool get isReadyToTrade {
final hasSelectedQuote = selectedQuote != null; // final hasSelectedQuote = selectedQuote != null;
final hasSelectedPaymentMethod = selectedPaymentMethod != null; final hasSelectedPaymentMethod = selectedPaymentMethod != null;
final isPaymentMethodLoaded = paymentMethodState is PaymentMethodLoaded; final isPaymentMethodLoaded = paymentMethodState is PaymentMethodLoaded;
final isBuySellQuotLoaded = buySellQuotState is BuySellQuotLoaded; final isBuySellQuotLoaded = buySellQuotState is BuySellQuotLoaded;
return hasSelectedQuote && return hasSelectedPaymentMethod &&
hasSelectedPaymentMethod &&
isPaymentMethodLoaded && isPaymentMethodLoaded &&
isBuySellQuotLoaded; isBuySellQuotLoaded;
} }
@ -220,7 +219,9 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
.toString() .toString()
.replaceAll(RegExp('\\,'), ''); .replaceAll(RegExp('\\,'), '');
} else { } else {
await calculateBestRate(); if (bestRateQuote != null || fiatCurrency == bestRateQuote?.fiatCurrency) {
await calculateBestRate();
}
} }
} }
@ -250,7 +251,9 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
.toString() .toString()
.replaceAll(RegExp('\\,'), ''); .replaceAll(RegExp('\\,'), '');
} else { } else {
await calculateBestRate(); if (bestRateQuote != null || fiatCurrency == bestRateQuote?.fiatCurrency) {
await calculateBestRate();
}
} }
} }
@ -308,7 +311,7 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
}).toList(); }).toList();
final updatedQuoteOptions = List<SelectableItem>.from([ final updatedQuoteOptions = List<SelectableItem>.from([
OptionTitle(title: 'Recommended'), if (sortedRecommendedQuotes.isNotEmpty) OptionTitle(title: 'Recommended'),
...sortedRecommendedQuotes, ...sortedRecommendedQuotes,
if (sortedQuotes.isNotEmpty) OptionTitle(title: 'All Providers'), if (sortedQuotes.isNotEmpty) OptionTitle(title: 'All Providers'),
...sortedQuotes, ...sortedQuotes,
@ -352,13 +355,20 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
Future<void> _getAvailablePaymentTypes() async { Future<void> _getAvailablePaymentTypes() async {
paymentMethodState = PaymentMethodLoading(); paymentMethodState = PaymentMethodLoading();
selectedPaymentMethod = null; selectedPaymentMethod = null;
final result = await Future.wait(providerList.map((element) => element final resultNative = await Future.wait(providerList.map((element) => element
.getAvailablePaymentTypes(fiatCurrency.title, cryptoCurrency, isBuyAction) .getAvailablePaymentTypes(fiatCurrency.title, cryptoCurrency, isBuyAction)
.timeout( .timeout(
Duration(seconds: 10), Duration(seconds: 10),
onTimeout: () => [], onTimeout: () => [],
))); )));
final resultSepa = await Future.wait(providerList.map((element) => element
.getAvailablePaymentTypes(FiatCurrency.eur.title, cryptoCurrency, isBuyAction)
.timeout(
Duration(seconds: 10),
onTimeout: () => [],
)));
final result = [...resultNative, ...resultSepa];
final Map<PaymentType, PaymentMethod> uniquePaymentMethods = {}; final Map<PaymentType, PaymentMethod> uniquePaymentMethods = {};
for (var methods in result) { for (var methods in result) {
for (var method in methods) { for (var method in methods) {
@ -376,12 +386,26 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
paymentMethodState = PaymentMethodFailed(); paymentMethodState = PaymentMethodFailed();
} }
} }
static const currenciesWithSepa = [
// 'ALL', // Albanian lek
FiatCurrency.bgn, // Bulgarian lev
FiatCurrency.czk, // Czech koruna
FiatCurrency.dkk, // Danish krone
FiatCurrency.huf, // Hungarian forint
FiatCurrency.isk, // Icelandic króna
FiatCurrency.chf, // Liechtenstein/Swiss franc
FiatCurrency.nok, // Norwegian krone
FiatCurrency.pln, // Polish złoty
FiatCurrency.ron, // Romanian leu
FiatCurrency.sek, // Swedish krona
FiatCurrency.gbp, // British pound sterling
];
@action @action
Future<void> calculateBestRate() async { Future<void> calculateBestRate() async {
buySellQuotState = BuySellQuotLoading(); buySellQuotState = BuySellQuotLoading();
final List<BuyProvider> validProviders = providerList.where((provider) { final List<BuyProvider> validProvidersNative = providerList.where((provider) {
if (isBuyAction) { if (isBuyAction) {
return provider.supportedCryptoList.any((pair) => return provider.supportedCryptoList.any((pair) =>
pair.from == cryptoCurrency && pair.to == fiatCurrency); pair.from == cryptoCurrency && pair.to == fiatCurrency);
@ -391,12 +415,25 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
} }
}).toList(); }).toList();
if (validProviders.isEmpty) { final List<BuyProvider> validProvidersSepa = providerList.where((provider) {
if (currenciesWithSepa.contains(fiatCurrency)) {
if (isBuyAction) {
return provider.supportedCryptoList.any((pair) =>
pair.from == cryptoCurrency && pair.to == FiatCurrency.eur);
} else {
return provider.supportedFiatList.any((pair) =>
pair.from == FiatCurrency.eur && pair.to == cryptoCurrency);
}
}
return false;
}).toList();
if (validProvidersNative.isEmpty && validProvidersSepa.isEmpty) {
buySellQuotState = BuySellQuotFailed(); buySellQuotState = BuySellQuotFailed();
return; return;
} }
final result = await Future.wait<List<Quote>?>(validProviders.map((element) => element final result = await Future.wait<List<Quote>?>(validProvidersNative.map((element) => element
.fetchQuote( .fetchQuote(
cryptoCurrency: cryptoCurrency, cryptoCurrency: cryptoCurrency,
fiatCurrency: fiatCurrency, fiatCurrency: fiatCurrency,
@ -409,36 +446,59 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
Duration(seconds: 10), Duration(seconds: 10),
onTimeout: () => null, onTimeout: () => null,
))); )));
final resultSepa = await Future.wait<List<Quote>?>(validProvidersSepa.map((element) => element
.fetchQuote(
cryptoCurrency: cryptoCurrency,
fiatCurrency: FiatCurrency.eur,
amount: amount,
paymentType: selectedPaymentMethod?.paymentMethodType,
isBuyAction: isBuyAction,
walletAddress: wallet.walletAddresses.address,
)
.timeout(
Duration(seconds: 10),
onTimeout: () => null,
)));
sortedRecommendedQuotes.clear(); sortedRecommendedQuotes.clear();
sortedQuotes.clear(); sortedQuotes.clear();
final validQuotes = result final validQuotesNative = result
.where((element) => element != null && element.isNotEmpty) .where((element) => element != null && element.isNotEmpty)
.expand((element) => element!) .expand((element) => element!)
.toList(); .toList();
if (validQuotes.isEmpty) { final validQuotesSepa = resultSepa
.where((element) => element != null && element.isNotEmpty)
.expand((element) => element!)
.toList();
if (validQuotesNative.isEmpty && validQuotesSepa.isEmpty) {
buySellQuotState = BuySellQuotFailed(); buySellQuotState = BuySellQuotFailed();
return; return;
} }
validQuotes.sort((a, b) => a.rate.compareTo(b.rate)); validQuotesNative.sort((a, b) => a.rate.compareTo(b.rate));
validQuotesSepa.sort((a, b) => a.rate.compareTo(b.rate));
final Set<String> addedProviders = {}; final Set<String> addedProviders = {};
final List<Quote> uniqueProviderQuotes = validQuotes.where((element) {
final List<Quote> uniqueProviderQuotesNative = validQuotesNative.where((element) {
if (addedProviders.contains(element.provider.title)) return false; if (addedProviders.contains(element.provider.title)) return false;
addedProviders.add(element.provider.title); addedProviders.add(element.provider.title);
return true; return true;
}).toList(); }).toList();
final List<Quote> successRateQuotes = validQuotes.where((element) =>
final List<Quote> successRateQuotes = [...validQuotesNative, ...validQuotesSepa].where((element) =>
element.provider is OnRamperBuyProvider && element.provider is OnRamperBuyProvider &&
element.recommendations.contains(ProviderRecommendation.successRate) element.recommendations.contains(ProviderRecommendation.successRate)
).toList(); ).toList();
final List<Quote> uniqueProviderQuotes = [];
for (final quote in successRateQuotes) { for (final quote in successRateQuotes) {
if (!uniqueProviderQuotes.contains(quote)) { if (!uniqueProviderQuotesNative.contains(quote)) {
uniqueProviderQuotes.add(quote); uniqueProviderQuotes.add(quote);
} }
} }
@ -446,7 +506,7 @@ abstract class BuySellViewModelBase extends WalletChangeListenerViewModel with S
sortedRecommendedQuotes.addAll(uniqueProviderQuotes); sortedRecommendedQuotes.addAll(uniqueProviderQuotes);
sortedQuotes = ObservableList.of( sortedQuotes = ObservableList.of(
validQuotes.where((element) => !uniqueProviderQuotes.contains(element)).toList()); [...validQuotesNative, ...validQuotesSepa].where((element) => !uniqueProviderQuotes.contains(element)).toList());
if (sortedRecommendedQuotes.isNotEmpty) { if (sortedRecommendedQuotes.isNotEmpty) {
sortedRecommendedQuotes.first sortedRecommendedQuotes.first