diff --git a/lib/buy/moonpay/moonpay_payment_methods.dart b/lib/buy/moonpay/moonpay_payment_methods.dart new file mode 100644 index 0000000000..d9e17c3b05 --- /dev/null +++ b/lib/buy/moonpay/moonpay_payment_methods.dart @@ -0,0 +1,32 @@ +class MoonPayPaymentMethod { + MoonPayPaymentMethod({ + required this.type, + required this.displayName, + required this.iconUrl, + required this.active, + this.limitAmount, + this.limitCurrencyCode, + }); + + factory MoonPayPaymentMethod.fromJson(Map json) { + final availability = json["availability"] as Map? ?? {}; + final limits = json["limits"] as Map?; + final perTransaction = limits?["perTransaction"] as Map?; + + return MoonPayPaymentMethod( + type: json["type"] as String? ?? "", + displayName: json["displayName"] as String? ?? "", + iconUrl: json["iconUrl"] as String? ?? "", + active: availability["active"] as bool? ?? false, + limitAmount: (perTransaction?["limit"] as num?)?.toDouble(), + limitCurrencyCode: perTransaction?["currencyCode"] as String?, + ); + } + + final String type; + final String displayName; + final String iconUrl; + final bool active; + final double? limitAmount; + final String? limitCurrencyCode; +} \ No newline at end of file diff --git a/lib/buy/moonpay/moonpay_provider.dart b/lib/buy/moonpay/moonpay_provider.dart index c4a03a853f..81ed043378 100644 --- a/lib/buy/moonpay/moonpay_provider.dart +++ b/lib/buy/moonpay/moonpay_provider.dart @@ -1,41 +1,38 @@ -import 'dart:convert'; -import 'dart:developer'; - -import 'package:cake_wallet/.secrets.g.dart' as secrets; -import 'package:cake_wallet/buy/buy_exception.dart'; -import 'package:cake_wallet/buy/buy_provider.dart'; -import 'package:cake_wallet/buy/buy_provider_description.dart'; -import 'package:cake_wallet/buy/buy_quote.dart'; -import 'package:cake_wallet/order/order.dart'; -import 'package:cake_wallet/order/order_source_description.dart'; -import 'package:cake_wallet/buy/pairs_utils.dart'; -import 'package:cake_wallet/buy/payment_method.dart'; -import 'package:cake_wallet/entities/fiat_currency.dart'; -import 'package:cake_wallet/exchange/trade_state.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/palette.dart'; -import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; -import 'package:cake_wallet/store/app_store.dart'; -import 'package:cake_wallet/themes/core/material_base_theme.dart'; -import 'package:cw_core/currency_for_wallet_type.dart'; -import 'package:cw_core/utils/proxy_wrapper.dart'; -import 'package:cw_core/crypto_currency.dart'; -import 'package:cw_core/wallet_base.dart'; -import 'package:cw_core/utils/print_verbose.dart'; -import 'package:flutter/material.dart'; -import 'package:url_launcher/url_launcher.dart'; +import "dart:convert"; +import "dart:developer"; + +import "package:cake_wallet/.secrets.g.dart" as secrets; +import "package:cake_wallet/buy/buy_exception.dart"; +import "package:cake_wallet/buy/buy_provider.dart"; +import "package:cake_wallet/buy/buy_provider_description.dart"; +import "package:cake_wallet/buy/buy_quote.dart"; +import "package:cake_wallet/buy/moonpay/moonpay_payment_methods.dart"; +import "package:cake_wallet/buy/pairs_utils.dart"; +import "package:cake_wallet/buy/payment_method.dart"; +import "package:cake_wallet/entities/fiat_currency.dart"; +import "package:cake_wallet/exchange/trade_state.dart"; +import "package:cake_wallet/generated/i18n.dart"; +import "package:cake_wallet/order/order.dart"; +import "package:cake_wallet/order/order_source_description.dart"; +import "package:cake_wallet/palette.dart"; +import "package:cake_wallet/src/widgets/alert_with_one_action.dart"; +import "package:cake_wallet/store/app_store.dart"; +import "package:cw_core/crypto_currency.dart"; +import "package:cw_core/currency_for_wallet_type.dart"; +import "package:cw_core/utils/print_verbose.dart"; +import "package:cw_core/utils/proxy_wrapper.dart"; +import "package:flutter/material.dart"; +import "package:url_launcher/url_launcher.dart"; class MoonPayProvider extends BuyProvider { MoonPayProvider({ required AppStore appStore, - required WalletBase wallet, - bool isTestEnvironment = false, + required super.wallet, + super.isTestEnvironment = false, }) : baseSellUrl = isTestEnvironment ? _baseSellTestUrl : _baseSellProductUrl, baseBuyUrl = isTestEnvironment ? _baseBuyTestUrl : _baseBuyProductUrl, - this._appStore = appStore, + _appStore = appStore, super( - wallet: wallet, - isTestEnvironment: isTestEnvironment, hardwareWalletVM: null, supportedCryptoList: supportedCryptoToFiatPairs( notSupportedCrypto: _notSupportedCrypto, notSupportedFiat: _notSupportedFiat), @@ -44,37 +41,70 @@ class MoonPayProvider extends BuyProvider { final AppStore _appStore; - static const _baseSellTestUrl = 'sell-sandbox.moonpay.com'; - static const _baseSellProductUrl = 'sell.moonpay.com'; - static const _baseBuyTestUrl = 'buy-staging.moonpay.com'; - static const _baseBuyProductUrl = 'buy.moonpay.com'; - static const _cIdBaseUrl = 'exchange-helper.cakewallet.com'; - static const _apiUrl = 'https://api.moonpay.com'; - static const _baseUrl = 'api.moonpay.com'; - static const _currenciesPath = '/v3/currencies'; - static const _buyQuote = '/buy_quote'; - static const _sellQuote = '/sell_quote'; + static const _baseSellTestUrl = "sell-sandbox.moonpay.com"; + static const _baseSellProductUrl = "sell.moonpay.com"; + static const _baseBuyTestUrl = "buy-staging.moonpay.com"; + static const _baseBuyProductUrl = "buy.moonpay.com"; + static const _cIdBaseUrl = "exchange-helper.cakewallet.com"; + static const _apiUrl = "https://api.moonpay.com"; + static const _baseUrl = "api.moonpay.com"; + static const _currenciesPath = "/v3/currencies"; + static const _buyQuote = "/buy_quote"; + static const _sellQuote = "/sell_quote"; + static const _paymentMethodsPath = "/api/moonpay/payment-methods"; - static const _transactionsSuffix = '/v1/transactions'; + static const _transactionsSuffix = "/v1/transactions"; static const List _notSupportedCrypto = []; static const List _notSupportedFiat = []; + static String get _exchangeHelperApiKey => secrets.exchangeHelperApiKey; + + static const Map _moonPayPaymentMethodStrings = { + PaymentType.creditCard: 'credit_debit_card', + PaymentType.debitCard: 'credit_debit_card', + PaymentType.ach: 'ach_bank_transfer', + PaymentType.applePay: 'apple_pay', + PaymentType.googlePay: 'google_pay', + PaymentType.sepa: 'sepa_bank_transfer', + PaymentType.paypal: 'paypal', + PaymentType.sepaOpenBankingPayment: 'sepa_open_banking_payment', + PaymentType.gbpOpenBankingPayment: 'gbp_open_banking_payment', + PaymentType.lowCostAch: 'low_cost_ach', + PaymentType.mobileWallet: 'mobile_wallet', + PaymentType.pixInstantPayment: 'pix_instant_payment', + PaymentType.yellowCardBankTransfer: 'yellow_card_bank_transfer', + PaymentType.fiatBalance: 'fiat_balance', + PaymentType.revolutPay: 'revolut_pay', + PaymentType.moonpayCashApp: 'cash_app', + PaymentType.moonpayBalance: 'moonpay_balance', + }; + + static final Map _paymentTypeByMoonPayString = { + for (final entry in _moonPayPaymentMethodStrings.entries) entry.value: entry.key, + }; + + String? normalizePaymentMethod(PaymentType paymentMethod) => + _moonPayPaymentMethodStrings[paymentMethod]; + + PaymentType _getPaymentTypeByString(String? paymentMethod) => + _paymentTypeByMoonPayString[paymentMethod] ?? PaymentType.unknown; + final String baseBuyUrl; final String baseSellUrl; @override String get providerDescription => - 'MoonPay offers a fast and simple way to buy and sell cryptocurrencies'; + "MoonPay offers a fast and simple way to buy and sell cryptocurrencies"; @override - String get title => 'MoonPay'; + String get title => "MoonPay"; @override - String get lightIcon => 'assets/images/moonpay_light.png'; + String get lightIcon => "assets/images/moonpay_light.png"; @override - String get darkIcon => 'assets/images/moonpay_dark.png'; + String get darkIcon => "assets/images/moonpay_dark.png"; @override bool get isAggregator => false; @@ -84,18 +114,7 @@ class MoonPayProvider extends BuyProvider { String get currencyCode => walletTypeToCryptoCurrency(wallet.type, chainId: wallet.chainId).title.toLowerCase(); - String get trackUrl => baseBuyUrl + '/transaction_receipt?transactionId='; - - static String get _exchangeHelperApiKey => secrets.exchangeHelperApiKey; - - static String themeToMoonPayTheme(MaterialThemeBase theme) { - switch (theme.type) { - case ThemeType.light: - return 'light'; - case ThemeType.dark: - return 'dark'; - } - } + String get trackUrl => "$baseBuyUrl/transaction_receipt?transactionId="; Future getMoonpaySignedQuery(String query) async { final uri = @@ -103,102 +122,127 @@ class MoonPayProvider extends BuyProvider { final response = await ProxyWrapper().post( clearnetUri: uri, - headers: {'Content-Type': 'application/json', 'x-api-key': _exchangeHelperApiKey}, - body: json.encode({'query': query}), + headers: {"Content-Type": "application/json", "x-api-key": _exchangeHelperApiKey}, + body: json.encode({"query": query}), ); if (response.statusCode == 200) { - printV((jsonDecode(response.body) as Map)); - return (jsonDecode(response.body) as Map)['query'] as String; + printV(jsonDecode(response.body) as Map); + return (jsonDecode(response.body) as Map)["query"] as String; } else { throw Exception( - 'Provider currently unavailable. Status: ${response.statusCode} ${response.body}'); + "Provider currently unavailable. Status: ${response.statusCode} ${response.body}", + ); } } - Future> fetchFiatCredentials( - String fiatCurrency, String cryptocurrency, String? paymentMethod) async { - final params = {'baseCurrencyCode': fiatCurrency.toLowerCase(), 'apiKey': _apiKey}; + Future> fetchMoonPayPaymentMethods({ + required String currencyCode, + String transactionType = "buy", + }) async { + final String? countryCode = FiatCurrency.tryDeserialize(raw: currencyCode)?.apiCountryCode; - if (paymentMethod != null) params['paymentMethod'] = paymentMethod; + if (countryCode == null) { + throw Exception("failed to determine country code for currency: $currencyCode"); + } - final path = '$_currenciesPath/${cryptocurrency.toLowerCase()}/limits'; - final url = Uri.https(_baseUrl, path, params); + final params = { + "currencyCode": currencyCode, + "countryCode": countryCode, + "transactionType": transactionType, + if (countryCode == "USA") "stateOfResidence": "NY", + }; - try { - final response = await ProxyWrapper().get( - clearnetUri: url, - headers: {'accept': 'application/json'}, - ); + final uri = Uri.https(_cIdBaseUrl, _paymentMethodsPath, params); - if (response.statusCode == 200) { - return jsonDecode(response.body) as Map; - } else { - printV('MoonPay does not support fiat: $fiatCurrency'); - return {}; + final response = await ProxyWrapper().get( + clearnetUri: uri, + headers: { + "Accept": "application/json", + "x-api-key": _exchangeHelperApiKey, + }, + ); + + if (response.statusCode != 200) { + if (response.statusCode == 500) { + throw Exception("failed to fetch payment methods. Status: 500 Internal Server Error"); } - } catch (e) { - printV('MoonPay Error fetching fiat currencies: $e'); - return {}; + throw Exception( + "failed to fetch payment methods. Status: ${response.statusCode} ${response.body}"); } + + final decoded = jsonDecode(response.body) as Map; + final list = decoded["payment-methods"] as List? ?? []; + + return list.map((e) => MoonPayPaymentMethod.fromJson(e as Map)).toList(); } + @override Future> getAvailablePaymentTypes( String fiatCurrency, CryptoCurrency cryptoCurrency, bool isBuyAction) async { final List paymentMethods = []; - if (isBuyAction) { - final fiatBuyCredentials = - await fetchFiatCredentials(fiatCurrency, cryptoCurrency.title, null); - if (fiatBuyCredentials.isNotEmpty) { - final paymentMethod = fiatBuyCredentials['paymentMethod'] as String?; + try { + final moonPayMethods = await fetchMoonPayPaymentMethods( + currencyCode: fiatCurrency, + transactionType: isBuyAction ? "buy" : "sell", + ); + + for (final method in moonPayMethods) { + if (!method.active) { + continue; + } + final paymentType = _getPaymentTypeByString(method.type); + paymentMethods.add(PaymentMethod.fromMoonPayJson( - fiatBuyCredentials, _getPaymentTypeByString(paymentMethod))); - return paymentMethods; + method, + paymentType, + ),); } + } catch (e) { + printV("Error fetching payment methods: $e"); } return paymentMethods; } @override - Future?> fetchQuote( - {required CryptoCurrency cryptoCurrency, - required FiatCurrency fiatCurrency, - required double amount, - required bool isBuyAction, - required String walletAddress, - PaymentType? paymentType, - String? customPaymentMethodType, - String? countryCode}) async { + Future?> fetchQuote({ + required CryptoCurrency cryptoCurrency, + required FiatCurrency fiatCurrency, + required double amount, + required bool isBuyAction, + required String walletAddress, + PaymentType? paymentType, + String? customPaymentMethodType, + String? countryCode, + }) async { String? paymentMethod; if (paymentType != null && paymentType != PaymentType.all) { paymentMethod = normalizePaymentMethod(paymentType); - if (paymentMethod == null) paymentMethod = paymentType.name; - } else { - paymentMethod = 'credit_debit_card'; + paymentMethod ??= paymentType.name; } - final action = isBuyAction ? 'buy' : 'sell'; + final action = isBuyAction ? "buy" : "sell"; final formattedCryptoCurrency = _normalizeCurrency(cryptoCurrency); final baseCurrencyCode = isBuyAction ? fiatCurrency.name.toLowerCase() : cryptoCurrency.title.toLowerCase(); final params = { - 'baseCurrencyCode': baseCurrencyCode, - 'baseCurrencyAmount': amount.toStringAsFixed(2), - 'paymentMethod': paymentMethod, - 'areFeesIncluded': 'false', - 'apiKey': _apiKey + "baseCurrencyCode": baseCurrencyCode, + "baseCurrencyAmount": amount.toStringAsFixed(2), + if (paymentMethod != null) "enabledPaymentMethods": paymentMethod, + "areFeesIncluded": "false", + 'apiKey': "pk_live_JPGapObCLwMCCxREzYE8zvsRN06eppUf" }; - log('MoonPay: Fetching $action quote: ${isBuyAction ? formattedCryptoCurrency : fiatCurrency.name.toLowerCase()} -> ${isBuyAction ? baseCurrencyCode : formattedCryptoCurrency}, amount: $amount, paymentMethod: $paymentMethod'); + log("MoonPay: Fetching $action quote: ${isBuyAction ? formattedCryptoCurrency : fiatCurrency.name.toLowerCase()} -> ${isBuyAction ? baseCurrencyCode : formattedCryptoCurrency}, amount: $amount, paymentMethod: $paymentMethod"); final quotePath = isBuyAction ? _buyQuote : _sellQuote; - final path = '$_currenciesPath/$formattedCryptoCurrency$quotePath'; + final path = "$_currenciesPath/$formattedCryptoCurrency$quotePath"; final url = Uri.https(_baseUrl, path, params); try { final response = await ProxyWrapper().get(clearnetUri: url); @@ -218,19 +262,26 @@ class MoonPayProvider extends BuyProvider { } final paymentMethods = data['paymentMethod'] as String?; + final quote = - Quote.fromMoonPayJson(data, isBuyAction, _getPaymentTypeByString(paymentMethods)); + Quote.fromMoonPayJson(data, isBuyAction, _getPaymentTypeByString(paymentMethods ?? paymentMethod)); quote.setFiatCurrency = fiatCurrency; quote.setCryptoCurrency = cryptoCurrency; return [quote]; - } else { - printV('Moon Pay: Error fetching buy quote: '); + } + try { + final errorData = jsonDecode(response.body) as Map; + final errorMessage = errorData["message"] as String?; + printV("Error fetching buy quote: $errorMessage"); + return null; + } catch (e) { + printV("Error parsing error response: $e"); return null; } } catch (e) { - printV('Moon Pay: Error fetching buy quote: $e'); + printV("Exception while fetching buy quote: $e"); return null; } } @@ -244,20 +295,20 @@ class MoonPayProvider extends BuyProvider { required String cryptoCurrencyAddress, String? countryCode}) async { final Map params = { - 'theme': themeToMoonPayTheme(_appStore.themeStore.currentTheme), - 'language': _appStore.settingsStore.languageCode, - 'colorCode': _appStore.themeStore.currentTheme.isDark + "theme": _appStore.themeStore.currentTheme.type.name, + "language": _appStore.settingsStore.languageCode, + "colorCode": _appStore.themeStore.currentTheme.isDark ? '#${Palette.blueCraiola.value.toRadixString(16).substring(2, 8)}' : '#${Palette.moderateSlateBlue.value.toRadixString(16).substring(2, 8)}', - 'baseCurrencyCode': isBuyAction ? quote.fiatCurrency.name : quote.cryptoCurrency.name, - 'baseCurrencyAmount': amount.toStringAsFixed(2), - 'walletAddress': cryptoCurrencyAddress, - 'lockAmount': 'false', - 'showAllCurrencies': 'false', - 'showWalletAddressForm': 'false', + "baseCurrencyCode": isBuyAction ? quote.fiatCurrency.name : quote.cryptoCurrency.name, + "baseCurrencyAmount": amount.toStringAsFixed(2), + "walletAddress": cryptoCurrencyAddress, + "lockAmount": "false", + "showAllCurrencies": "false", + "showWalletAddressForm": "false", if (isBuyAction) - 'enabledPaymentMethods': normalizePaymentMethod(quote.paymentType) ?? - 'credit_debit_card,apple_pay,google_pay,samsung_pay,sepa_bank_transfer,gbp_bank_transfer,gbp_open_banking_payment', + "enabledPaymentMethods": normalizePaymentMethod(quote.paymentType) ?? + "credit_debit_card,apple_pay,google_pay,samsung_pay,sepa_bank_transfer,gbp_bank_transfer,gbp_open_banking_payment", if (!isBuyAction) 'refundWalletAddress': cryptoCurrencyAddress }; @@ -274,20 +325,18 @@ class MoonPayProvider extends BuyProvider { if (await canLaunchUrl(uri)) { await launchUrl(uri, mode: LaunchMode.externalApplication); } else { - throw Exception('Could not launch URL'); + throw Exception("Could not launch URL"); } } catch (e) { if (context.mounted) { await showDialog( context: context, - builder: (BuildContext context) { - return AlertWithOneAction( - alertTitle: 'MoonPay', - alertContent: 'The MoonPay service is currently unavailable: $e', - buttonText: S.of(context).ok, - buttonAction: () => Navigator.of(context).pop(), - ); - }, + builder: (BuildContext context) => AlertWithOneAction( + alertTitle: 'MoonPay', + alertContent: 'The MoonPay service is currently unavailable: $e', + buttonText: S.of(context).ok, + buttonAction: () => Navigator.of(context).pop(), + ), ); } } @@ -347,76 +396,4 @@ class MoonPayProvider extends BuyProvider { return currency.toString().toLowerCase(); } - - String? normalizePaymentMethod(PaymentType paymentMethod) { - switch (paymentMethod) { - case PaymentType.creditCard: - return 'credit_debit_card'; - case PaymentType.debitCard: - return 'credit_debit_card'; - case PaymentType.ach: - return 'ach_bank_transfer'; - case PaymentType.applePay: - return 'apple_pay'; - case PaymentType.googlePay: - return 'google_pay'; - case PaymentType.sepa: - return 'sepa_bank_transfer'; - case PaymentType.paypal: - return 'paypal'; - case PaymentType.sepaOpenBankingPayment: - return 'sepa_open_banking_payment'; - case PaymentType.gbpOpenBankingPayment: - return 'gbp_open_banking_payment'; - case PaymentType.lowCostAch: - return 'low_cost_ach'; - case PaymentType.mobileWallet: - return 'mobile_wallet'; - case PaymentType.pixInstantPayment: - return 'pix_instant_payment'; - case PaymentType.yellowCardBankTransfer: - return 'yellow_card_bank_transfer'; - case PaymentType.fiatBalance: - return 'fiat_balance'; - case PaymentType.revolutPay: - return 'revolut_pay'; - default: - return null; - } - } - - PaymentType _getPaymentTypeByString(String? paymentMethod) { - switch (paymentMethod) { - case 'ach_bank_transfer': - return PaymentType.ach; - case 'apple_pay': - return PaymentType.applePay; - case 'credit_debit_card': - return PaymentType.creditCard; - case 'fiat_balance': - return PaymentType.fiatBalance; - case 'gbp_open_banking_payment': - return PaymentType.gbpOpenBankingPayment; - case 'google_pay': - return PaymentType.googlePay; - case 'low_cost_ach': - return PaymentType.lowCostAch; - case 'mobile_wallet': - return PaymentType.mobileWallet; - case 'paypal': - return PaymentType.paypal; - case 'pix_instant_payment': - return PaymentType.pixInstantPayment; - case 'sepa_bank_transfer': - return PaymentType.sepa; - case 'sepa_open_banking_payment': - return PaymentType.sepaOpenBankingPayment; - case 'yellow_card_bank_transfer': - return PaymentType.yellowCardBankTransfer; - case 'revolut_pay': - return PaymentType.revolutPay; - default: - return PaymentType.unknown; - } - } } diff --git a/lib/buy/payment_method.dart b/lib/buy/payment_method.dart index 06f1cfe34f..860c894c17 100644 --- a/lib/buy/payment_method.dart +++ b/lib/buy/payment_method.dart @@ -1,4 +1,6 @@ +import "package:cake_wallet/buy/moonpay/moonpay_payment_methods.dart"; import 'package:cake_wallet/core/selectable_option.dart'; +import "package:cake_wallet/entities/calculate_fiat_amount.dart"; enum PaymentType { all, @@ -33,6 +35,8 @@ enum PaymentType { fiatBalance, bancontact, pixPay, + moonpayCashApp, + moonpayBalance, unknown, } @@ -165,6 +169,8 @@ class PaymentMethod extends SelectableOption { required this.customIconPath, this.customDescription, this.customPaymentMethodType, + this.customBadges = const [], + this.customBottomLeftSubTitle, }) : super(title: paymentMethodType.title ?? customTitle); final PaymentType paymentMethodType; @@ -172,8 +178,16 @@ class PaymentMethod extends SelectableOption { final String customIconPath; final String? customDescription; final String? customPaymentMethodType; + final List customBadges; + final String? customBottomLeftSubTitle; bool isSelected = false; + @override + List get badges => customBadges; + + @override + String? get bottomLeftSubTitle => customBottomLeftSubTitle; + @override String? get description => paymentMethodType.description ?? customDescription; @@ -210,11 +224,25 @@ class PaymentMethod extends SelectableOption { customIconPath: 'assets/images/card.png'); } - factory PaymentMethod.fromMoonPayJson(Map json, PaymentType paymentType) { + factory PaymentMethod.fromMoonPayJson(MoonPayPaymentMethod method, PaymentType paymentType) { + final List badges = []; + String? limitSubtitle; + if (paymentType == PaymentType.moonpayCashApp) { + badges.add('New'); + } + if (method.limitAmount != null && method.limitCurrencyCode != null) { + limitSubtitle = + 'max: ${formatWithCommas(method.limitAmount.toString())} ${method.limitCurrencyCode!.toUpperCase()}'; + } + return PaymentMethod( - paymentMethodType: paymentType, - customTitle: json['paymentMethod'] as String, - customIconPath: 'assets/images/card.png'); + paymentMethodType: paymentType, + customTitle: method.displayName, + customIconPath: method.iconUrl.isNotEmpty ? method.iconUrl : 'assets/images/card.png', + customPaymentMethodType: method.type, + customBadges: badges, + customBottomLeftSubTitle: limitSubtitle, + ); } factory PaymentMethod.fromMeldJson(Map json) { diff --git a/lib/entities/fiat_currency.dart b/lib/entities/fiat_currency.dart index 1907211b71..6997a96600 100644 --- a/lib/entities/fiat_currency.dart +++ b/lib/entities/fiat_currency.dart @@ -8,9 +8,11 @@ class FiatCurrency extends EnumerableItem with Serializable impl required this.countryCode, required this.fullName, this.decimals = 2, + this.isoCountryCode, }) : super(title: symbol, raw: symbol); final String countryCode; + final String? isoCountryCode; @override final String fullName; @@ -21,6 +23,8 @@ class FiatCurrency extends EnumerableItem with Serializable impl @override final String symbol; + String get apiCountryCode => isoCountryCode ?? countryCode.toUpperCase(); + static List get all => _all.values.toList(); static List get currenciesAvailableToBuyWith => [ @@ -74,15 +78,15 @@ class FiatCurrency extends EnumerableItem with Serializable impl static const bdt = FiatCurrency(symbol: 'BDT', countryCode: "bgd", fullName: "Bangladeshi Taka"); static const bgn = FiatCurrency(symbol: 'BGN', countryCode: "bgr", fullName: "Bulgarian Lev"); static const brl = FiatCurrency(symbol: 'BRL', countryCode: "bra", fullName: "Brazilian Real"); - static const cad = FiatCurrency(symbol: 'CAD', countryCode: "cad", fullName: "Canadian Dollar"); + static const cad = FiatCurrency(symbol: 'CAD', countryCode: "cad", fullName: "Canadian Dollar", isoCountryCode: "CAN"); static const chf = FiatCurrency(symbol: 'CHF', countryCode: "che", fullName: "Swiss Franc"); static const clp = FiatCurrency(symbol: 'CLP', countryCode: "chl", fullName: "Chilean Peso"); static const cny = FiatCurrency(symbol: 'CNY', countryCode: "chn", fullName: "Chinese Yuan"); static const cop = FiatCurrency(symbol: 'COP', countryCode: "col", fullName: "Colombian Peso"); - static const czk = FiatCurrency(symbol: 'CZK', countryCode: "czk", fullName: "Czech Koruna"); + static const czk = FiatCurrency(symbol: 'CZK', countryCode: "czk", fullName: "Czech Koruna", isoCountryCode: "CZE"); static const dkk = FiatCurrency(symbol: 'DKK', countryCode: "dnk", fullName: "Danish Krone"); static const egp = FiatCurrency(symbol: 'EGP', countryCode: "egy", fullName: "Egyptian Pound"); - static const eur = FiatCurrency(symbol: 'EUR', countryCode: "eur", fullName: "Euro"); + static const eur = FiatCurrency(symbol: 'EUR', countryCode: "eur", fullName: "Euro", isoCountryCode: "DEU"); static const gbp = FiatCurrency(symbol: 'GBP', countryCode: "gbr", fullName: "Pound Sterling"); static const ghs = FiatCurrency(symbol: 'GHS', countryCode: "gha", fullName: "Ghanaian Cedi"); static const gtq = @@ -126,7 +130,7 @@ class FiatCurrency extends EnumerableItem with Serializable impl static const vnd = FiatCurrency(symbol: 'VND', countryCode: "vnm", fullName: "Vietnamese Dong đồng"); static const zar = - FiatCurrency(symbol: 'ZAR', countryCode: "saf", fullName: "South African Rand"); + FiatCurrency(symbol: 'ZAR', countryCode: "saf", fullName: "South African Rand", isoCountryCode: "ZAF"); static const tur = FiatCurrency(symbol: 'TRY', countryCode: "tur", fullName: "Turkish Lira"); static const kes = FiatCurrency(symbol: 'KES', countryCode: "ken", fullName: "Kenyan Shillings"); @@ -186,6 +190,8 @@ class FiatCurrency extends EnumerableItem with Serializable impl static FiatCurrency deserialize({required String raw}) => _all[raw] ?? FiatCurrency.usd; + static FiatCurrency? tryDeserialize({required String raw}) => _all[raw]; + @override bool operator ==(Object other) => other is FiatCurrency && other.raw == raw; diff --git a/lib/src/screens/select_options_page.dart b/lib/src/screens/select_options_page.dart index 6300416550..e45c1efb66 100644 --- a/lib/src/screens/select_options_page.dart +++ b/lib/src/screens/select_options_page.dart @@ -41,8 +41,7 @@ abstract class SelectOptionsPage extends BasePage { String get title => pageTitle; @override - Widget body(BuildContext context) { - return ScrollableWithBottomSection( + Widget body(BuildContext context) => ScrollableWithBottomSection( content: BodySelectOptionsPage( currentTheme: currentTheme, items: items, @@ -81,7 +80,6 @@ abstract class SelectOptionsPage extends BasePage { ), ), ); - } } class BodySelectOptionsPage extends StatefulWidget { @@ -131,8 +129,7 @@ class _BodySelectOptionsPageState extends State { } @override - Widget build(BuildContext context) { - return Center( + Widget build(BuildContext context) => Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 350), child: Column( @@ -191,5 +188,4 @@ class _BodySelectOptionsPageState extends State { ), ), ); - } }