Generic fixes (#1245)

* Remove error message if buy action is disabled

* Fix wallet list selected wallet issue

* Check if the widget is still mounted before showing popup

* minor code readability enhancement [skip ci]

* Code enhancement [skip ci]

* Revert removing ask each time localization

* Add Moonpay to sell flow
Code Enhancements

* remove error popup when sell option is disabled
This commit is contained in:
Omar Hatem 2024-01-01 15:05:37 +02:00 committed by GitHub
parent 4065a1bcab
commit 133fa2987a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 270 additions and 313 deletions

View file

@ -20,12 +20,7 @@ class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
@override
Future<EthereumWallet> create(EthereumNewWalletCredentials credentials) async {
final strength = (credentials.seedPhraseLength == 12)
? 128
: (credentials.seedPhraseLength == 24)
? 256
: 128;
final strength = credentials.seedPhraseLength == 24 ? 256 : 128;
final mnemonic = bip39.generateMnemonic(strength: strength);
final wallet = EthereumWallet(
@ -67,8 +62,8 @@ class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
@override
Future<void> remove(String wallet) async {
File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
final walletInfo = walletInfoSource.values.firstWhereOrNull(
(info) => info.id == WalletBase.idFor(wallet, getType()))!;
final walletInfo = walletInfoSource.values
.firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
await walletInfoSource.delete(walletInfo.key);
}

View file

@ -20,11 +20,7 @@ class PolygonWalletService extends WalletService<PolygonNewWalletCredentials,
@override
Future<PolygonWallet> create(PolygonNewWalletCredentials credentials) async {
final strength = (credentials.seedPhraseLength == 12)
? 128
: (credentials.seedPhraseLength == 24)
? 256
: 128;
final strength = credentials.seedPhraseLength == 24 ? 256 : 128;
final mnemonic = bip39.generateMnemonic(strength: strength);
final wallet = PolygonWallet(

View file

@ -14,9 +14,7 @@ abstract class BuyProvider {
String get title;
String get buyOptionDescription;
String get sellOptionDescription;
String get providerDescription;
String get lightIcon;

View file

@ -26,10 +26,7 @@ class DFXBuyProvider extends BuyProvider {
String get title => 'DFX Connect';
@override
String get buyOptionDescription => S.current.dfx_option_description;
@override
String get sellOptionDescription => S.current.dfx_option_description;
String get providerDescription => S.current.dfx_option_description;
@override
String get lightIcon => 'assets/images/dfx_light.png';
@ -152,6 +149,7 @@ class DFXBuyProvider extends BuyProvider {
}
}
@override
Future<void> launchProvider(BuildContext context, bool? isBuyAction) async {
try {
final assetOut = this.assetOut;

View file

@ -21,19 +21,33 @@ import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cw_core/crypto_currency.dart';
import 'package:url_launcher/url_launcher.dart';
class MoonPaySellProvider {
MoonPaySellProvider({required SettingsStore settingsStore,
required WalletBase wallet, this.isTest = false})
: baseUrl = isTest ? _baseTestUrl : _baseProductUrl,
class MoonPaySellProvider extends BuyProvider {
MoonPaySellProvider({
required SettingsStore settingsStore,
required WalletBase wallet,
bool isTestEnvironment = false,
}) : baseUrl = isTestEnvironment ? _baseTestUrl : _baseProductUrl,
this._settingsStore = settingsStore,
this._wallet = wallet;
super(wallet: wallet, isTestEnvironment: isTestEnvironment);
final SettingsStore _settingsStore;
final WalletBase _wallet;
static const _baseTestUrl = 'sell-sandbox.moonpay.com';
static const _baseProductUrl = 'sell.moonpay.com';
@override
String get providerDescription =>
'MoonPay offers a fast and simple way to buy and sell cryptocurrencies';
@override
String get title => 'MoonPay';
@override
String get lightIcon => 'assets/images/moonpay_light.png';
@override
String get darkIcon => 'assets/images/moonpay_dark.png';
static String themeToMoonPayTheme(ThemeBase theme) {
switch (theme.type) {
case ThemeType.bright:
@ -45,11 +59,11 @@ class MoonPaySellProvider {
}
static String get _apiKey => secrets.moonPayApiKey;
static String get _secretKey => secrets.moonPaySecretKey;
final bool isTest;
final String baseUrl;
Future<Uri> requestUrl({
Future<Uri> requestMoonPayUrl({
required CryptoCurrency currency,
required String refundWalletAddress,
required SettingsStore settingsStore,
@ -78,7 +92,7 @@ class MoonPaySellProvider {
final digest = hmac.convert(messageBytes);
final signature = base64.encode(digest.bytes);
if (isTest) {
if (isTestEnvironment) {
return originalUri;
}
@ -88,11 +102,12 @@ class MoonPaySellProvider {
return signedUri;
}
Future<void> launchProvider(BuildContext context) async {
@override
Future<void> launchProvider(BuildContext context, bool? isBuyAction) async {
try {
final uri = await requestUrl(
currency: _wallet.currency,
refundWalletAddress: _wallet.walletAddresses.address,
final uri = await requestMoonPayUrl(
currency: wallet.currency,
refundWalletAddress: wallet.walletAddresses.address,
settingsStore: _settingsStore,
);
@ -137,35 +152,43 @@ class MoonPayBuyProvider extends BuyProvider {
static const _secretKey = secrets.moonPaySecretKey;
@override
String get title => 'Moon Pay';
String get title => 'MoonPay';
@override
String get buyOptionDescription => '';
String get providerDescription =>
'MoonPay offers a fast and simple way to buy and sell cryptocurrencies';
@override
String get lightIcon => 'assets/images/moonpay_light.png';
@override
String get darkIcon => 'assets/images/moonpay_dark.png';
String get currencyCode =>
walletTypeToCryptoCurrency(wallet.type).title.toLowerCase();
String get currencyCode => walletTypeToCryptoCurrency(wallet.type).title.toLowerCase();
String get trackUrl => baseUrl + '/transaction_receipt?transactionId=';
String baseUrl;
Future<String> requestUrl(String amount, String sourceCurrency) async {
final enabledPaymentMethods =
'credit_debit_card%2Capple_pay%2Cgoogle_pay%2Csamsung_pay'
final enabledPaymentMethods = 'credit_debit_card%2Capple_pay%2Cgoogle_pay%2Csamsung_pay'
'%2Csepa_bank_transfer%2Cgbp_bank_transfer%2Cgbp_open_banking_payment';
final suffix = '?apiKey=' + _apiKey + '&currencyCode=' +
currencyCode + '&enabledPaymentMethods=' + enabledPaymentMethods +
'&walletAddress=' + wallet.walletAddresses.address +
'&baseCurrencyCode=' + sourceCurrency.toLowerCase() +
'&baseCurrencyAmount=' + amount + '&lockAmount=true' +
'&showAllCurrencies=false' + '&showWalletAddressForm=false';
final suffix = '?apiKey=' +
_apiKey +
'&currencyCode=' +
currencyCode +
'&enabledPaymentMethods=' +
enabledPaymentMethods +
'&walletAddress=' +
wallet.walletAddresses.address +
'&baseCurrencyCode=' +
sourceCurrency.toLowerCase() +
'&baseCurrencyAmount=' +
amount +
'&lockAmount=true' +
'&showAllCurrencies=false' +
'&showWalletAddressForm=false';
final originalUrl = baseUrl + suffix;
@ -174,24 +197,27 @@ class MoonPayBuyProvider extends BuyProvider {
final hmac = Hmac(sha256, key);
final digest = hmac.convert(messageBytes);
final signature = base64.encode(digest.bytes);
final urlWithSignature = originalUrl +
'&signature=${Uri.encodeComponent(signature)}';
final urlWithSignature = originalUrl + '&signature=${Uri.encodeComponent(signature)}';
return isTestEnvironment ? originalUrl : urlWithSignature;
}
Future<BuyAmount> calculateAmount(String amount, String sourceCurrency) async {
final url = _apiUrl + _currenciesSuffix + '/$currencyCode' +
_quoteSuffix + '/?apiKey=' + _apiKey +
'&baseCurrencyAmount=' + amount +
'&baseCurrencyCode=' + sourceCurrency.toLowerCase();
final url = _apiUrl +
_currenciesSuffix +
'/$currencyCode' +
_quoteSuffix +
'/?apiKey=' +
_apiKey +
'&baseCurrencyAmount=' +
amount +
'&baseCurrencyCode=' +
sourceCurrency.toLowerCase();
final uri = Uri.parse(url);
final response = await get(uri);
if (response.statusCode != 200) {
throw BuyException(
title: buyOptionDescription,
content: 'Quote is not found!');
throw BuyException(title: providerDescription, content: 'Quote is not found!');
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
@ -200,21 +226,16 @@ class MoonPayBuyProvider extends BuyProvider {
final minSourceAmount = responseJSON['baseCurrency']['minAmount'] as int;
return BuyAmount(
sourceAmount: sourceAmount,
destAmount: destAmount,
minAmount: minSourceAmount);
sourceAmount: sourceAmount, destAmount: destAmount, minAmount: minSourceAmount);
}
Future<Order> findOrderById(String id) async {
final url = _apiUrl + _transactionsSuffix + '/$id' +
'?apiKey=' + _apiKey;
final url = _apiUrl + _transactionsSuffix + '/$id' + '?apiKey=' + _apiKey;
final uri = Uri.parse(url);
final response = await get(uri);
if (response.statusCode != 200) {
throw BuyException(
title: buyOptionDescription,
content: 'Transaction $id is not found!');
throw BuyException(title: providerDescription, content: 'Transaction $id is not found!');
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
@ -232,8 +253,7 @@ class MoonPayBuyProvider extends BuyProvider {
createdAt: createdAt,
amount: amount.toString(),
receiveAddress: wallet.walletAddresses.address,
walletId: wallet.id
);
walletId: wallet.id);
}
static Future<bool> onEnabled() async {
@ -254,12 +274,6 @@ class MoonPayBuyProvider extends BuyProvider {
}
@override
// TODO: implement sellOptionDescription
String get sellOptionDescription => throw UnimplementedError();
@override
Future<void> launchProvider(BuildContext context, bool? isBuyAction) {
// TODO: implement launchProvider
throw UnimplementedError();
}
}
Future<void> launchProvider(BuildContext context, bool? isBuyAction) =>
throw UnimplementedError();
}

View file

@ -23,10 +23,7 @@ class OnRamperBuyProvider extends BuyProvider {
String get title => 'Onramper';
@override
String get buyOptionDescription => S.current.onramper_option_description;
@override
String get sellOptionDescription => S.current.onramper_option_description;
String get providerDescription => S.current.onramper_option_description;
@override
String get lightIcon => 'assets/images/onramper_light.png';

View file

@ -1,10 +1,7 @@
import 'dart:convert';
import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cake_wallet/buy/buy_amount.dart';
import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/buy/buy_provider_description.dart';
import 'package:cake_wallet/buy/order.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
@ -14,22 +11,18 @@ import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:url_launcher/url_launcher.dart';
class RobinhoodBuyProvider extends BuyProvider{
class RobinhoodBuyProvider extends BuyProvider {
RobinhoodBuyProvider({required WalletBase wallet, bool isTestEnvironment = false})
: super(wallet: wallet, isTestEnvironment: isTestEnvironment);
static const _baseUrl = 'applink.robinhood.com';
static const _cIdBaseUrl = 'exchange-helper.cakewallet.com';
@override
String get title => 'Robinhood Connect';
@override
String get buyOptionDescription => S.current.robinhood_option_description;
@override
String get sellOptionDescription => S.current.robinhood_option_description;
String get providerDescription => S.current.robinhood_option_description;
@override
String get lightIcon => 'assets/images/robinhood_light.png';
@ -105,5 +98,4 @@ class RobinhoodBuyProvider extends BuyProvider{
});
}
}
}

View file

@ -13,10 +13,8 @@ import 'package:cake_wallet/.secrets.g.dart' as secrets;
class WyreBuyProvider extends BuyProvider {
WyreBuyProvider({required WalletBase wallet, bool isTestEnvironment = false})
: baseApiUrl = isTestEnvironment
? _baseTestApiUrl
: _baseProductApiUrl,
super(wallet: wallet, isTestEnvironment: isTestEnvironment);
: baseApiUrl = isTestEnvironment ? _baseTestApiUrl : _baseProductApiUrl,
super(wallet: wallet, isTestEnvironment: isTestEnvironment);
static const _baseTestApiUrl = 'https://api.testwyre.com';
static const _baseProductApiUrl = 'https://api.sendwyre.com';
@ -36,7 +34,7 @@ class WyreBuyProvider extends BuyProvider {
String get title => 'Wyre';
@override
String get buyOptionDescription => '';
String get providerDescription => '';
@override
String get lightIcon => 'assets/images/robinhood_light.png';
@ -44,16 +42,13 @@ class WyreBuyProvider extends BuyProvider {
@override
String get darkIcon => 'assets/images/robinhood_dark.png';
String get trackUrl => isTestEnvironment
? _trackTestUrl
: _trackProductUrl;
String get trackUrl => isTestEnvironment ? _trackTestUrl : _trackProductUrl;
String baseApiUrl;
Future<String> requestUrl(String amount, String sourceCurrency) async {
final timestamp = DateTime.now().millisecondsSinceEpoch.toString();
final url = baseApiUrl + _ordersSuffix + _reserveSuffix +
_timeStampSuffix + timestamp;
final url = baseApiUrl + _ordersSuffix + _reserveSuffix + _timeStampSuffix + timestamp;
final uri = Uri.parse(url);
final body = {
'amount': amount,
@ -72,9 +67,7 @@ class WyreBuyProvider extends BuyProvider {
body: json.encode(body));
if (response.statusCode != 200) {
throw BuyException(
title: buyOptionDescription,
content: 'Url $url is not found!');
throw BuyException(title: providerDescription, content: 'Url $url is not found!');
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
@ -102,9 +95,7 @@ class WyreBuyProvider extends BuyProvider {
body: json.encode(body));
if (response.statusCode != 200) {
throw BuyException(
title: buyOptionDescription,
content: 'Quote is not found!');
throw BuyException(title: providerDescription, content: 'Quote is not found!');
}
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
@ -112,7 +103,8 @@ class WyreBuyProvider extends BuyProvider {
final destAmount = responseJSON['destAmount'] as double;
final achAmount = responseJSON['sourceAmountWithoutFees'] as double;
return BuyAmount(sourceAmount: sourceAmount, destAmount: destAmount, achSourceAmount: achAmount);
return BuyAmount(
sourceAmount: sourceAmount, destAmount: destAmount, achSourceAmount: achAmount);
}
Future<Order> findOrderById(String id) async {
@ -121,35 +113,27 @@ class WyreBuyProvider extends BuyProvider {
final orderResponse = await get(orderUri);
if (orderResponse.statusCode != 200) {
throw BuyException(
title: buyOptionDescription,
content: 'Order $id is not found!');
throw BuyException(title: providerDescription, content: 'Order $id is not found!');
}
final orderResponseJSON =
json.decode(orderResponse.body) as Map<String, dynamic>;
final orderResponseJSON = json.decode(orderResponse.body) as Map<String, dynamic>;
final transferId = orderResponseJSON['transferId'] as String;
final from = orderResponseJSON['sourceCurrency'] as String;
final to = orderResponseJSON['destCurrency'] as String;
final status = orderResponseJSON['status'] as String;
final state = TradeState.deserialize(raw: status.toLowerCase());
final createdAtRaw = orderResponseJSON['createdAt'] as int;
final createdAt =
DateTime.fromMillisecondsSinceEpoch(createdAtRaw).toLocal();
final createdAt = DateTime.fromMillisecondsSinceEpoch(createdAtRaw).toLocal();
final transferUrl =
baseApiUrl + _transferSuffix + transferId + _trackSuffix;
final transferUrl = baseApiUrl + _transferSuffix + transferId + _trackSuffix;
final transferUri = Uri.parse(transferUrl);
final transferResponse = await get(transferUri);
if (transferResponse.statusCode != 200) {
throw BuyException(
title: buyOptionDescription,
content: 'Transfer $transferId is not found!');
throw BuyException(title: providerDescription, content: 'Transfer $transferId is not found!');
}
final transferResponseJSON =
json.decode(transferResponse.body) as Map<String, dynamic>;
final transferResponseJSON = json.decode(transferResponse.body) as Map<String, dynamic>;
final amount = transferResponseJSON['destAmount'] as double;
return Order(
@ -162,8 +146,7 @@ class WyreBuyProvider extends BuyProvider {
createdAt: createdAt,
amount: amount.toString(),
receiveAddress: wallet.walletAddresses.address,
walletId: wallet.id
);
walletId: wallet.id);
}
@override
@ -171,8 +154,4 @@ class WyreBuyProvider extends BuyProvider {
// TODO: implement launchProvider
throw UnimplementedError();
}
@override
// TODO: implement sellOptionDescription
String get sellOptionDescription => throw UnimplementedError();
}
}

View file

@ -1,7 +1,7 @@
import 'package:cake_wallet/anonpay/anonpay_api.dart';
import 'package:cake_wallet/anonpay/anonpay_info_base.dart';
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
import 'package:cake_wallet/buy/moonpay/moonpay_provider.dart';
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
import 'package:cake_wallet/buy/payfura/payfura_buy_provider.dart';

View file

@ -1,112 +0,0 @@
import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/buy/dfx/dfx_buy_provider.dart';
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart';
import 'package:cake_wallet/di.dart';
import 'package:cw_core/wallet_type.dart';
enum BuyProviderType {
askEachTime,
robinhood,
dfx,
onramper,
}
extension BuyProviderTypeName on BuyProviderType {
String get name {
switch (this) {
case BuyProviderType.askEachTime:
return 'Ask each time';
case BuyProviderType.robinhood:
return 'Robinhood Connect';
case BuyProviderType.dfx:
return 'DFX Connect';
case BuyProviderType.onramper:
return 'Onramper';
default:
return this.toString().split('.').last;
}
}
String get id {
switch (this) {
case BuyProviderType.askEachTime:
return 'ask_each_time_provider';
case BuyProviderType.robinhood:
return 'robinhood_connect_provider';
case BuyProviderType.dfx:
return 'dfx_connect_provider';
case BuyProviderType.onramper:
return 'onramper_provider';
default:
return this.toString().split('.').last.replaceAll('.', '_')
.toLowerCase() + '_provider';
}
}
}
class BuyProviderHelper {
static List<BuyProviderType> getAvailableBuyProviderTypes(
WalletType walletType) {
switch (walletType) {
case WalletType.nano:
case WalletType.banano:
return [BuyProviderType.askEachTime, BuyProviderType.onramper];
case WalletType.monero:
return [
BuyProviderType.askEachTime,
BuyProviderType.onramper,
BuyProviderType.dfx
];
case WalletType.bitcoin:
case WalletType.ethereum:
return [
BuyProviderType.askEachTime,
BuyProviderType.onramper,
BuyProviderType.dfx,
BuyProviderType.robinhood
];
case WalletType.litecoin:
case WalletType.bitcoinCash:
return [
BuyProviderType.askEachTime,
BuyProviderType.onramper,
BuyProviderType.robinhood
];
default:
return [];
}
}
static List<BuyProviderType> getAvailableSellProviderTypes(
WalletType walletType) {
switch (walletType) {
case WalletType.nano:
case WalletType.banano:
return [BuyProviderType.askEachTime];
case WalletType.monero:
return [BuyProviderType.askEachTime, BuyProviderType.dfx];
case WalletType.bitcoin:
case WalletType.ethereum:
return [BuyProviderType.askEachTime, BuyProviderType.dfx];
case WalletType.litecoin:
case WalletType.bitcoinCash:
return [BuyProviderType.askEachTime];
default:
return [];
}
}
static BuyProvider? getProviderByType(BuyProviderType type) {
switch (type) {
case BuyProviderType.robinhood:
return getIt.get<RobinhoodBuyProvider>();
case BuyProviderType.dfx:
return getIt.get<DFXBuyProvider>();
case BuyProviderType.onramper:
return getIt.get<OnRamperBuyProvider>();
case BuyProviderType.askEachTime:
return null;
}
}
}

View file

@ -37,8 +37,6 @@ class MainActions {
canShow: (viewModel) => viewModel.hasBuyAction,
onTap: (BuildContext context, DashboardViewModel viewModel) async {
if (!viewModel.isEnabledBuyAction) {
await _showErrorDialog(
context, S.of(context).buy, S.of(context).unsupported_asset);
return;
}
@ -88,8 +86,6 @@ class MainActions {
canShow: (viewModel) => viewModel.hasSellAction,
onTap: (BuildContext context, DashboardViewModel viewModel) async {
if (!viewModel.isEnabledSellAction) {
await _showErrorDialog(
context, S.of(context).sell, S.of(context).unsupported_asset);
return;
}

View file

@ -0,0 +1,108 @@
import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/buy/dfx/dfx_buy_provider.dart';
import 'package:cake_wallet/buy/moonpay/moonpay_provider.dart';
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart';
import 'package:cake_wallet/di.dart';
import 'package:cw_core/wallet_type.dart';
enum ProviderType {
askEachTime,
robinhood,
dfx,
onramper,
moonpaySell,
}
extension ProviderTypeName on ProviderType {
String get title {
switch (this) {
case ProviderType.askEachTime:
return 'Ask each time';
case ProviderType.robinhood:
return 'Robinhood Connect';
case ProviderType.dfx:
return 'DFX Connect';
case ProviderType.onramper:
return 'Onramper';
case ProviderType.moonpaySell:
return 'MoonPay';
}
}
String get id {
switch (this) {
case ProviderType.askEachTime:
return 'ask_each_time_provider';
case ProviderType.robinhood:
return 'robinhood_connect_provider';
case ProviderType.dfx:
return 'dfx_connect_provider';
case ProviderType.onramper:
return 'onramper_provider';
case ProviderType.moonpaySell:
return 'moonpay_provider';
}
}
}
class ProvidersHelper {
static List<ProviderType> getAvailableBuyProviderTypes(WalletType walletType) {
switch (walletType) {
case WalletType.nano:
case WalletType.banano:
return [ProviderType.askEachTime, ProviderType.onramper];
case WalletType.monero:
return [ProviderType.askEachTime, ProviderType.onramper, ProviderType.dfx];
case WalletType.bitcoin:
case WalletType.ethereum:
return [
ProviderType.askEachTime,
ProviderType.onramper,
ProviderType.dfx,
ProviderType.robinhood,
];
case WalletType.litecoin:
case WalletType.bitcoinCash:
return [ProviderType.askEachTime, ProviderType.onramper, ProviderType.robinhood];
case WalletType.none:
case WalletType.haven:
case WalletType.polygon:
return [];
}
}
static List<ProviderType> getAvailableSellProviderTypes(WalletType walletType) {
switch (walletType) {
case WalletType.monero:
return [ProviderType.askEachTime, ProviderType.dfx];
case WalletType.bitcoin:
case WalletType.ethereum:
return [ProviderType.askEachTime, ProviderType.moonpaySell, ProviderType.dfx];
case WalletType.litecoin:
case WalletType.bitcoinCash:
return [ProviderType.askEachTime, ProviderType.moonpaySell];
case WalletType.nano:
case WalletType.banano:
case WalletType.none:
case WalletType.haven:
case WalletType.polygon:
return [];
}
}
static BuyProvider? getProviderByType(ProviderType type) {
switch (type) {
case ProviderType.robinhood:
return getIt.get<RobinhoodBuyProvider>();
case ProviderType.dfx:
return getIt.get<DFXBuyProvider>();
case ProviderType.onramper:
return getIt.get<OnRamperBuyProvider>();
case ProviderType.askEachTime:
return null;
case ProviderType.moonpaySell:
return getIt.get<MoonPaySellProvider>();
}
}
}

View file

@ -1,5 +1,3 @@
import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/entities/buy_provider_types.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/option_tile.dart';
@ -22,8 +20,7 @@ class BuySellOptionsPage extends BasePage {
@override
Widget body(BuildContext context) {
final isLightMode =
Theme.of(context).extension<OptionTileTheme>()?.useDarkImage ?? false;
final isLightMode = Theme.of(context).extension<OptionTileTheme>()?.useDarkImage ?? false;
final availableProviders = isBuyAction
? dashboardViewModel.availableBuyProviders
: dashboardViewModel.availableSellProviders;
@ -46,31 +43,26 @@ class BuySellOptionsPage extends BasePage {
child: OptionTile(
image: icon,
title: provider.toString(),
description: isBuyAction
? provider.buyOptionDescription
: provider.sellOptionDescription,
onPressed: () =>
provider.launchProvider(context, isBuyAction),
description: provider.providerDescription,
onPressed: () => provider.launchProvider(context, isBuyAction),
),
);
}).toList(),
Spacer(),
Padding(
padding: EdgeInsets.fromLTRB(24, 24, 24, 32),
child: Text(
isBuyAction
? S.of(context).select_buy_provider_notice
: S.of(context).select_sell_provider_notice,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Theme.of(context)
.extension<TransactionTradeTheme>()!
.detailsTitlesColor,
),
Padding(
padding: EdgeInsets.fromLTRB(24, 24, 24, 32),
child: Text(
isBuyAction
? S.of(context).select_buy_provider_notice
: S.of(context).select_sell_provider_notice,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
),
),
),
],
),
),

View file

@ -1,7 +1,7 @@
import 'dart:async';
import 'dart:io';
import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
import 'package:cake_wallet/buy/moonpay/moonpay_provider.dart';
import 'package:cake_wallet/buy/wyre/wyre_buy_provider.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/palette.dart';

View file

@ -29,7 +29,7 @@ class BuyListItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
final isSelected = selectedProvider?.buyOptionDescription == provider.buyOptionDescription;
final isSelected = selectedProvider?.providerDescription == provider.providerDescription;
final iconColor = isSelected ? Colors.white : Colors.black;
final providerIcon = Image.asset('assets/images/wyre-icon.png', width: 36, height: 36);

View file

@ -299,7 +299,8 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
}
void transactionStatePopup() {
showPopUp<void>(
if (this.mounted) {
showPopUp<void>(
context: context,
builder: (BuildContext popupContext) {
return Observer(builder: (_) {
@ -344,7 +345,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
onPressed: () {
Navigator.of(popupContext).pop();
RequestReviewHandler.requestReview();
},
},
text: S.of(popupContext).got_it,
color: Theme.of(popupContext).primaryColor,
textColor: Colors.white))
@ -391,5 +392,6 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
);
});
});
}
}
}

View file

@ -1,6 +1,5 @@
import 'package:cake_wallet/entities/wallet_list_order_types.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/filter_list_widget.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/filter_widget.dart';
import 'package:cake_wallet/src/screens/wallet_list/filtered_list.dart';
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
import 'package:cake_wallet/core/auth_service.dart';
@ -335,7 +334,9 @@ class WalletListBodyState extends State<WalletListBody> {
// in desktop platforms the navigation tree is different
if (responsiveLayoutUtil.shouldRenderMobileUI) {
WidgetsBinding.instance.addPostFrameCallback((_) {
Navigator.of(context).pop();
if (this.mounted) {
Navigator.of(context).pop();
}
});
}
} catch (e) {

View file

@ -4,7 +4,7 @@ import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
import 'package:cake_wallet/entities/buy_provider_types.dart';
import 'package:cake_wallet/entities/provider_types.dart';
import 'package:cake_wallet/entities/cake_2fa_preset_options.dart';
import 'package:cake_wallet/entities/background_tasks.dart';
import 'package:cake_wallet/entities/exchange_api_mode.dart';
@ -149,8 +149,8 @@ abstract class SettingsStoreBase with Store {
currentSyncMode = initialSyncMode,
currentSyncAll = initialSyncAll,
priority = ObservableMap<WalletType, TransactionPriority>(),
defaultBuyProviders = ObservableMap<WalletType, BuyProviderType>(),
defaultSellProviders = ObservableMap<WalletType, BuyProviderType>() {
defaultBuyProviders = ObservableMap<WalletType, ProviderType>(),
defaultSellProviders = ObservableMap<WalletType, ProviderType>() {
//this.nodes = ObservableMap<WalletType, Node>.of(nodes);
if (initialMoneroTransactionPriority != null) {
@ -187,10 +187,10 @@ abstract class SettingsStoreBase with Store {
final key = 'buyProvider_${walletType.toString()}';
final providerId = sharedPreferences.getString(key);
if (providerId != null) {
defaultBuyProviders[walletType] = BuyProviderType.values
.firstWhere((provider) => provider.id == providerId, orElse: () => BuyProviderType.askEachTime);
defaultBuyProviders[walletType] = ProviderType.values
.firstWhere((provider) => provider.id == providerId, orElse: () => ProviderType.askEachTime);
} else {
defaultBuyProviders[walletType] = BuyProviderType.askEachTime;
defaultBuyProviders[walletType] = ProviderType.askEachTime;
}
});
@ -198,10 +198,10 @@ abstract class SettingsStoreBase with Store {
final key = 'sellProvider_${walletType.toString()}';
final providerId = sharedPreferences.getString(key);
if (providerId != null) {
defaultSellProviders[walletType] = BuyProviderType.values
.firstWhere((provider) => provider.id == providerId, orElse: () => BuyProviderType.askEachTime);
defaultSellProviders[walletType] = ProviderType.values
.firstWhere((provider) => provider.id == providerId, orElse: () => ProviderType.askEachTime);
} else {
defaultSellProviders[walletType] = BuyProviderType.askEachTime;
defaultSellProviders[walletType] = ProviderType.askEachTime;
}
});
@ -617,10 +617,10 @@ abstract class SettingsStoreBase with Store {
ObservableMap<String, bool> trocadorProviderStates = ObservableMap<String, bool>();
@observable
ObservableMap<WalletType, BuyProviderType> defaultBuyProviders;
ObservableMap<WalletType, ProviderType> defaultBuyProviders;
@observable
ObservableMap<WalletType, BuyProviderType> defaultSellProviders;
ObservableMap<WalletType, ProviderType> defaultSellProviders;
@observable
SortBalanceBy sortBalanceBy;

View file

@ -1,5 +1,5 @@
import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
import 'package:cake_wallet/buy/moonpay/moonpay_provider.dart';
import 'package:cake_wallet/buy/wyre/wyre_buy_provider.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/entities/fiat_currency.dart';

View file

@ -4,7 +4,7 @@ import 'package:cake_wallet/buy/buy_provider.dart';
import 'package:cake_wallet/core/key_service.dart';
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
import 'package:cake_wallet/entities/balance_display_mode.dart';
import 'package:cake_wallet/entities/buy_provider_types.dart';
import 'package:cake_wallet/entities/provider_types.dart';
import 'package:cake_wallet/entities/exchange_api_mode.dart';
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/generated/i18n.dart';
@ -42,7 +42,7 @@ import 'package:cw_core/wallet_type.dart';
import 'package:eth_sig_util/util/utils.dart';
import 'package:flutter/services.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/entities/buy_provider_types.dart';
import 'package:cake_wallet/entities/provider_types.dart';
part 'dashboard_view_model.g.dart';
@ -297,27 +297,27 @@ abstract class DashboardViewModelBase with Store {
Map<String, List<FilterItem>> filterItems;
BuyProvider? get defaultBuyProvider => BuyProviderHelper.getProviderByType(
settingsStore.defaultBuyProviders[wallet.type] ?? BuyProviderType.askEachTime);
BuyProvider? get defaultBuyProvider => ProvidersHelper.getProviderByType(
settingsStore.defaultBuyProviders[wallet.type] ?? ProviderType.askEachTime);
BuyProvider? get defaultSellProvider => BuyProviderHelper.getProviderByType(
settingsStore.defaultSellProviders[wallet.type] ?? BuyProviderType.askEachTime);
BuyProvider? get defaultSellProvider => ProvidersHelper.getProviderByType(
settingsStore.defaultSellProviders[wallet.type] ?? ProviderType.askEachTime);
bool get isBuyEnabled => settingsStore.isBitcoinBuyEnabled;
List<BuyProvider> get availableBuyProviders {
final providerTypes = BuyProviderHelper.getAvailableBuyProviderTypes(wallet.type);
final providerTypes = ProvidersHelper.getAvailableBuyProviderTypes(wallet.type);
return providerTypes
.map((type) => BuyProviderHelper.getProviderByType(type))
.map((type) => ProvidersHelper.getProviderByType(type))
.where((provider) => provider != null)
.cast<BuyProvider>()
.toList();
}
List<BuyProvider> get availableSellProviders {
final providerTypes = BuyProviderHelper.getAvailableSellProviderTypes(wallet.type);
final providerTypes = ProvidersHelper.getAvailableSellProviderTypes(wallet.type);
return providerTypes
.map((type) => BuyProviderHelper.getProviderByType(type))
.map((type) => ProvidersHelper.getProviderByType(type))
.where((provider) => provider != null)
.cast<BuyProvider>()
.toList();

View file

@ -9,7 +9,7 @@ import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.d
import 'package:cake_wallet/src/screens/trade_details/track_trade_list_item.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
import 'package:cake_wallet/buy/moonpay/moonpay_provider.dart';
import 'package:cake_wallet/buy/wyre/wyre_buy_provider.dart';
part 'order_details_view_model.g.dart';

View file

@ -1,5 +1,5 @@
import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/entities/buy_provider_types.dart';
import 'package:cake_wallet/entities/provider_types.dart';
import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/store/settings_store.dart';
@ -64,20 +64,20 @@ abstract class OtherSettingsViewModelBase with Store {
bool get isEnabledSellAction =>
!_settingsStore.disableSell && _wallet.type != WalletType.haven;
List<BuyProviderType> get availableBuyProvidersTypes {
return BuyProviderHelper.getAvailableBuyProviderTypes(walletType);
List<ProviderType> get availableBuyProvidersTypes {
return ProvidersHelper.getAvailableBuyProviderTypes(walletType);
}
List<BuyProviderType> get availableSellProvidersTypes =>
BuyProviderHelper.getAvailableSellProviderTypes(walletType);
List<ProviderType> get availableSellProvidersTypes =>
ProvidersHelper.getAvailableSellProviderTypes(walletType);
BuyProviderType get buyProviderType =>
ProviderType get buyProviderType =>
_settingsStore.defaultBuyProviders[walletType] ??
BuyProviderType.askEachTime;
ProviderType.askEachTime;
BuyProviderType get sellProviderType =>
ProviderType get sellProviderType =>
_settingsStore.defaultSellProviders[walletType] ??
BuyProviderType.askEachTime;
ProviderType.askEachTime;
String getDisplayPriority(dynamic priority) {
final _priority = priority as TransactionPriority;
@ -93,28 +93,28 @@ abstract class OtherSettingsViewModelBase with Store {
}
String getBuyProviderType(dynamic buyProviderType) {
final _buyProviderType = buyProviderType as BuyProviderType;
return _buyProviderType == BuyProviderType.askEachTime
final _buyProviderType = buyProviderType as ProviderType;
return _buyProviderType == ProviderType.askEachTime
? S.current.ask_each_time
: _buyProviderType.name;
: _buyProviderType.title;
}
String getSellProviderType(dynamic sellProviderType) {
final _sellProviderType = sellProviderType as BuyProviderType;
return _sellProviderType == BuyProviderType.askEachTime
final _sellProviderType = sellProviderType as ProviderType;
return _sellProviderType == ProviderType.askEachTime
? S.current.ask_each_time
: _sellProviderType.name;
: _sellProviderType.title;
}
void onDisplayPrioritySelected(TransactionPriority priority) =>
_settingsStore.priority[_wallet.type] = priority;
@action
BuyProviderType onBuyProviderTypeSelected(BuyProviderType buyProviderType) =>
ProviderType onBuyProviderTypeSelected(ProviderType buyProviderType) =>
_settingsStore.defaultBuyProviders[walletType] = buyProviderType;
@action
BuyProviderType onSellProviderTypeSelected(
BuyProviderType sellProviderType) =>
ProviderType onSellProviderTypeSelected(
ProviderType sellProviderType) =>
_settingsStore.defaultSellProviders[walletType] = sellProviderType;
}

View file

@ -22,6 +22,7 @@ abstract class WalletListViewModelBase with Store {
) : wallets = ObservableList<WalletListItem>() {
setOrderType(_appStore.settingsStore.walletListOrder);
reaction((_) => _appStore.wallet, (_) => updateList());
updateList();
}
@observable