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
Omar Hatem committed
Jan 1, 2024 at 15:05 UTC
133fa2987a48fd1f6ac77dd57c202f64a6d75619
23 files changed
+270
-313
cw_ethereum/lib/ethereum_wallet_service.dart
+3
-8
@@ -20,12 +20,7 @@ class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
20
21
@override
22
Future<EthereumWallet> create(EthereumNewWalletCredentials credentials) async {
23
-
24
- final strength = (credentials.seedPhraseLength == 12)
25
- ? 128
26
- : (credentials.seedPhraseLength == 24)
27
- ? 256
28
- : 128;
23
+ final strength = credentials.seedPhraseLength == 24 ? 256 : 128;
24
25
final mnemonic = bip39.generateMnemonic(strength: strength);
26
final wallet = EthereumWallet(
@@ -67,8 +62,8 @@ class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
62
@override
63
Future<void> remove(String wallet) async {
64
File(await pathForWalletDir(name: wallet, type: getType())).delete(recursive: true);
70
- final walletInfo = walletInfoSource.values.firstWhereOrNull(
71
- (info) => info.id == WalletBase.idFor(wallet, getType()))!;
65
+ final walletInfo = walletInfoSource.values
66
+ .firstWhereOrNull((info) => info.id == WalletBase.idFor(wallet, getType()))!;
67
await walletInfoSource.delete(walletInfo.key);
68
}
69
cw_polygon/lib/polygon_wallet_service.dart
+1
-5
@@ -20,11 +20,7 @@ class PolygonWalletService extends WalletService<PolygonNewWalletCredentials,
20
21
@override
22
Future<PolygonWallet> create(PolygonNewWalletCredentials credentials) async {
23
- final strength = (credentials.seedPhraseLength == 12)
24
- ? 128
25
- : (credentials.seedPhraseLength == 24)
26
- ? 256
27
- : 128;
23
+ final strength = credentials.seedPhraseLength == 24 ? 256 : 128;
24
25
final mnemonic = bip39.generateMnemonic(strength: strength);
26
final wallet = PolygonWallet(
lib/buy/buy_provider.dart
+1
-3
@@ -14,9 +14,7 @@ abstract class BuyProvider {
14
15
String get title;
16
17
- String get buyOptionDescription;
18
-
19
- String get sellOptionDescription;
17
+ String get providerDescription;
18
19
String get lightIcon;
20
lib/buy/dfx/dfx_buy_provider.dart
+2
-4
@@ -26,10 +26,7 @@ class DFXBuyProvider extends BuyProvider {
26
String get title => 'DFX Connect';
27
28
@override
29
- String get buyOptionDescription => S.current.dfx_option_description;
30
-
31
- @override
32
- String get sellOptionDescription => S.current.dfx_option_description;
29
+ String get providerDescription => S.current.dfx_option_description;
30
31
@override
32
String get lightIcon => 'assets/images/dfx_light.png';
@@ -152,6 +149,7 @@ class DFXBuyProvider extends BuyProvider {
149
}
150
}
151
152
+ @override
153
Future<void> launchProvider(BuildContext context, bool? isBuyAction) async {
154
try {
155
final assetOut = this.assetOut;
lib/buy/moonpay/moonpay_provider.dart
renamed
+68
-54
@@ -21,19 +21,33 @@ import 'package:cake_wallet/.secrets.g.dart' as secrets;
21
import 'package:cw_core/crypto_currency.dart';
22
import 'package:url_launcher/url_launcher.dart';
23
24
-class MoonPaySellProvider {
25
- MoonPaySellProvider({required SettingsStore settingsStore,
26
- required WalletBase wallet, this.isTest = false})
27
- : baseUrl = isTest ? _baseTestUrl : _baseProductUrl,
24
+class MoonPaySellProvider extends BuyProvider {
25
+ MoonPaySellProvider({
26
+ required SettingsStore settingsStore,
27
+ required WalletBase wallet,
28
+ bool isTestEnvironment = false,
29
+ }) : baseUrl = isTestEnvironment ? _baseTestUrl : _baseProductUrl,
30
this._settingsStore = settingsStore,
29
- this._wallet = wallet;
31
+ super(wallet: wallet, isTestEnvironment: isTestEnvironment);
32
33
final SettingsStore _settingsStore;
32
- final WalletBase _wallet;
34
35
static const _baseTestUrl = 'sell-sandbox.moonpay.com';
36
static const _baseProductUrl = 'sell.moonpay.com';
37
38
+ @override
39
+ String get providerDescription =>
40
+ 'MoonPay offers a fast and simple way to buy and sell cryptocurrencies';
41
+
42
+ @override
43
+ String get title => 'MoonPay';
44
+
45
+ @override
46
+ String get lightIcon => 'assets/images/moonpay_light.png';
47
+
48
+ @override
49
+ String get darkIcon => 'assets/images/moonpay_dark.png';
50
+
51
static String themeToMoonPayTheme(ThemeBase theme) {
52
switch (theme.type) {
53
case ThemeType.bright:
@@ -45,11 +59,11 @@ class MoonPaySellProvider {
59
}
60
61
static String get _apiKey => secrets.moonPayApiKey;
62
+
63
static String get _secretKey => secrets.moonPaySecretKey;
49
- final bool isTest;
64
final String baseUrl;
65
52
- Future<Uri> requestUrl({
66
+ Future<Uri> requestMoonPayUrl({
67
required CryptoCurrency currency,
68
required String refundWalletAddress,
69
required SettingsStore settingsStore,
@@ -78,7 +92,7 @@ class MoonPaySellProvider {
92
final digest = hmac.convert(messageBytes);
93
final signature = base64.encode(digest.bytes);
94
81
- if (isTest) {
95
+ if (isTestEnvironment) {
96
return originalUri;
97
}
98
@@ -88,11 +102,12 @@ class MoonPaySellProvider {
102
return signedUri;
103
}
104
91
- Future<void> launchProvider(BuildContext context) async {
105
+ @override
106
+ Future<void> launchProvider(BuildContext context, bool? isBuyAction) async {
107
try {
93
- final uri = await requestUrl(
94
- currency: _wallet.currency,
95
- refundWalletAddress: _wallet.walletAddresses.address,
108
+ final uri = await requestMoonPayUrl(
109
+ currency: wallet.currency,
110
+ refundWalletAddress: wallet.walletAddresses.address,
111
settingsStore: _settingsStore,
112
);
113
@@ -137,35 +152,43 @@ class MoonPayBuyProvider extends BuyProvider {
152
static const _secretKey = secrets.moonPaySecretKey;
153
154
@override
140
- String get title => 'Moon Pay';
155
+ String get title => 'MoonPay';
156
157
@override
143
- String get buyOptionDescription => '';
158
+ String get providerDescription =>
159
+ 'MoonPay offers a fast and simple way to buy and sell cryptocurrencies';
160
161
@override
162
String get lightIcon => 'assets/images/moonpay_light.png';
163
164
@override
165
String get darkIcon => 'assets/images/moonpay_dark.png';
150
-
151
- String get currencyCode =>
152
- walletTypeToCryptoCurrency(wallet.type).title.toLowerCase();
166
+
167
+ String get currencyCode => walletTypeToCryptoCurrency(wallet.type).title.toLowerCase();
168
169
String get trackUrl => baseUrl + '/transaction_receipt?transactionId=';
170
171
String baseUrl;
172
173
Future<String> requestUrl(String amount, String sourceCurrency) async {
159
- final enabledPaymentMethods =
160
- 'credit_debit_card%2Capple_pay%2Cgoogle_pay%2Csamsung_pay'
174
+ final enabledPaymentMethods = 'credit_debit_card%2Capple_pay%2Cgoogle_pay%2Csamsung_pay'
175
'%2Csepa_bank_transfer%2Cgbp_bank_transfer%2Cgbp_open_banking_payment';
176
163
- final suffix = '?apiKey=' + _apiKey + '¤cyCode=' +
164
- currencyCode + '&enabledPaymentMethods=' + enabledPaymentMethods +
165
- '&walletAddress=' + wallet.walletAddresses.address +
166
- '&baseCurrencyCode=' + sourceCurrency.toLowerCase() +
167
- '&baseCurrencyAmount=' + amount + '&lockAmount=true' +
168
- '&showAllCurrencies=false' + '&showWalletAddressForm=false';
177
+ final suffix = '?apiKey=' +
178
+ _apiKey +
179
+ '¤cyCode=' +
180
+ currencyCode +
181
+ '&enabledPaymentMethods=' +
182
+ enabledPaymentMethods +
183
+ '&walletAddress=' +
184
+ wallet.walletAddresses.address +
185
+ '&baseCurrencyCode=' +
186
+ sourceCurrency.toLowerCase() +
187
+ '&baseCurrencyAmount=' +
188
+ amount +
189
+ '&lockAmount=true' +
190
+ '&showAllCurrencies=false' +
191
+ '&showWalletAddressForm=false';
192
193
final originalUrl = baseUrl + suffix;
194
@@ -174,24 +197,27 @@ class MoonPayBuyProvider extends BuyProvider {
197
final hmac = Hmac(sha256, key);
198
final digest = hmac.convert(messageBytes);
199
final signature = base64.encode(digest.bytes);
177
- final urlWithSignature = originalUrl +
178
- '&signature=${Uri.encodeComponent(signature)}';
200
+ final urlWithSignature = originalUrl + '&signature=${Uri.encodeComponent(signature)}';
201
202
return isTestEnvironment ? originalUrl : urlWithSignature;
203
}
204
205
Future<BuyAmount> calculateAmount(String amount, String sourceCurrency) async {
184
- final url = _apiUrl + _currenciesSuffix + '/$currencyCode' +
185
- _quoteSuffix + '/?apiKey=' + _apiKey +
186
- '&baseCurrencyAmount=' + amount +
187
- '&baseCurrencyCode=' + sourceCurrency.toLowerCase();
206
+ final url = _apiUrl +
207
+ _currenciesSuffix +
208
+ '/$currencyCode' +
209
+ _quoteSuffix +
210
+ '/?apiKey=' +
211
+ _apiKey +
212
+ '&baseCurrencyAmount=' +
213
+ amount +
214
+ '&baseCurrencyCode=' +
215
+ sourceCurrency.toLowerCase();
216
final uri = Uri.parse(url);
217
final response = await get(uri);
218
219
if (response.statusCode != 200) {
192
- throw BuyException(
193
- title: buyOptionDescription,
194
- content: 'Quote is not found!');
220
+ throw BuyException(title: providerDescription, content: 'Quote is not found!');
221
}
222
223
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
@@ -200,21 +226,16 @@ class MoonPayBuyProvider extends BuyProvider {
226
final minSourceAmount = responseJSON['baseCurrency']['minAmount'] as int;
227
228
return BuyAmount(
203
- sourceAmount: sourceAmount,
204
- destAmount: destAmount,
205
- minAmount: minSourceAmount);
229
+ sourceAmount: sourceAmount, destAmount: destAmount, minAmount: minSourceAmount);
230
}
231
232
Future<Order> findOrderById(String id) async {
209
- final url = _apiUrl + _transactionsSuffix + '/$id' +
210
- '?apiKey=' + _apiKey;
233
+ final url = _apiUrl + _transactionsSuffix + '/$id' + '?apiKey=' + _apiKey;
234
final uri = Uri.parse(url);
235
final response = await get(uri);
236
237
if (response.statusCode != 200) {
215
- throw BuyException(
216
- title: buyOptionDescription,
217
- content: 'Transaction $id is not found!');
238
+ throw BuyException(title: providerDescription, content: 'Transaction $id is not found!');
239
}
240
241
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
@@ -232,8 +253,7 @@ class MoonPayBuyProvider extends BuyProvider {
253
createdAt: createdAt,
254
amount: amount.toString(),
255
receiveAddress: wallet.walletAddresses.address,
235
- walletId: wallet.id
236
- );
256
+ walletId: wallet.id);
257
}
258
259
static Future<bool> onEnabled() async {
@@ -254,12 +274,6 @@ class MoonPayBuyProvider extends BuyProvider {
274
}
275
276
@override
257
- // TODO: implement sellOptionDescription
258
- String get sellOptionDescription => throw UnimplementedError();
259
-
260
- @override
261
- Future<void> launchProvider(BuildContext context, bool? isBuyAction) {
262
- // TODO: implement launchProvider
263
- throw UnimplementedError();
264
- }
265
-}
\ No newline at end of file
277
+ Future<void> launchProvider(BuildContext context, bool? isBuyAction) =>
278
+ throw UnimplementedError();
279
+}
lib/buy/onramper/onramper_buy_provider.dart
+1
-4
@@ -23,10 +23,7 @@ class OnRamperBuyProvider extends BuyProvider {
23
String get title => 'Onramper';
24
25
@override
26
- String get buyOptionDescription => S.current.onramper_option_description;
27
-
28
- @override
29
- String get sellOptionDescription => S.current.onramper_option_description;
26
+ String get providerDescription => S.current.onramper_option_description;
27
28
@override
29
String get lightIcon => 'assets/images/onramper_light.png';
lib/buy/robinhood/robinhood_buy_provider.dart
+2
-10
@@ -1,10 +1,7 @@
1
import 'dart:convert';
2
3
import 'package:cake_wallet/.secrets.g.dart' as secrets;
4
-import 'package:cake_wallet/buy/buy_amount.dart';
4
import 'package:cake_wallet/buy/buy_provider.dart';
6
-import 'package:cake_wallet/buy/buy_provider_description.dart';
7
-import 'package:cake_wallet/buy/order.dart';
5
import 'package:cake_wallet/generated/i18n.dart';
6
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
7
import 'package:cake_wallet/utils/show_pop_up.dart';
@@ -14,22 +11,18 @@ import 'package:flutter/material.dart';
11
import 'package:http/http.dart' as http;
12
import 'package:url_launcher/url_launcher.dart';
13
17
-class RobinhoodBuyProvider extends BuyProvider{
14
+class RobinhoodBuyProvider extends BuyProvider {
15
RobinhoodBuyProvider({required WalletBase wallet, bool isTestEnvironment = false})
16
: super(wallet: wallet, isTestEnvironment: isTestEnvironment);
17
18
static const _baseUrl = 'applink.robinhood.com';
19
static const _cIdBaseUrl = 'exchange-helper.cakewallet.com';
20
24
-
21
@override
22
String get title => 'Robinhood Connect';
23
24
@override
29
- String get buyOptionDescription => S.current.robinhood_option_description;
30
-
31
- @override
32
- String get sellOptionDescription => S.current.robinhood_option_description;
25
+ String get providerDescription => S.current.robinhood_option_description;
26
27
@override
28
String get lightIcon => 'assets/images/robinhood_light.png';
@@ -105,5 +98,4 @@ class RobinhoodBuyProvider extends BuyProvider{
98
});
99
}
100
}
108
-
101
}
lib/buy/wyre/wyre_buy_provider.dart
+17
-38
@@ -13,10 +13,8 @@ import 'package:cake_wallet/.secrets.g.dart' as secrets;
13
14
class WyreBuyProvider extends BuyProvider {
15
WyreBuyProvider({required WalletBase wallet, bool isTestEnvironment = false})
16
- : baseApiUrl = isTestEnvironment
17
- ? _baseTestApiUrl
18
- : _baseProductApiUrl,
19
- super(wallet: wallet, isTestEnvironment: isTestEnvironment);
16
+ : baseApiUrl = isTestEnvironment ? _baseTestApiUrl : _baseProductApiUrl,
17
+ super(wallet: wallet, isTestEnvironment: isTestEnvironment);
18
19
static const _baseTestApiUrl = 'https://api.testwyre.com';
20
static const _baseProductApiUrl = 'https://api.sendwyre.com';
@@ -36,7 +34,7 @@ class WyreBuyProvider extends BuyProvider {
34
String get title => 'Wyre';
35
36
@override
39
- String get buyOptionDescription => '';
37
+ String get providerDescription => '';
38
39
@override
40
String get lightIcon => 'assets/images/robinhood_light.png';
@@ -44,16 +42,13 @@ class WyreBuyProvider extends BuyProvider {
42
@override
43
String get darkIcon => 'assets/images/robinhood_dark.png';
44
47
- String get trackUrl => isTestEnvironment
48
- ? _trackTestUrl
49
- : _trackProductUrl;
45
+ String get trackUrl => isTestEnvironment ? _trackTestUrl : _trackProductUrl;
46
47
String baseApiUrl;
48
49
Future<String> requestUrl(String amount, String sourceCurrency) async {
50
final timestamp = DateTime.now().millisecondsSinceEpoch.toString();
55
- final url = baseApiUrl + _ordersSuffix + _reserveSuffix +
56
- _timeStampSuffix + timestamp;
51
+ final url = baseApiUrl + _ordersSuffix + _reserveSuffix + _timeStampSuffix + timestamp;
52
final uri = Uri.parse(url);
53
final body = {
54
'amount': amount,
@@ -72,9 +67,7 @@ class WyreBuyProvider extends BuyProvider {
67
body: json.encode(body));
68
69
if (response.statusCode != 200) {
75
- throw BuyException(
76
- title: buyOptionDescription,
77
- content: 'Url $url is not found!');
70
+ throw BuyException(title: providerDescription, content: 'Url $url is not found!');
71
}
72
73
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
@@ -102,9 +95,7 @@ class WyreBuyProvider extends BuyProvider {
95
body: json.encode(body));
96
97
if (response.statusCode != 200) {
105
- throw BuyException(
106
- title: buyOptionDescription,
107
- content: 'Quote is not found!');
98
+ throw BuyException(title: providerDescription, content: 'Quote is not found!');
99
}
100
101
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
@@ -112,7 +103,8 @@ class WyreBuyProvider extends BuyProvider {
103
final destAmount = responseJSON['destAmount'] as double;
104
final achAmount = responseJSON['sourceAmountWithoutFees'] as double;
105
115
- return BuyAmount(sourceAmount: sourceAmount, destAmount: destAmount, achSourceAmount: achAmount);
106
+ return BuyAmount(
107
+ sourceAmount: sourceAmount, destAmount: destAmount, achSourceAmount: achAmount);
108
}
109
110
Future<Order> findOrderById(String id) async {
@@ -121,35 +113,27 @@ class WyreBuyProvider extends BuyProvider {
113
final orderResponse = await get(orderUri);
114
115
if (orderResponse.statusCode != 200) {
124
- throw BuyException(
125
- title: buyOptionDescription,
126
- content: 'Order $id is not found!');
116
+ throw BuyException(title: providerDescription, content: 'Order $id is not found!');
117
}
118
129
- final orderResponseJSON =
130
- json.decode(orderResponse.body) as Map<String, dynamic>;
119
+ final orderResponseJSON = json.decode(orderResponse.body) as Map<String, dynamic>;
120
final transferId = orderResponseJSON['transferId'] as String;
121
final from = orderResponseJSON['sourceCurrency'] as String;
122
final to = orderResponseJSON['destCurrency'] as String;
123
final status = orderResponseJSON['status'] as String;
124
final state = TradeState.deserialize(raw: status.toLowerCase());
125
final createdAtRaw = orderResponseJSON['createdAt'] as int;
137
- final createdAt =
138
- DateTime.fromMillisecondsSinceEpoch(createdAtRaw).toLocal();
126
+ final createdAt = DateTime.fromMillisecondsSinceEpoch(createdAtRaw).toLocal();
127
140
- final transferUrl =
141
- baseApiUrl + _transferSuffix + transferId + _trackSuffix;
128
+ final transferUrl = baseApiUrl + _transferSuffix + transferId + _trackSuffix;
129
final transferUri = Uri.parse(transferUrl);
130
final transferResponse = await get(transferUri);
131
132
if (transferResponse.statusCode != 200) {
146
- throw BuyException(
147
- title: buyOptionDescription,
148
- content: 'Transfer $transferId is not found!');
133
+ throw BuyException(title: providerDescription, content: 'Transfer $transferId is not found!');
134
}
135
151
- final transferResponseJSON =
152
- json.decode(transferResponse.body) as Map<String, dynamic>;
136
+ final transferResponseJSON = json.decode(transferResponse.body) as Map<String, dynamic>;
137
final amount = transferResponseJSON['destAmount'] as double;
138
139
return Order(
@@ -162,8 +146,7 @@ class WyreBuyProvider extends BuyProvider {
146
createdAt: createdAt,
147
amount: amount.toString(),
148
receiveAddress: wallet.walletAddresses.address,
165
- walletId: wallet.id
166
- );
149
+ walletId: wallet.id);
150
}
151
152
@override
@@ -171,8 +154,4 @@ class WyreBuyProvider extends BuyProvider {
154
// TODO: implement launchProvider
155
throw UnimplementedError();
156
}
174
-
175
- @override
176
- // TODO: implement sellOptionDescription
177
- String get sellOptionDescription => throw UnimplementedError();
178
-}
\ No newline at end of file
157
+}
lib/di.dart
+1
-1
@@ -1,7 +1,7 @@
1
import 'package:cake_wallet/anonpay/anonpay_api.dart';
2
import 'package:cake_wallet/anonpay/anonpay_info_base.dart';
3
import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
4
-import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
4
+import 'package:cake_wallet/buy/moonpay/moonpay_provider.dart';
5
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
6
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
7
import 'package:cake_wallet/buy/payfura/payfura_buy_provider.dart';
lib/entities/buy_provider_types.dart
deleted
-112
@@ -1,112 +0,0 @@
1
-import 'package:cake_wallet/buy/buy_provider.dart';
2
-import 'package:cake_wallet/buy/dfx/dfx_buy_provider.dart';
3
-import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
4
-import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart';
5
-import 'package:cake_wallet/di.dart';
6
-import 'package:cw_core/wallet_type.dart';
7
-
8
-enum BuyProviderType {
9
- askEachTime,
10
- robinhood,
11
- dfx,
12
- onramper,
13
-}
14
-
15
-extension BuyProviderTypeName on BuyProviderType {
16
- String get name {
17
- switch (this) {
18
- case BuyProviderType.askEachTime:
19
- return 'Ask each time';
20
- case BuyProviderType.robinhood:
21
- return 'Robinhood Connect';
22
- case BuyProviderType.dfx:
23
- return 'DFX Connect';
24
- case BuyProviderType.onramper:
25
- return 'Onramper';
26
- default:
27
- return this.toString().split('.').last;
28
- }
29
- }
30
-
31
- String get id {
32
- switch (this) {
33
- case BuyProviderType.askEachTime:
34
- return 'ask_each_time_provider';
35
- case BuyProviderType.robinhood:
36
- return 'robinhood_connect_provider';
37
- case BuyProviderType.dfx:
38
- return 'dfx_connect_provider';
39
- case BuyProviderType.onramper:
40
- return 'onramper_provider';
41
- default:
42
- return this.toString().split('.').last.replaceAll('.', '_')
43
- .toLowerCase() + '_provider';
44
- }
45
- }
46
-}
47
-
48
-class BuyProviderHelper {
49
- static List<BuyProviderType> getAvailableBuyProviderTypes(
50
- WalletType walletType) {
51
- switch (walletType) {
52
- case WalletType.nano:
53
- case WalletType.banano:
54
- return [BuyProviderType.askEachTime, BuyProviderType.onramper];
55
- case WalletType.monero:
56
- return [
57
- BuyProviderType.askEachTime,
58
- BuyProviderType.onramper,
59
- BuyProviderType.dfx
60
- ];
61
- case WalletType.bitcoin:
62
- case WalletType.ethereum:
63
- return [
64
- BuyProviderType.askEachTime,
65
- BuyProviderType.onramper,
66
- BuyProviderType.dfx,
67
- BuyProviderType.robinhood
68
- ];
69
- case WalletType.litecoin:
70
- case WalletType.bitcoinCash:
71
- return [
72
- BuyProviderType.askEachTime,
73
- BuyProviderType.onramper,
74
- BuyProviderType.robinhood
75
- ];
76
- default:
77
- return [];
78
- }
79
- }
80
-
81
- static List<BuyProviderType> getAvailableSellProviderTypes(
82
- WalletType walletType) {
83
- switch (walletType) {
84
- case WalletType.nano:
85
- case WalletType.banano:
86
- return [BuyProviderType.askEachTime];
87
- case WalletType.monero:
88
- return [BuyProviderType.askEachTime, BuyProviderType.dfx];
89
- case WalletType.bitcoin:
90
- case WalletType.ethereum:
91
- return [BuyProviderType.askEachTime, BuyProviderType.dfx];
92
- case WalletType.litecoin:
93
- case WalletType.bitcoinCash:
94
- return [BuyProviderType.askEachTime];
95
- default:
96
- return [];
97
- }
98
- }
99
-
100
- static BuyProvider? getProviderByType(BuyProviderType type) {
101
- switch (type) {
102
- case BuyProviderType.robinhood:
103
- return getIt.get<RobinhoodBuyProvider>();
104
- case BuyProviderType.dfx:
105
- return getIt.get<DFXBuyProvider>();
106
- case BuyProviderType.onramper:
107
- return getIt.get<OnRamperBuyProvider>();
108
- case BuyProviderType.askEachTime:
109
- return null;
110
- }
111
- }
112
-}
lib/entities/main_actions.dart
-4
@@ -37,8 +37,6 @@ class MainActions {
37
canShow: (viewModel) => viewModel.hasBuyAction,
38
onTap: (BuildContext context, DashboardViewModel viewModel) async {
39
if (!viewModel.isEnabledBuyAction) {
40
- await _showErrorDialog(
41
- context, S.of(context).buy, S.of(context).unsupported_asset);
40
return;
41
}
42
@@ -88,8 +86,6 @@ class MainActions {
86
canShow: (viewModel) => viewModel.hasSellAction,
87
onTap: (BuildContext context, DashboardViewModel viewModel) async {
88
if (!viewModel.isEnabledSellAction) {
91
- await _showErrorDialog(
92
- context, S.of(context).sell, S.of(context).unsupported_asset);
89
return;
90
}
91
lib/entities/provider_types.dart
new
+108
@@ -0,0 +1,108 @@
1
+import 'package:cake_wallet/buy/buy_provider.dart';
2
+import 'package:cake_wallet/buy/dfx/dfx_buy_provider.dart';
3
+import 'package:cake_wallet/buy/moonpay/moonpay_provider.dart';
4
+import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
5
+import 'package:cake_wallet/buy/robinhood/robinhood_buy_provider.dart';
6
+import 'package:cake_wallet/di.dart';
7
+import 'package:cw_core/wallet_type.dart';
8
+
9
+enum ProviderType {
10
+ askEachTime,
11
+ robinhood,
12
+ dfx,
13
+ onramper,
14
+ moonpaySell,
15
+}
16
+
17
+extension ProviderTypeName on ProviderType {
18
+ String get title {
19
+ switch (this) {
20
+ case ProviderType.askEachTime:
21
+ return 'Ask each time';
22
+ case ProviderType.robinhood:
23
+ return 'Robinhood Connect';
24
+ case ProviderType.dfx:
25
+ return 'DFX Connect';
26
+ case ProviderType.onramper:
27
+ return 'Onramper';
28
+ case ProviderType.moonpaySell:
29
+ return 'MoonPay';
30
+ }
31
+ }
32
+
33
+ String get id {
34
+ switch (this) {
35
+ case ProviderType.askEachTime:
36
+ return 'ask_each_time_provider';
37
+ case ProviderType.robinhood:
38
+ return 'robinhood_connect_provider';
39
+ case ProviderType.dfx:
40
+ return 'dfx_connect_provider';
41
+ case ProviderType.onramper:
42
+ return 'onramper_provider';
43
+ case ProviderType.moonpaySell:
44
+ return 'moonpay_provider';
45
+ }
46
+ }
47
+}
48
+
49
+class ProvidersHelper {
50
+ static List<ProviderType> getAvailableBuyProviderTypes(WalletType walletType) {
51
+ switch (walletType) {
52
+ case WalletType.nano:
53
+ case WalletType.banano:
54
+ return [ProviderType.askEachTime, ProviderType.onramper];
55
+ case WalletType.monero:
56
+ return [ProviderType.askEachTime, ProviderType.onramper, ProviderType.dfx];
57
+ case WalletType.bitcoin:
58
+ case WalletType.ethereum:
59
+ return [
60
+ ProviderType.askEachTime,
61
+ ProviderType.onramper,
62
+ ProviderType.dfx,
63
+ ProviderType.robinhood,
64
+ ];
65
+ case WalletType.litecoin:
66
+ case WalletType.bitcoinCash:
67
+ return [ProviderType.askEachTime, ProviderType.onramper, ProviderType.robinhood];
68
+ case WalletType.none:
69
+ case WalletType.haven:
70
+ case WalletType.polygon:
71
+ return [];
72
+ }
73
+ }
74
+
75
+ static List<ProviderType> getAvailableSellProviderTypes(WalletType walletType) {
76
+ switch (walletType) {
77
+ case WalletType.monero:
78
+ return [ProviderType.askEachTime, ProviderType.dfx];
79
+ case WalletType.bitcoin:
80
+ case WalletType.ethereum:
81
+ return [ProviderType.askEachTime, ProviderType.moonpaySell, ProviderType.dfx];
82
+ case WalletType.litecoin:
83
+ case WalletType.bitcoinCash:
84
+ return [ProviderType.askEachTime, ProviderType.moonpaySell];
85
+ case WalletType.nano:
86
+ case WalletType.banano:
87
+ case WalletType.none:
88
+ case WalletType.haven:
89
+ case WalletType.polygon:
90
+ return [];
91
+ }
92
+ }
93
+
94
+ static BuyProvider? getProviderByType(ProviderType type) {
95
+ switch (type) {
96
+ case ProviderType.robinhood:
97
+ return getIt.get<RobinhoodBuyProvider>();
98
+ case ProviderType.dfx:
99
+ return getIt.get<DFXBuyProvider>();
100
+ case ProviderType.onramper:
101
+ return getIt.get<OnRamperBuyProvider>();
102
+ case ProviderType.askEachTime:
103
+ return null;
104
+ case ProviderType.moonpaySell:
105
+ return getIt.get<MoonPaySellProvider>();
106
+ }
107
+ }
108
+}
lib/src/screens/buy/buy_options_page.dart
+15
-23
@@ -1,5 +1,3 @@
1
-import 'package:cake_wallet/buy/buy_provider.dart';
2
-import 'package:cake_wallet/entities/buy_provider_types.dart';
1
import 'package:cake_wallet/generated/i18n.dart';
2
import 'package:cake_wallet/src/screens/base_page.dart';
3
import 'package:cake_wallet/src/widgets/option_tile.dart';
@@ -22,8 +20,7 @@ class BuySellOptionsPage extends BasePage {
20
21
@override
22
Widget body(BuildContext context) {
25
- final isLightMode =
26
- Theme.of(context).extension<OptionTileTheme>()?.useDarkImage ?? false;
23
+ final isLightMode = Theme.of(context).extension<OptionTileTheme>()?.useDarkImage ?? false;
24
final availableProviders = isBuyAction
25
? dashboardViewModel.availableBuyProviders
26
: dashboardViewModel.availableSellProviders;
@@ -46,31 +43,26 @@ class BuySellOptionsPage extends BasePage {
43
child: OptionTile(
44
image: icon,
45
title: provider.toString(),
49
- description: isBuyAction
50
- ? provider.buyOptionDescription
51
- : provider.sellOptionDescription,
52
- onPressed: () =>
53
- provider.launchProvider(context, isBuyAction),
46
+ description: provider.providerDescription,
47
+ onPressed: () => provider.launchProvider(context, isBuyAction),
48
),
49
);
50
}).toList(),
51
Spacer(),
58
- Padding(
59
- padding: EdgeInsets.fromLTRB(24, 24, 24, 32),
60
- child: Text(
61
- isBuyAction
62
- ? S.of(context).select_buy_provider_notice
63
- : S.of(context).select_sell_provider_notice,
64
- textAlign: TextAlign.center,
65
- style: TextStyle(
66
- fontSize: 14,
67
- fontWeight: FontWeight.normal,
68
- color: Theme.of(context)
69
- .extension<TransactionTradeTheme>()!
70
- .detailsTitlesColor,
71
- ),
52
+ Padding(
53
+ padding: EdgeInsets.fromLTRB(24, 24, 24, 32),
54
+ child: Text(
55
+ isBuyAction
56
+ ? S.of(context).select_buy_provider_notice
57
+ : S.of(context).select_sell_provider_notice,
58
+ textAlign: TextAlign.center,
59
+ style: TextStyle(
60
+ fontSize: 14,
61
+ fontWeight: FontWeight.normal,
62
+ color: Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
63
),
64
),
65
+ ),
66
],
67
),
68
),
lib/src/screens/buy/buy_webview_page.dart
+1
-1
@@ -1,7 +1,7 @@
1
import 'dart:async';
2
import 'dart:io';
3
import 'package:cake_wallet/buy/buy_provider.dart';
4
-import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
4
+import 'package:cake_wallet/buy/moonpay/moonpay_provider.dart';
5
import 'package:cake_wallet/buy/wyre/wyre_buy_provider.dart';
6
import 'package:cake_wallet/generated/i18n.dart';
7
import 'package:cake_wallet/palette.dart';
lib/src/screens/buy/widgets/buy_list_item.dart
+1
-1
@@ -29,7 +29,7 @@ class BuyListItem extends StatelessWidget {
29
30
@override
31
Widget build(BuildContext context) {
32
- final isSelected = selectedProvider?.buyOptionDescription == provider.buyOptionDescription;
32
+ final isSelected = selectedProvider?.providerDescription == provider.providerDescription;
33
final iconColor = isSelected ? Colors.white : Colors.black;
34
35
final providerIcon = Image.asset('assets/images/wyre-icon.png', width: 36, height: 36);
lib/src/screens/exchange_trade/exchange_trade_page.dart
+4
-2
@@ -299,7 +299,8 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
299
}
300
301
void transactionStatePopup() {
302
- showPopUp<void>(
302
+ if (this.mounted) {
303
+ showPopUp<void>(
304
context: context,
305
builder: (BuildContext popupContext) {
306
return Observer(builder: (_) {
@@ -344,7 +345,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
345
onPressed: () {
346
Navigator.of(popupContext).pop();
347
RequestReviewHandler.requestReview();
347
- },
348
+ },
349
text: S.of(popupContext).got_it,
350
color: Theme.of(popupContext).primaryColor,
351
textColor: Colors.white))
@@ -391,5 +392,6 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
392
);
393
});
394
});
395
+ }
396
}
397
}
lib/src/screens/wallet_list/wallet_list_page.dart
+3
-2
@@ -1,6 +1,5 @@
1
import 'package:cake_wallet/entities/wallet_list_order_types.dart';
2
import 'package:cake_wallet/src/screens/dashboard/widgets/filter_list_widget.dart';
3
-import 'package:cake_wallet/src/screens/dashboard/widgets/filter_widget.dart';
3
import 'package:cake_wallet/src/screens/wallet_list/filtered_list.dart';
4
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
5
import 'package:cake_wallet/core/auth_service.dart';
@@ -335,7 +334,9 @@ class WalletListBodyState extends State<WalletListBody> {
334
// in desktop platforms the navigation tree is different
335
if (responsiveLayoutUtil.shouldRenderMobileUI) {
336
WidgetsBinding.instance.addPostFrameCallback((_) {
338
- Navigator.of(context).pop();
337
+ if (this.mounted) {
338
+ Navigator.of(context).pop();
339
+ }
340
});
341
}
342
} catch (e) {
lib/store/settings_store.dart
+11
-11
@@ -4,7 +4,7 @@ import 'package:cake_wallet/bitcoin/bitcoin.dart';
4
import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
5
import 'package:cake_wallet/buy/buy_provider.dart';
6
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
7
-import 'package:cake_wallet/entities/buy_provider_types.dart';
7
+import 'package:cake_wallet/entities/provider_types.dart';
8
import 'package:cake_wallet/entities/cake_2fa_preset_options.dart';
9
import 'package:cake_wallet/entities/background_tasks.dart';
10
import 'package:cake_wallet/entities/exchange_api_mode.dart';
@@ -149,8 +149,8 @@ abstract class SettingsStoreBase with Store {
149
currentSyncMode = initialSyncMode,
150
currentSyncAll = initialSyncAll,
151
priority = ObservableMap<WalletType, TransactionPriority>(),
152
- defaultBuyProviders = ObservableMap<WalletType, BuyProviderType>(),
153
- defaultSellProviders = ObservableMap<WalletType, BuyProviderType>() {
152
+ defaultBuyProviders = ObservableMap<WalletType, ProviderType>(),
153
+ defaultSellProviders = ObservableMap<WalletType, ProviderType>() {
154
//this.nodes = ObservableMap<WalletType, Node>.of(nodes);
155
156
if (initialMoneroTransactionPriority != null) {
@@ -187,10 +187,10 @@ abstract class SettingsStoreBase with Store {
187
final key = 'buyProvider_${walletType.toString()}';
188
final providerId = sharedPreferences.getString(key);
189
if (providerId != null) {
190
- defaultBuyProviders[walletType] = BuyProviderType.values
191
- .firstWhere((provider) => provider.id == providerId, orElse: () => BuyProviderType.askEachTime);
190
+ defaultBuyProviders[walletType] = ProviderType.values
191
+ .firstWhere((provider) => provider.id == providerId, orElse: () => ProviderType.askEachTime);
192
} else {
193
- defaultBuyProviders[walletType] = BuyProviderType.askEachTime;
193
+ defaultBuyProviders[walletType] = ProviderType.askEachTime;
194
}
195
});
196
@@ -198,10 +198,10 @@ abstract class SettingsStoreBase with Store {
198
final key = 'sellProvider_${walletType.toString()}';
199
final providerId = sharedPreferences.getString(key);
200
if (providerId != null) {
201
- defaultSellProviders[walletType] = BuyProviderType.values
202
- .firstWhere((provider) => provider.id == providerId, orElse: () => BuyProviderType.askEachTime);
201
+ defaultSellProviders[walletType] = ProviderType.values
202
+ .firstWhere((provider) => provider.id == providerId, orElse: () => ProviderType.askEachTime);
203
} else {
204
- defaultSellProviders[walletType] = BuyProviderType.askEachTime;
204
+ defaultSellProviders[walletType] = ProviderType.askEachTime;
205
}
206
});
207
@@ -617,10 +617,10 @@ abstract class SettingsStoreBase with Store {
617
ObservableMap<String, bool> trocadorProviderStates = ObservableMap<String, bool>();
618
619
@observable
620
- ObservableMap<WalletType, BuyProviderType> defaultBuyProviders;
620
+ ObservableMap<WalletType, ProviderType> defaultBuyProviders;
621
622
@observable
623
- ObservableMap<WalletType, BuyProviderType> defaultSellProviders;
623
+ ObservableMap<WalletType, ProviderType> defaultSellProviders;
624
625
@observable
626
SortBalanceBy sortBalanceBy;
lib/view_model/buy/buy_view_model.dart
+1
-1
@@ -1,5 +1,5 @@
1
import 'package:cake_wallet/buy/buy_provider.dart';
2
-import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
2
+import 'package:cake_wallet/buy/moonpay/moonpay_provider.dart';
3
import 'package:cake_wallet/buy/wyre/wyre_buy_provider.dart';
4
import 'package:cw_core/crypto_currency.dart';
5
import 'package:cake_wallet/entities/fiat_currency.dart';
lib/view_model/dashboard/dashboard_view_model.dart
+10
-10
@@ -4,7 +4,7 @@ import 'package:cake_wallet/buy/buy_provider.dart';
4
import 'package:cake_wallet/core/key_service.dart';
5
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
6
import 'package:cake_wallet/entities/balance_display_mode.dart';
7
-import 'package:cake_wallet/entities/buy_provider_types.dart';
7
+import 'package:cake_wallet/entities/provider_types.dart';
8
import 'package:cake_wallet/entities/exchange_api_mode.dart';
9
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
10
import 'package:cake_wallet/generated/i18n.dart';
@@ -42,7 +42,7 @@ import 'package:cw_core/wallet_type.dart';
42
import 'package:eth_sig_util/util/utils.dart';
43
import 'package:flutter/services.dart';
44
import 'package:mobx/mobx.dart';
45
-import 'package:cake_wallet/entities/buy_provider_types.dart';
45
+import 'package:cake_wallet/entities/provider_types.dart';
46
47
part 'dashboard_view_model.g.dart';
48
@@ -297,27 +297,27 @@ abstract class DashboardViewModelBase with Store {
297
298
Map<String, List<FilterItem>> filterItems;
299
300
- BuyProvider? get defaultBuyProvider => BuyProviderHelper.getProviderByType(
301
- settingsStore.defaultBuyProviders[wallet.type] ?? BuyProviderType.askEachTime);
300
+ BuyProvider? get defaultBuyProvider => ProvidersHelper.getProviderByType(
301
+ settingsStore.defaultBuyProviders[wallet.type] ?? ProviderType.askEachTime);
302
303
- BuyProvider? get defaultSellProvider => BuyProviderHelper.getProviderByType(
304
- settingsStore.defaultSellProviders[wallet.type] ?? BuyProviderType.askEachTime);
303
+ BuyProvider? get defaultSellProvider => ProvidersHelper.getProviderByType(
304
+ settingsStore.defaultSellProviders[wallet.type] ?? ProviderType.askEachTime);
305
306
bool get isBuyEnabled => settingsStore.isBitcoinBuyEnabled;
307
308
List<BuyProvider> get availableBuyProviders {
309
- final providerTypes = BuyProviderHelper.getAvailableBuyProviderTypes(wallet.type);
309
+ final providerTypes = ProvidersHelper.getAvailableBuyProviderTypes(wallet.type);
310
return providerTypes
311
- .map((type) => BuyProviderHelper.getProviderByType(type))
311
+ .map((type) => ProvidersHelper.getProviderByType(type))
312
.where((provider) => provider != null)
313
.cast<BuyProvider>()
314
.toList();
315
}
316
317
List<BuyProvider> get availableSellProviders {
318
- final providerTypes = BuyProviderHelper.getAvailableSellProviderTypes(wallet.type);
318
+ final providerTypes = ProvidersHelper.getAvailableSellProviderTypes(wallet.type);
319
return providerTypes
320
- .map((type) => BuyProviderHelper.getProviderByType(type))
320
+ .map((type) => ProvidersHelper.getProviderByType(type))
321
.where((provider) => provider != null)
322
.cast<BuyProvider>()
323
.toList();
lib/view_model/order_details_view_model.dart
+1
-1
@@ -9,7 +9,7 @@ import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.d
9
import 'package:cake_wallet/src/screens/trade_details/track_trade_list_item.dart';
10
import 'package:url_launcher/url_launcher.dart';
11
import 'package:cw_core/wallet_base.dart';
12
-import 'package:cake_wallet/buy/moonpay/moonpay_buy_provider.dart';
12
+import 'package:cake_wallet/buy/moonpay/moonpay_provider.dart';
13
import 'package:cake_wallet/buy/wyre/wyre_buy_provider.dart';
14
15
part 'order_details_view_model.g.dart';
lib/view_model/settings/other_settings_view_model.dart
+18
-18
@@ -1,5 +1,5 @@
1
import 'package:cake_wallet/bitcoin/bitcoin.dart';
2
-import 'package:cake_wallet/entities/buy_provider_types.dart';
2
+import 'package:cake_wallet/entities/provider_types.dart';
3
import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
4
import 'package:cake_wallet/generated/i18n.dart';
5
import 'package:cake_wallet/store/settings_store.dart';
@@ -64,20 +64,20 @@ abstract class OtherSettingsViewModelBase with Store {
64
bool get isEnabledSellAction =>
65
!_settingsStore.disableSell && _wallet.type != WalletType.haven;
66
67
- List<BuyProviderType> get availableBuyProvidersTypes {
68
- return BuyProviderHelper.getAvailableBuyProviderTypes(walletType);
67
+ List<ProviderType> get availableBuyProvidersTypes {
68
+ return ProvidersHelper.getAvailableBuyProviderTypes(walletType);
69
}
70
71
- List<BuyProviderType> get availableSellProvidersTypes =>
72
- BuyProviderHelper.getAvailableSellProviderTypes(walletType);
71
+ List<ProviderType> get availableSellProvidersTypes =>
72
+ ProvidersHelper.getAvailableSellProviderTypes(walletType);
73
74
- BuyProviderType get buyProviderType =>
74
+ ProviderType get buyProviderType =>
75
_settingsStore.defaultBuyProviders[walletType] ??
76
- BuyProviderType.askEachTime;
76
+ ProviderType.askEachTime;
77
78
- BuyProviderType get sellProviderType =>
78
+ ProviderType get sellProviderType =>
79
_settingsStore.defaultSellProviders[walletType] ??
80
- BuyProviderType.askEachTime;
80
+ ProviderType.askEachTime;
81
82
String getDisplayPriority(dynamic priority) {
83
final _priority = priority as TransactionPriority;
@@ -93,28 +93,28 @@ abstract class OtherSettingsViewModelBase with Store {
93
}
94
95
String getBuyProviderType(dynamic buyProviderType) {
96
- final _buyProviderType = buyProviderType as BuyProviderType;
97
- return _buyProviderType == BuyProviderType.askEachTime
96
+ final _buyProviderType = buyProviderType as ProviderType;
97
+ return _buyProviderType == ProviderType.askEachTime
98
? S.current.ask_each_time
99
- : _buyProviderType.name;
99
+ : _buyProviderType.title;
100
}
101
102
String getSellProviderType(dynamic sellProviderType) {
103
- final _sellProviderType = sellProviderType as BuyProviderType;
104
- return _sellProviderType == BuyProviderType.askEachTime
103
+ final _sellProviderType = sellProviderType as ProviderType;
104
+ return _sellProviderType == ProviderType.askEachTime
105
? S.current.ask_each_time
106
- : _sellProviderType.name;
106
+ : _sellProviderType.title;
107
}
108
109
void onDisplayPrioritySelected(TransactionPriority priority) =>
110
_settingsStore.priority[_wallet.type] = priority;
111
112
@action
113
- BuyProviderType onBuyProviderTypeSelected(BuyProviderType buyProviderType) =>
113
+ ProviderType onBuyProviderTypeSelected(ProviderType buyProviderType) =>
114
_settingsStore.defaultBuyProviders[walletType] = buyProviderType;
115
116
@action
117
- BuyProviderType onSellProviderTypeSelected(
118
- BuyProviderType sellProviderType) =>
117
+ ProviderType onSellProviderTypeSelected(
118
+ ProviderType sellProviderType) =>
119
_settingsStore.defaultSellProviders[walletType] = sellProviderType;
120
}
lib/view_model/wallet_list/wallet_list_view_model.dart
+1
@@ -22,6 +22,7 @@ abstract class WalletListViewModelBase with Store {
22
) : wallets = ObservableList<WalletListItem>() {
23
setOrderType(_appStore.settingsStore.walletListOrder);
24
reaction((_) => _appStore.wallet, (_) => updateList());
25
+ updateList();
26
}
27
28
@observable