Cw 591 in app cake pay integration (#1376)

* init commit * buy card UI * buy card detail page * card filter * dropdown button * user auth flow * create order * denomination option * fix searching * denom option fix UI * simulate payment * Update pr_test_build.yml * Update pr_test_build.yml * Implement order expiration handling [skip ci] * refactor code [skip ci] * remove ionia related code [skip ci] * change auth flow * add currency prefix * grid view UI * fix country filter issue * fix underline color * fix fetching card list [skip ci] * list view * update cake pay title * Optimize API usage by fetching CakePay vendors * handle no cards found case * adjust the flow of purchases * UI fixes * fix btc payment data * link extractor * fix fetch next page issue * UI fixes * fix text size * revert base page changes * Revert "revert base page changes" * UI fixes * fix UI * fix link style + localization * update cake pay title * update cake pay subtitle * Update cake_pay_order.dart * revert inject_app_details update

Serhii committed Jun 6, 2024 at 04:51 UTC 30dc8f9238950226833c0adc861f0cc96158217f
108 files changed +3490 -5257
.github/workflows/pr_test_build.yml
+4
@@ -151,6 +151,10 @@ jobs:
151 echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart
152 echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart
153 echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart
154 + echo "const testCakePayApiKey = '${{ secrets.TEST_CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
155 + echo "const cakePayApiKey = '${{ secrets.CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart
156 + echo "const authorization = '${{ secrets.CAKE_PAY_AUTHORIZATION }}';" >> lib/.secrets.g.dart
157 + echo "const CSRFToken = '${{ secrets.CSRF_TOKEN }}';" >> lib/.secrets.g.dart
158 echo "const quantexExchangeMarkup = '${{ secrets.QUANTEX_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart
159 echo "const nano2ApiKey = '${{ secrets.NANO2_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart
160 echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart
lib/cake_pay/cake_pay_api.dart new
+245
@@ -0,0 +1,245 @@
1 +import 'dart:convert';
2 +
3 +import 'package:cake_wallet/cake_pay/cake_pay_order.dart';
4 +import 'package:cake_wallet/cake_pay/cake_pay_user_credentials.dart';
5 +import 'package:cake_wallet/cake_pay/cake_pay_vendor.dart';
6 +import 'package:http/http.dart' as http;
7 +
8 +class CakePayApi {
9 + static const testBaseUri = false;
10 +
11 + static const baseTestCakePayUri = 'test.cakepay.com';
12 + static const baseProdCakePayUri = 'buy.cakepay.com';
13 +
14 + static const baseCakePayUri = testBaseUri ? baseTestCakePayUri : baseProdCakePayUri;
15 +
16 + static const vendorsPath = '/api/vendors';
17 + static const countriesPath = '/api/countries';
18 + static const authPath = '/api/auth';
19 + static final verifyEmailPath = '/api/verify';
20 + static final logoutPath = '/api/logout';
21 + static final createOrderPath = '/api/order';
22 + static final simulatePaymentPath = '/api/simulate_payment';
23 +
24 + /// AuthenticateUser
25 + Future<String> authenticateUser({required String email, required String apiKey}) async {
26 + try {
27 + final uri = Uri.https(baseCakePayUri, authPath);
28 + final headers = {
29 + 'Accept': 'application/json',
30 + 'Content-Type': 'application/json',
31 + 'Authorization': 'Api-Key $apiKey',
32 + };
33 + final response = await http.post(uri, headers: headers, body: json.encode({'email': email}));
34 +
35 + if (response.statusCode != 200) {
36 + throw Exception('Unexpected http status: ${response.statusCode}');
37 + }
38 +
39 + final bodyJson = json.decode(response.body) as Map<String, dynamic>;
40 +
41 + if (bodyJson.containsKey('user') && bodyJson['user']['email'] != null) {
42 + return bodyJson['user']['email'] as String;
43 + }
44 +
45 + throw Exception('Failed to authenticate user with error: $bodyJson');
46 + } catch (e) {
47 + throw Exception('Failed to authenticate user with error: $e');
48 + }
49 + }
50 +
51 + /// Verify email
52 + Future<CakePayUserCredentials> verifyEmail({
53 + required String email,
54 + required String code,
55 + required String apiKey,
56 + }) async {
57 + final uri = Uri.https(baseCakePayUri, verifyEmailPath);
58 + final headers = {
59 + 'Accept': 'application/json',
60 + 'Content-Type': 'application/json',
61 + 'Authorization': 'Api-Key $apiKey',
62 + };
63 + final query = <String, String>{'email': email, 'otp': code};
64 +
65 + final response = await http.post(uri, headers: headers, body: json.encode(query));
66 +
67 + if (response.statusCode != 200) {
68 + throw Exception('Unexpected http status: ${response.statusCode}');
69 + }
70 +
71 + final bodyJson = json.decode(response.body) as Map<String, dynamic>;
72 +
73 + if (bodyJson.containsKey('error')) {
74 + throw Exception(bodyJson['error'] as String);
75 + }
76 +
77 + if (bodyJson.containsKey('token')) {
78 + final token = bodyJson['token'] as String;
79 + final userEmail = bodyJson['user']['email'] as String;
80 + return CakePayUserCredentials(userEmail, token);
81 + } else {
82 + throw Exception('E-mail verification failed.');
83 + }
84 + }
85 +
86 + /// createOrder
87 + Future<CakePayOrder> createOrder({
88 + required String apiKey,
89 + required int cardId,
90 + required String price,
91 + required int quantity,
92 + required String userEmail,
93 + required String token,
94 + }) async {
95 + final uri = Uri.https(baseCakePayUri, createOrderPath);
96 + final headers = {
97 + 'Accept': 'application/json',
98 + 'Content-Type': 'application/json',
99 + 'Authorization': 'Api-Key $apiKey',
100 + };
101 + final query = <String, dynamic>{
102 + 'card_id': cardId,
103 + 'price': price,
104 + 'quantity': quantity,
105 + 'user_email': userEmail,
106 + 'token': token,
107 + 'send_email': true
108 + };
109 +
110 + try {
111 + final response = await http.post(uri, headers: headers, body: json.encode(query));
112 +
113 + if (response.statusCode != 201) {
114 + final responseBody = json.decode(response.body);
115 + if (responseBody is List) {
116 + throw '${responseBody[0]}';
117 + } else {
118 + throw Exception('Unexpected error: $responseBody');
119 + }
120 + }
121 +
122 + final bodyJson = json.decode(response.body) as Map<String, dynamic>;
123 + return CakePayOrder.fromMap(bodyJson);
124 + } catch (e) {
125 + throw Exception('${e}');
126 + }
127 + }
128 +
129 + ///Simulate Payment
130 + Future<void> simulatePayment(
131 + {required String CSRFToken, required String authorization, required String orderId}) async {
132 + final uri = Uri.https(baseCakePayUri, simulatePaymentPath + '/$orderId');
133 +
134 + final headers = {
135 + 'accept': 'application/json',
136 + 'authorization': authorization,
137 + 'X-CSRFToken': CSRFToken,
138 + };
139 +
140 + final response = await http.get(uri, headers: headers);
141 +
142 + print('Response: ${response.statusCode}');
143 +
144 + if (response.statusCode != 200) {
145 + throw Exception('Unexpected http status: ${response.statusCode}');
146 + }
147 +
148 + final bodyJson = json.decode(response.body) as Map<String, dynamic>;
149 +
150 + throw Exception('You just bot a gift card with id: ${bodyJson['order_id']}');
151 + }
152 +
153 + /// Logout
154 + Future<void> logoutUser({required String email, required String apiKey}) async {
155 + final uri = Uri.https(baseCakePayUri, logoutPath);
156 + final headers = {
157 + 'Accept': 'application/json',
158 + 'Content-Type': 'application/json',
159 + 'Authorization': 'Api-Key $apiKey',
160 + };
161 +
162 + try {
163 + final response = await http.post(uri, headers: headers, body: json.encode({'email': email}));
164 +
165 + if (response.statusCode != 200) {
166 + throw Exception('Unexpected http status: ${response.statusCode}');
167 + }
168 + } catch (e) {
169 + print('Caught exception: $e');
170 + }
171 + }
172 +
173 + /// Get Countries
174 + Future<List<String>> getCountries(
175 + {required String CSRFToken, required String authorization}) async {
176 + final uri = Uri.https(baseCakePayUri, countriesPath);
177 +
178 + final headers = {
179 + 'accept': 'application/json',
180 + 'authorization': authorization,
181 + 'X-CSRFToken': CSRFToken,
182 + };
183 +
184 + final response = await http.get(uri, headers: headers);
185 +
186 + if (response.statusCode != 200) {
187 + throw Exception('Unexpected http status: ${response.statusCode}');
188 + }
189 +
190 + final bodyJson = json.decode(response.body) as List;
191 +
192 + return bodyJson.map<String>((country) => country['name'] as String).toList();
193 + }
194 +
195 + /// Get Vendors
196 + Future<List<CakePayVendor>> getVendors({
197 + required String CSRFToken,
198 + required String authorization,
199 + int? page,
200 + String? country,
201 + String? countryCode,
202 + String? search,
203 + List<String>? vendorIds,
204 + bool? giftCards,
205 + bool? prepaidCards,
206 + bool? onDemand,
207 + bool? custom,
208 + }) async {
209 + var queryParams = {
210 + 'page': page?.toString(),
211 + 'country': country,
212 + 'country_code': countryCode,
213 + 'search': search,
214 + 'vendor_ids': vendorIds?.join(','),
215 + 'gift_cards': giftCards?.toString(),
216 + 'prepaid_cards': prepaidCards?.toString(),
217 + 'on_demand': onDemand?.toString(),
218 + 'custom': custom?.toString(),
219 + };
220 +
221 + final uri = Uri.https(baseCakePayUri, vendorsPath, queryParams);
222 +
223 + var headers = {
224 + 'accept': 'application/json; charset=UTF-8',
225 + 'authorization': authorization,
226 + 'X-CSRFToken': CSRFToken,
227 + };
228 +
229 + var response = await http.get(uri, headers: headers);
230 +
231 + if (response.statusCode != 200) {
232 + throw Exception(response.body);
233 + }
234 +
235 + final bodyJson = json.decode(response.body);
236 +
237 + if (bodyJson is List<dynamic> && bodyJson.isEmpty) {
238 + return [];
239 + }
240 +
241 + return (bodyJson['results'] as List)
242 + .map((e) => CakePayVendor.fromJson(e as Map<String, dynamic>))
243 + .toList();
244 + }
245 +}
lib/cake_pay/cake_pay_card.dart new
+87
@@ -0,0 +1,87 @@
1 +import 'dart:convert';
2 +
3 +import 'package:cake_wallet/entities/fiat_currency.dart';
4 +
5 +class CakePayCard {
6 + final int id;
7 + final String name;
8 + final String? description;
9 + final String? termsAndConditions;
10 + final String? howToUse;
11 + final String? expiryAndValidity;
12 + final String? cardImageUrl;
13 + final String? country;
14 + final FiatCurrency fiatCurrency;
15 + final List<String> denominationsUsd;
16 + final List<String> denominations;
17 + final String? minValueUsd;
18 + final String? maxValueUsd;
19 + final String? minValue;
20 + final String? maxValue;
21 +
22 + CakePayCard({
23 + required this.id,
24 + required this.name,
25 + this.description,
26 + this.termsAndConditions,
27 + this.howToUse,
28 + this.expiryAndValidity,
29 + this.cardImageUrl,
30 + this.country,
31 + required this.fiatCurrency,
32 + required this.denominationsUsd,
33 + required this.denominations,
34 + this.minValueUsd,
35 + this.maxValueUsd,
36 + this.minValue,
37 + this.maxValue,
38 + });
39 +
40 + factory CakePayCard.fromJson(Map<String, dynamic> json) {
41 + final name = stripHtmlIfNeeded(json['name'] as String? ?? '');
42 + final decodedName = fixEncoding(name);
43 +
44 + final description = stripHtmlIfNeeded(json['description'] as String? ?? '');
45 + final decodedDescription = fixEncoding(description);
46 +
47 + final termsAndConditions = stripHtmlIfNeeded(json['terms_and_conditions'] as String? ?? '');
48 + final decodedTermsAndConditions = fixEncoding(termsAndConditions);
49 +
50 + final howToUse = stripHtmlIfNeeded(json['how_to_use'] as String? ?? '');
51 + final decodedHowToUse = fixEncoding(howToUse);
52 +
53 + final fiatCurrency = FiatCurrency.deserialize(raw: json['currency_code'] as String? ?? '');
54 +
55 + final List<String> denominationsUsd =
56 + (json['denominations_usd'] as List?)?.map((e) => e.toString()).toList() ?? [];
57 + final List<String> denominations =
58 + (json['denominations'] as List?)?.map((e) => e.toString()).toList() ?? [];
59 +
60 + return CakePayCard(
61 + id: json['id'] as int? ?? 0,
62 + name: decodedName,
63 + description: decodedDescription,
64 + termsAndConditions: decodedTermsAndConditions,
65 + howToUse: decodedHowToUse,
66 + expiryAndValidity: json['expiry_and_validity'] as String?,
67 + cardImageUrl: json['card_image_url'] as String?,
68 + country: json['country'] as String?,
69 + fiatCurrency: fiatCurrency,
70 + denominationsUsd: denominationsUsd,
71 + denominations: denominations,
72 + minValueUsd: json['min_value_usd'] as String?,
73 + maxValueUsd: json['max_value_usd'] as String?,
74 + minValue: json['min_value'] as String?,
75 + maxValue: json['max_value'] as String?,
76 + );
77 + }
78 +
79 + static String stripHtmlIfNeeded(String text) {
80 + return text.replaceAll(RegExp(r'<[^>]*>|&[^;]+;'), ' ');
81 + }
82 +
83 + static String fixEncoding(String text) {
84 + final bytes = latin1.encode(text);
85 + return utf8.decode(bytes, allowMalformed: true);
86 + }
87 +}
lib/cake_pay/cake_pay_order.dart new
+131
@@ -0,0 +1,131 @@
1 +
2 +class CakePayOrder {
3 + final String orderId;
4 + final List<OrderCard> cards;
5 + final String? externalId;
6 + final double amountUsd;
7 + final String status;
8 + final String? vouchers;
9 + final PaymentData paymentData;
10 +
11 + CakePayOrder({
12 + required this.orderId,
13 + required this.cards,
14 + required this.externalId,
15 + required this.amountUsd,
16 + required this.status,
17 + required this.vouchers,
18 + required this.paymentData,
19 + });
20 +
21 + factory CakePayOrder.fromMap(Map<String, dynamic> map) {
22 + return CakePayOrder(
23 + orderId: map['order_id'] as String,
24 + cards: (map['cards'] as List<dynamic>)
25 + .map((x) => OrderCard.fromMap(x as Map<String, dynamic>))
26 + .toList(),
27 + externalId: map['external_id'] as String?,
28 + amountUsd: map['amount_usd'] as double,
29 + status: map['status'] as String,
30 + vouchers: map['vouchers'] as String?,
31 + paymentData: PaymentData.fromMap(map['payment_data'] as Map<String, dynamic>));
32 + }
33 +}
34 +
35 +class OrderCard {
36 + final int cardId;
37 + final int? externalId;
38 + final String price;
39 + final int quantity;
40 + final String currencyCode;
41 +
42 + OrderCard({
43 + required this.cardId,
44 + required this.externalId,
45 + required this.price,
46 + required this.quantity,
47 + required this.currencyCode,
48 + });
49 +
50 + factory OrderCard.fromMap(Map<String, dynamic> map) {
51 + return OrderCard(
52 + cardId: map['card_id'] as int,
53 + externalId: map['external_id'] as int?,
54 + price: map['price'] as String,
55 + quantity: map['quantity'] as int,
56 + currencyCode: map['currency_code'] as String,
57 + );
58 + }
59 +}
60 +
61 +class PaymentData {
62 + final CryptoPaymentData btc;
63 + final CryptoPaymentData xmr;
64 + final DateTime invoiceTime;
65 + final DateTime expirationTime;
66 + final int? commission;
67 +
68 + PaymentData({
69 + required this.btc,
70 + required this.xmr,
71 + required this.invoiceTime,
72 + required this.expirationTime,
73 + required this.commission,
74 + });
75 +
76 + factory PaymentData.fromMap(Map<String, dynamic> map) {
77 + return PaymentData(
78 + btc: CryptoPaymentData.fromMap(map['BTC'] as Map<String, dynamic>),
79 + xmr: CryptoPaymentData.fromMap(map['XMR'] as Map<String, dynamic>),
80 + invoiceTime: DateTime.fromMillisecondsSinceEpoch(map['invoice_time'] as int),
81 + expirationTime: DateTime.fromMillisecondsSinceEpoch(map['expiration_time'] as int),
82 + commission: map['commission'] as int?,
83 + );
84 + }
85 +}
86 +
87 +class CryptoPaymentData {
88 + final String price;
89 + final PaymentUrl? paymentUrls;
90 + final String address;
91 +
92 + CryptoPaymentData({
93 + required this.price,
94 + this.paymentUrls,
95 + required this.address,
96 + });
97 +
98 + factory CryptoPaymentData.fromMap(Map<String, dynamic> map) {
99 + return CryptoPaymentData(
100 + price: map['price'] as String,
101 + paymentUrls: PaymentUrl.fromMap(map['paymentUrls'] as Map<String, dynamic>?),
102 + address: map['address'] as String,
103 + );
104 + }
105 +}
106 +
107 +class PaymentUrl {
108 + final String? bip21;
109 + final String? bip72;
110 + final String? bip72b;
111 + final String? bip73;
112 + final String? bolt11;
113 +
114 + PaymentUrl({
115 + this.bip21,
116 + this.bip72,
117 + this.bip72b,
118 + this.bip73,
119 + this.bolt11,
120 + });
121 +
122 + factory PaymentUrl.fromMap(Map<String, dynamic>? map) {
123 + return PaymentUrl(
124 + bip21: map?['BIP21'] as String?,
125 + bip72: map?['BIP72'] as String?,
126 + bip72b: map?['BIP72b'] as String?,
127 + bip73: map?['BIP73'] as String?,
128 + bolt11: map?['BOLT11'] as String?,
129 + );
130 + }
131 +}
lib/cake_pay/cake_pay_payment_credantials.dart new
+15
@@ -0,0 +1,15 @@
1 +class PaymentCredential {
2 + final double amount;
3 + final int quantity;
4 + final double totalAmount;
5 + final String? userName;
6 + final String fiatCurrency;
7 +
8 + PaymentCredential({
9 + required this.amount,
10 + required this.quantity,
11 + required this.totalAmount,
12 + required this.userName,
13 + required this.fiatCurrency,
14 + });
15 +}
\ No newline at end of file
lib/cake_pay/cake_pay_service.dart new
+107
@@ -0,0 +1,107 @@
1 +import 'package:cake_wallet/.secrets.g.dart' as secrets;
2 +import 'package:cake_wallet/cake_pay/cake_pay_api.dart';
3 +import 'package:cake_wallet/cake_pay/cake_pay_order.dart';
4 +import 'package:cake_wallet/cake_pay/cake_pay_vendor.dart';
5 +import 'package:cake_wallet/core/secure_storage.dart';
6 +
7 +class CakePayService {
8 + CakePayService(this.secureStorage, this.cakePayApi);
9 +
10 + static const cakePayEmailStorageKey = 'cake_pay_email';
11 + static const cakePayUsernameStorageKey = 'cake_pay_username';
12 + static const cakePayUserTokenKey = 'cake_pay_user_token';
13 +
14 + static String get testCakePayApiKey => secrets.testCakePayApiKey;
15 +
16 + static String get cakePayApiKey => secrets.cakePayApiKey;
17 +
18 + static String get CSRFToken => secrets.CSRFToken;
19 +
20 + static String get authorization => secrets.authorization;
21 +
22 + final SecureStorage secureStorage;
23 + final CakePayApi cakePayApi;
24 +
25 + /// Get Available Countries
26 + Future<List<String>> getCountries() async =>
27 + await cakePayApi.getCountries(CSRFToken: CSRFToken, authorization: authorization);
28 +
29 + /// Get Vendors
30 + Future<List<CakePayVendor>> getVendors({
31 + int? page,
32 + String? country,
33 + String? countryCode,
34 + String? search,
35 + List<String>? vendorIds,
36 + bool? giftCards,
37 + bool? prepaidCards,
38 + bool? onDemand,
39 + bool? custom,
40 + }) async {
41 + final result = await cakePayApi.getVendors(
42 + CSRFToken: CSRFToken,
43 + authorization: authorization,
44 + page: page,
45 + country: country,
46 + countryCode: countryCode,
47 + search: search,
48 + vendorIds: vendorIds,
49 + giftCards: giftCards,
50 + prepaidCards: prepaidCards,
51 + onDemand: onDemand,
52 + custom: custom);
53 + return result;
54 + }
55 +
56 + /// LogIn
57 + Future<void> logIn(String email) async {
58 + final userName = await cakePayApi.authenticateUser(email: email, apiKey: cakePayApiKey);
59 + await secureStorage.write(key: cakePayEmailStorageKey, value: userName);
60 + await secureStorage.write(key: cakePayUsernameStorageKey, value: userName);
61 + }
62 +
63 + /// Verify email
64 + Future<void> verifyEmail(String code) async {
65 + final email = (await secureStorage.read(key: cakePayEmailStorageKey))!;
66 + final credentials =
67 + await cakePayApi.verifyEmail(email: email, code: code, apiKey: cakePayApiKey);
68 + await secureStorage.write(key: cakePayUserTokenKey, value: credentials.token);
69 + await secureStorage.write(key: cakePayUsernameStorageKey, value: credentials.username);
70 + }
71 +
72 + Future<String?> getUserEmail() async {
73 + return (await secureStorage.read(key: cakePayEmailStorageKey));
74 + }
75 +
76 + /// Check is user logged
77 + Future<bool> isLogged() async {
78 + final username = await secureStorage.read(key: cakePayUsernameStorageKey) ?? '';
79 + final password = await secureStorage.read(key: cakePayUserTokenKey) ?? '';
80 + return username.isNotEmpty && password.isNotEmpty;
81 + }
82 +
83 + /// Logout
84 + Future<void> logout(String email) async {
85 + await secureStorage.delete(key: cakePayUsernameStorageKey);
86 + await secureStorage.delete(key: cakePayUserTokenKey);
87 + await cakePayApi.logoutUser(email: email, apiKey: cakePayApiKey);
88 + }
89 +
90 + /// Purchase Gift Card
91 + Future<CakePayOrder> createOrder(
92 + {required int cardId, required String price, required int quantity}) async {
93 + final userEmail = (await secureStorage.read(key: cakePayEmailStorageKey))!;
94 + final token = (await secureStorage.read(key: cakePayUserTokenKey))!;
95 + return await cakePayApi.createOrder(
96 + apiKey: cakePayApiKey,
97 + cardId: cardId,
98 + price: price,
99 + quantity: quantity,
100 + token: token,
101 + userEmail: userEmail);
102 + }
103 +
104 + ///Simulate Purchase Gift Card
105 + Future<void> simulatePayment({required String orderId}) async => await cakePayApi.simulatePayment(
106 + CSRFToken: CSRFToken, authorization: authorization, orderId: orderId);
107 +}
lib/cake_pay/cake_pay_states.dart new
+67
@@ -0,0 +1,67 @@
1 +import 'cake_pay_card.dart';
2 +
3 +abstract class CakePayUserVerificationState {}
4 +
5 +class CakePayUserVerificationStateInitial extends CakePayUserVerificationState {}
6 +
7 +class CakePayUserVerificationStateSuccess extends CakePayUserVerificationState {}
8 +
9 +class CakePayUserVerificationStatePending extends CakePayUserVerificationState {}
10 +
11 +class CakePayUserVerificationStateLoading extends CakePayUserVerificationState {}
12 +
13 +class CakePayUserVerificationStateFailure extends CakePayUserVerificationState {
14 + CakePayUserVerificationStateFailure({required this.error});
15 +
16 + final String error;
17 +}
18 +
19 +abstract class CakePayOtpState {}
20 +
21 +class CakePayOtpValidating extends CakePayOtpState {}
22 +
23 +class CakePayOtpSuccess extends CakePayOtpState {}
24 +
25 +class CakePayOtpSendDisabled extends CakePayOtpState {}
26 +
27 +class CakePayOtpSendEnabled extends CakePayOtpState {}
28 +
29 +class CakePayOtpFailure extends CakePayOtpState {
30 + CakePayOtpFailure({required this.error});
31 +
32 + final String error;
33 +}
34 +
35 +class CakePayCreateCardState {}
36 +
37 +class CakePayCreateCardStateSuccess extends CakePayCreateCardState {}
38 +
39 +class CakePayCreateCardStateLoading extends CakePayCreateCardState {}
40 +
41 +class CakePayCreateCardStateFailure extends CakePayCreateCardState {
42 + CakePayCreateCardStateFailure({required this.error});
43 +
44 + final String error;
45 +}
46 +
47 +class CakePayCardsState {}
48 +
49 +class CakePayCardsStateNoCards extends CakePayCardsState {}
50 +
51 +class CakePayCardsStateFetching extends CakePayCardsState {}
52 +
53 +class CakePayCardsStateFailure extends CakePayCardsState {}
54 +
55 +class CakePayCardsStateSuccess extends CakePayCardsState {
56 + CakePayCardsStateSuccess({required this.card});
57 +
58 + final CakePayCard card;
59 +}
60 +
61 +abstract class CakePayVendorState {}
62 +
63 +class InitialCakePayVendorLoadingState extends CakePayVendorState {}
64 +
65 +class CakePayVendorLoadingState extends CakePayVendorState {}
66 +
67 +class CakePayVendorLoadedState extends CakePayVendorState {}
lib/cake_pay/cake_pay_user_credentials.dart new
+6
@@ -0,0 +1,6 @@
1 +class CakePayUserCredentials {
2 + const CakePayUserCredentials(this.username, this.token);
3 +
4 + final String username;
5 + final String token;
6 +}
\ No newline at end of file
lib/cake_pay/cake_pay_vendor.dart new
+51
@@ -0,0 +1,51 @@
1 +import 'dart:convert';
2 +
3 +import 'cake_pay_card.dart';
4 +
5 +class CakePayVendor {
6 + final int id;
7 + final String name;
8 + final bool unavailable;
9 + final String? cakeWarnings;
10 + final List<String> countries;
11 + final CakePayCard? card;
12 +
13 + CakePayVendor({
14 + required this.id,
15 + required this.name,
16 + required this.unavailable,
17 + this.cakeWarnings,
18 + required this.countries,
19 + this.card,
20 + });
21 +
22 + factory CakePayVendor.fromJson(Map<String, dynamic> json) {
23 + final name = stripHtmlIfNeeded(json['name'] as String);
24 + final decodedName = fixEncoding(name);
25 +
26 + var cardsJson = json['cards'] as List?;
27 + CakePayCard? firstCard;
28 +
29 + if (cardsJson != null && cardsJson.isNotEmpty) {
30 + firstCard = CakePayCard.fromJson(cardsJson.first as Map<String, dynamic>);
31 + }
32 +
33 + return CakePayVendor(
34 + id: json['id'] as int,
35 + name: decodedName,
36 + unavailable: json['unavailable'] as bool? ?? false,
37 + cakeWarnings: json['cake_warnings'] as String?,
38 + countries: List<String>.from(json['countries'] as List? ?? []),
39 + card: firstCard,
40 + );
41 + }
42 +
43 + static String stripHtmlIfNeeded(String text) {
44 + return text.replaceAll(RegExp(r'<[^>]*>|&[^;]+;'), ' ');
45 + }
46 +
47 + static String fixEncoding(String text) {
48 + final bytes = latin1.encode(text);
49 + return utf8.decode(bytes, allowMalformed: true);
50 + }
51 +}
lib/di.dart
+77 -153
@@ -2,7 +2,6 @@ import 'package:cake_wallet/.secrets.g.dart' as secrets;
2 import 'package:cake_wallet/anonpay/anonpay_api.dart';
3 import 'package:cake_wallet/anonpay/anonpay_info_base.dart';
4 import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
5 -import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart';
5 import 'package:cake_wallet/anypay/anypay_api.dart';
6 import 'package:cake_wallet/bitcoin/bitcoin.dart';
7 import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart';
@@ -33,16 +32,10 @@ import 'package:cake_wallet/entities/qr_view_data.dart';
32 import 'package:cake_wallet/entities/template.dart';
33 import 'package:cake_wallet/entities/transaction_description.dart';
34 import 'package:cake_wallet/ethereum/ethereum.dart';
35 +import 'package:cake_wallet/cake_pay/cake_pay_card.dart';
36 import 'package:cake_wallet/exchange/exchange_template.dart';
37 import 'package:cake_wallet/exchange/trade.dart';
38 import 'package:cake_wallet/haven/haven.dart';
39 -import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart';
40 -import 'package:cake_wallet/ionia/ionia_anypay.dart';
41 -import 'package:cake_wallet/ionia/ionia_api.dart';
42 -import 'package:cake_wallet/ionia/ionia_gift_card.dart';
43 -import 'package:cake_wallet/ionia/ionia_merchant.dart';
44 -import 'package:cake_wallet/ionia/ionia_service.dart';
45 -import 'package:cake_wallet/ionia/ionia_tip.dart';
39 import 'package:cake_wallet/monero/monero.dart';
40 import 'package:cake_wallet/nano/nano.dart';
41 import 'package:cake_wallet/polygon/polygon.dart';
@@ -72,14 +65,6 @@ import 'package:cake_wallet/src/screens/exchange/exchange_template_page.dart';
65 import 'package:cake_wallet/src/screens/exchange_trade/exchange_confirm_page.dart';
66 import 'package:cake_wallet/src/screens/exchange_trade/exchange_trade_page.dart';
67 import 'package:cake_wallet/src/screens/faq/faq_page.dart';
75 -import 'package:cake_wallet/src/screens/ionia/cards/ionia_account_cards_page.dart';
76 -import 'package:cake_wallet/src/screens/ionia/cards/ionia_account_page.dart';
77 -import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_redeem_page.dart';
78 -import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_tip_page.dart';
79 -import 'package:cake_wallet/src/screens/ionia/cards/ionia_gift_card_detail_page.dart';
80 -import 'package:cake_wallet/src/screens/ionia/cards/ionia_more_options_page.dart';
81 -import 'package:cake_wallet/src/screens/ionia/cards/ionia_payment_status_page.dart';
82 -import 'package:cake_wallet/src/screens/ionia/ionia.dart';
68 import 'package:cake_wallet/src/screens/monero_accounts/monero_account_edit_or_create_page.dart';
69 import 'package:cake_wallet/src/screens/monero_accounts/monero_account_list_page.dart';
70 import 'package:cake_wallet/src/screens/nano/nano_change_rep_page.dart';
@@ -124,16 +109,57 @@ import 'package:cake_wallet/src/screens/subaddress/address_edit_or_create_page.d
109 import 'package:cake_wallet/src/screens/support/support_page.dart';
110 import 'package:cake_wallet/src/screens/support_chat/support_chat_page.dart';
111 import 'package:cake_wallet/src/screens/support_other_links/support_other_links_page.dart';
112 +import 'package:cake_wallet/src/screens/wallet/wallet_edit_page.dart';
113 +import 'package:cake_wallet/src/screens/wallet_connect/wc_connections_listing_view.dart';
114 +import 'package:cake_wallet/themes/theme_list.dart';
115 +import 'package:cake_wallet/utils/device_info.dart';
116 +import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
117 +import 'package:cake_wallet/utils/payment_request.dart';
118 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
119 +import 'package:cake_wallet/view_model/dashboard/desktop_sidebar_view_model.dart';
120 +import 'package:cake_wallet/view_model/anon_invoice_page_view_model.dart';
121 +import 'package:cake_wallet/view_model/anonpay_details_view_model.dart';
122 +import 'package:cake_wallet/view_model/dashboard/home_settings_view_model.dart';
123 +import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
124 +import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
125 +import 'package:cake_wallet/view_model/cake_pay/cake_pay_auth_view_model.dart';
126 +import 'package:cake_wallet/view_model/cake_pay/cake_pay_buy_card_view_model.dart';
127 +import 'package:cake_wallet/cake_pay/cake_pay_service.dart';
128 +import 'package:cake_wallet/cake_pay/cake_pay_api.dart';
129 +import 'package:cake_wallet/cake_pay/cake_pay_vendor.dart';
130 +import 'package:cake_wallet/src/screens/cake_pay/auth/cake_pay_account_page.dart';
131 +import 'package:cake_wallet/src/screens/cake_pay/cake_pay.dart';
132 +import 'package:cake_wallet/view_model/cake_pay/cake_pay_account_view_model.dart';
133 +import 'package:cake_wallet/view_model/cake_pay/cake_pay_cards_list_view_model.dart';
134 +import 'package:cake_wallet/view_model/cake_pay/cake_pay_purchase_view_model.dart';
135 +import 'package:cake_wallet/view_model/nano_account_list/nano_account_edit_or_create_view_model.dart';
136 +import 'package:cake_wallet/view_model/nano_account_list/nano_account_list_view_model.dart';
137 +import 'package:cake_wallet/view_model/node_list/pow_node_list_view_model.dart';
138 +import 'package:cake_wallet/view_model/seed_type_view_model.dart';
139 +import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart';
140 +import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart';
141 +import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart';
142 +import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart';
143 +import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart';
144 +import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart';
145 +import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
146 +import 'package:cake_wallet/view_model/settings/trocador_providers_view_model.dart';
147 +import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.dart';
148 +import 'package:cake_wallet/view_model/wallet_list/wallet_edit_view_model.dart';
149 +import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
150 +import 'package:cake_wallet/view_model/wallet_restore_choose_derivation_view_model.dart';
151 +import 'package:cw_core/nano_account.dart';
152 +import 'package:cw_core/unspent_coins_info.dart';
153 +import 'package:cw_core/wallet_service.dart';
154 +import 'package:cw_core/transaction_info.dart';
155 +import 'package:cw_core/node.dart';
156 import 'package:cake_wallet/src/screens/trade_details/trade_details_page.dart';
157 import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart';
158 import 'package:cake_wallet/src/screens/transaction_details/transaction_details_page.dart';
159 import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart';
160 import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
132 -import 'package:cake_wallet/src/screens/wallet/wallet_edit_page.dart';
133 -import 'package:cake_wallet/src/screens/wallet_connect/wc_connections_listing_view.dart';
161 import 'package:cake_wallet/src/screens/wallet_keys/wallet_keys_page.dart';
162 import 'package:cake_wallet/src/screens/wallet_list/wallet_list_page.dart';
136 -import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
163 import 'package:cake_wallet/store/app_store.dart';
164 import 'package:cake_wallet/store/authentication_store.dart';
165 import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart';
@@ -148,14 +174,7 @@ import 'package:cake_wallet/store/templates/exchange_template_store.dart';
174 import 'package:cake_wallet/store/templates/send_template_store.dart';
175 import 'package:cake_wallet/store/wallet_list_store.dart';
176 import 'package:cake_wallet/store/yat/yat_store.dart';
151 -import 'package:cake_wallet/themes/theme_list.dart';
177 import 'package:cake_wallet/tron/tron.dart';
153 -import 'package:cake_wallet/utils/device_info.dart';
154 -import 'package:cake_wallet/utils/payment_request.dart';
155 -import 'package:cake_wallet/utils/responsive_layout_util.dart';
156 -import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
157 -import 'package:cake_wallet/view_model/anon_invoice_page_view_model.dart';
158 -import 'package:cake_wallet/view_model/anonpay_details_view_model.dart';
178 import 'package:cake_wallet/view_model/auth_view_model.dart';
179 import 'package:cake_wallet/view_model/backup_view_model.dart';
180 import 'package:cake_wallet/view_model/buy/buy_amount_view_model.dart';
@@ -165,46 +184,22 @@ import 'package:cake_wallet/view_model/contact_list/contact_view_model.dart';
184 import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart';
185 import 'package:cake_wallet/view_model/dashboard/cake_features_view_model.dart';
186 import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
168 -import 'package:cake_wallet/view_model/dashboard/desktop_sidebar_view_model.dart';
169 -import 'package:cake_wallet/view_model/dashboard/home_settings_view_model.dart';
170 -import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
171 -import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
187 import 'package:cake_wallet/view_model/edit_backup_password_view_model.dart';
188 import 'package:cake_wallet/view_model/exchange/exchange_trade_view_model.dart';
189 import 'package:cake_wallet/view_model/exchange/exchange_view_model.dart';
190 import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart';
176 -import 'package:cake_wallet/view_model/ionia/ionia_account_view_model.dart';
177 -import 'package:cake_wallet/view_model/ionia/ionia_auth_view_model.dart';
178 -import 'package:cake_wallet/view_model/ionia/ionia_buy_card_view_model.dart';
179 -import 'package:cake_wallet/view_model/ionia/ionia_custom_redeem_view_model.dart';
180 -import 'package:cake_wallet/view_model/ionia/ionia_custom_tip_view_model.dart';
181 -import 'package:cake_wallet/view_model/ionia/ionia_gift_card_details_view_model.dart';
182 -import 'package:cake_wallet/view_model/ionia/ionia_gift_cards_list_view_model.dart';
183 -import 'package:cake_wallet/view_model/ionia/ionia_payment_status_view_model.dart';
184 -import 'package:cake_wallet/view_model/ionia/ionia_purchase_merch_view_model.dart';
191 import 'package:cake_wallet/view_model/link_view_model.dart';
192 import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
193 import 'package:cake_wallet/view_model/monero_account_list/monero_account_edit_or_create_view_model.dart';
194 import 'package:cake_wallet/view_model/monero_account_list/monero_account_list_view_model.dart';
189 -import 'package:cake_wallet/view_model/nano_account_list/nano_account_edit_or_create_view_model.dart';
190 -import 'package:cake_wallet/view_model/nano_account_list/nano_account_list_view_model.dart';
195 import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
196 import 'package:cake_wallet/view_model/node_list/node_list_view_model.dart';
193 -import 'package:cake_wallet/view_model/node_list/pow_node_list_view_model.dart';
197 import 'package:cake_wallet/view_model/order_details_view_model.dart';
198 import 'package:cake_wallet/view_model/rescan_view_model.dart';
196 -import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart';
199 import 'package:cake_wallet/view_model/restore_from_backup_view_model.dart';
198 -import 'package:cake_wallet/view_model/seed_type_view_model.dart';
200 import 'package:cake_wallet/view_model/send/send_template_view_model.dart';
201 import 'package:cake_wallet/view_model/send/send_view_model.dart';
201 -import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart';
202 -import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart';
203 -import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart';
204 -import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart';
205 -import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart';
202 import 'package:cake_wallet/view_model/settings/silent_payments_settings_view_model.dart';
207 -import 'package:cake_wallet/view_model/settings/trocador_providers_view_model.dart';
203 import 'package:cake_wallet/view_model/setup_pin_code_view_model.dart';
204 import 'package:cake_wallet/view_model/support_view_model.dart';
205 import 'package:cake_wallet/view_model/trade_details_view_model.dart';
@@ -213,25 +208,16 @@ import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_details_view_
208 import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_item.dart';
209 import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_list_view_model.dart';
210 import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_edit_or_create_view_model.dart';
216 -import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.dart';
211 import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
212 import 'package:cake_wallet/view_model/wallet_hardware_restore_view_model.dart';
213 import 'package:cake_wallet/view_model/wallet_keys_view_model.dart';
220 -import 'package:cake_wallet/view_model/wallet_list/wallet_edit_view_model.dart';
221 -import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
214 import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
215 import 'package:cake_wallet/view_model/wallet_new_vm.dart';
224 -import 'package:cake_wallet/view_model/wallet_restore_choose_derivation_view_model.dart';
216 import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
217 import 'package:cake_wallet/view_model/wallet_seed_view_model.dart';
218 import 'package:cw_core/crypto_currency.dart';
228 -import 'package:cw_core/nano_account.dart';
229 -import 'package:cw_core/node.dart';
219 import 'package:cw_core/receive_page_option.dart';
231 -import 'package:cw_core/transaction_info.dart';
232 -import 'package:cw_core/unspent_coins_info.dart';
220 import 'package:cw_core/wallet_info.dart';
234 -import 'package:cw_core/wallet_service.dart';
221 import 'package:cw_core/wallet_type.dart';
222 import 'package:flutter/foundation.dart';
223 import 'package:flutter/widgets.dart';
@@ -239,6 +225,7 @@ import 'package:get_it/get_it.dart';
225 import 'package:hive/hive.dart';
226 import 'package:mobx/mobx.dart';
227 import 'package:shared_preferences/shared_preferences.dart';
228 +import 'cake_pay/cake_pay_payment_credantials.dart';
229
230 final getIt = GetIt.instance;
231
@@ -993,6 +980,8 @@ Future<void> setup({
980 trades: _tradesSource,
981 settingsStore: getIt.get<SettingsStore>()));
982
983 + getIt.registerFactory(() => CakeFeaturesViewModel(getIt.get<CakePayService>()));
984 +
985 getIt.registerFactory(() => BackupService(getIt.get<SecureStorage>(), _walletInfoSource,
986 getIt.get<KeyService>(), getIt.get<SharedPreferences>()));
987
@@ -1088,113 +1077,60 @@ Future<void> setup({
1077 getIt.registerFactoryParam<FullscreenQRPage, QrViewData, void>(
1078 (QrViewData viewData, _) => FullscreenQRPage(qrViewData: viewData));
1079
1091 - getIt.registerFactory(() => IoniaApi());
1080 + getIt.registerFactory(() => CakePayApi());
1081
1082 getIt.registerFactory(() => AnyPayApi());
1083
1095 - getIt.registerFactory<IoniaService>(
1096 - () => IoniaService(getIt.get<SecureStorage>(), getIt.get<IoniaApi>()));
1097 -
1098 - getIt.registerFactory<IoniaAnyPay>(() => IoniaAnyPay(
1099 - getIt.get<IoniaService>(), getIt.get<AnyPayApi>(), getIt.get<AppStore>().wallet!));
1084 + getIt.registerFactory<CakePayService>(
1085 + () => CakePayService(getIt.get<SecureStorage>(), getIt.get<CakePayApi>()));
1086
1101 - getIt.registerFactory(() => IoniaGiftCardsListViewModel(ioniaService: getIt.get<IoniaService>()));
1087 + getIt.registerFactory(() => CakePayCardsListViewModel(cakePayService: getIt.get<CakePayService>()));
1088
1103 - getIt.registerFactory(() => CakeFeaturesViewModel(getIt.get<IoniaService>()));
1089 + getIt.registerFactory(() => CakePayAuthViewModel(cakePayService: getIt.get<CakePayService>()));
1090
1105 - getIt.registerFactory(() => IoniaAuthViewModel(ioniaService: getIt.get<IoniaService>()));
1106 -
1107 - getIt.registerFactoryParam<IoniaMerchPurchaseViewModel, double, IoniaMerchant>(
1108 - (double amount, merchant) {
1109 - return IoniaMerchPurchaseViewModel(
1110 - ioniaAnyPayService: getIt.get<IoniaAnyPay>(),
1111 - amount: amount,
1112 - ioniaMerchant: merchant,
1091 + getIt.registerFactoryParam<CakePayPurchaseViewModel, PaymentCredential, CakePayCard>(
1092 + (PaymentCredential paymentCredential, CakePayCard card) {
1093 + return CakePayPurchaseViewModel(
1094 + cakePayService: getIt.get<CakePayService>(),
1095 + paymentCredential: paymentCredential,
1096 + card: card,
1097 sendViewModel: getIt.get<SendViewModel>());
1098 });
1099
1116 - getIt.registerFactoryParam<IoniaBuyCardViewModel, IoniaMerchant, void>(
1117 - (IoniaMerchant merchant, _) {
1118 - return IoniaBuyCardViewModel(ioniaMerchant: merchant);
1100 + getIt.registerFactoryParam<CakePayBuyCardViewModel, CakePayVendor, void>(
1101 + (CakePayVendor vendor, _) {
1102 + return CakePayBuyCardViewModel(vendor: vendor);
1103 });
1104
1121 - getIt.registerFactory(() => IoniaAccountViewModel(ioniaService: getIt.get<IoniaService>()));
1122 -
1123 - getIt.registerFactory(() => IoniaCreateAccountPage(getIt.get<IoniaAuthViewModel>()));
1105 + getIt.registerFactory(() => CakePayAccountViewModel(cakePayService: getIt.get<CakePayService>()));
1106
1125 - getIt.registerFactory(() => IoniaLoginPage(getIt.get<IoniaAuthViewModel>()));
1107 + getIt.registerFactory(() => CakePayWelcomePage(getIt.get<CakePayAuthViewModel>()));
1108
1127 - getIt.registerFactoryParam<IoniaVerifyIoniaOtp, List<dynamic>, void>((List<dynamic> args, _) {
1109 + getIt.registerFactoryParam<CakePayVerifyOtpPage, List<dynamic>, void>((List<dynamic> args, _) {
1110 final email = args.first as String;
1111 final isSignIn = args[1] as bool;
1112
1131 - return IoniaVerifyIoniaOtp(getIt.get<IoniaAuthViewModel>(), email, isSignIn);
1113 + return CakePayVerifyOtpPage(getIt.get<CakePayAuthViewModel>(), email, isSignIn);
1114 });
1115
1134 - getIt.registerFactory(() => IoniaWelcomePage());
1135 -
1136 - getIt.registerFactoryParam<IoniaBuyGiftCardPage, List<dynamic>, void>((List<dynamic> args, _) {
1137 - final merchant = args.first as IoniaMerchant;
1116 + getIt.registerFactoryParam<CakePayBuyCardPage, List<dynamic>, void>((List<dynamic> args, _) {
1117 + final vendor = args.first as CakePayVendor;
1118
1139 - return IoniaBuyGiftCardPage(getIt.get<IoniaBuyCardViewModel>(param1: merchant));
1119 + return CakePayBuyCardPage(getIt.get<CakePayBuyCardViewModel>(param1: vendor),
1120 + getIt.get<CakePayService>());
1121 });
1122
1142 - getIt.registerFactoryParam<IoniaBuyGiftCardDetailPage, List<dynamic>, void>(
1123 + getIt.registerFactoryParam<CakePayBuyCardDetailPage, List<dynamic>, void>(
1124 (List<dynamic> args, _) {
1144 - final amount = args.first as double;
1145 - final merchant = args.last as IoniaMerchant;
1146 - return IoniaBuyGiftCardDetailPage(
1147 - getIt.get<IoniaMerchPurchaseViewModel>(param1: amount, param2: merchant));
1148 - });
1149 -
1150 - getIt.registerFactoryParam<IoniaGiftCardDetailsViewModel, IoniaGiftCard, void>(
1151 - (IoniaGiftCard giftCard, _) {
1152 - return IoniaGiftCardDetailsViewModel(
1153 - ioniaService: getIt.get<IoniaService>(), giftCard: giftCard);
1154 - });
1155 -
1156 - getIt.registerFactoryParam<IoniaCustomTipViewModel, List<dynamic>, void>((List<dynamic> args, _) {
1157 - final amount = args[0] as double;
1158 - final merchant = args[1] as IoniaMerchant;
1159 - final tip = args[2] as IoniaTip;
1160 -
1161 - return IoniaCustomTipViewModel(amount: amount, tip: tip, ioniaMerchant: merchant);
1162 - });
1163 -
1164 - getIt.registerFactoryParam<IoniaGiftCardDetailPage, IoniaGiftCard, void>(
1165 - (IoniaGiftCard giftCard, _) {
1166 - return IoniaGiftCardDetailPage(getIt.get<IoniaGiftCardDetailsViewModel>(param1: giftCard));
1125 + final paymentCredential = args.first as PaymentCredential;
1126 + final card = args[1] as CakePayCard;
1127 + return CakePayBuyCardDetailPage(
1128 + getIt.get<CakePayPurchaseViewModel>(param1: paymentCredential, param2: card));
1129 });
1130
1169 - getIt.registerFactoryParam<IoniaMoreOptionsPage, List<dynamic>, void>((List<dynamic> args, _) {
1170 - final giftCard = args.first as IoniaGiftCard;
1171 -
1172 - return IoniaMoreOptionsPage(giftCard);
1173 - });
1131 + getIt.registerFactory(() => CakePayCardsPage(getIt.get<CakePayCardsListViewModel>()));
1132
1175 - getIt.registerFactoryParam<IoniaCustomRedeemViewModel, IoniaGiftCard, void>(
1176 - (IoniaGiftCard giftCard, _) =>
1177 - IoniaCustomRedeemViewModel(giftCard: giftCard, ioniaService: getIt.get<IoniaService>()));
1178 -
1179 - getIt.registerFactoryParam<IoniaCustomRedeemPage, List<dynamic>, void>((List<dynamic> args, _) {
1180 - final giftCard = args.first as IoniaGiftCard;
1181 -
1182 - return IoniaCustomRedeemPage(getIt.get<IoniaCustomRedeemViewModel>(param1: giftCard));
1183 - });
1184 -
1185 - getIt.registerFactoryParam<IoniaCustomTipPage, List<dynamic>, void>((List<dynamic> args, _) {
1186 - return IoniaCustomTipPage(getIt.get<IoniaCustomTipViewModel>(param1: args));
1187 - });
1188 -
1189 - getIt.registerFactory(() => IoniaManageCardsPage(getIt.get<IoniaGiftCardsListViewModel>()));
1190 -
1191 - getIt.registerFactory(() => IoniaDebitCardPage(getIt.get<IoniaGiftCardsListViewModel>()));
1192 -
1193 - getIt.registerFactory(() => IoniaActivateDebitCardPage(getIt.get<IoniaGiftCardsListViewModel>()));
1194 -
1195 - getIt.registerFactory(() => IoniaAccountPage(getIt.get<IoniaAccountViewModel>()));
1196 -
1197 - getIt.registerFactory(() => IoniaAccountCardsPage(getIt.get<IoniaAccountViewModel>()));
1133 + getIt.registerFactory(() => CakePayAccountPage(getIt.get<CakePayAccountViewModel>()));
1134
1135 getIt.registerFactoryParam<RBFDetailsPage, TransactionInfo, void>(
1136 (TransactionInfo transactionInfo, _) => RBFDetailsPage(
@@ -1225,18 +1161,6 @@ Future<void> setup({
1161 (AnonpayInvoiceInfo anonpayInvoiceInfo, _) => AnonpayDetailsPage(
1162 anonpayDetailsViewModel: getIt.get<AnonpayDetailsViewModel>(param1: anonpayInvoiceInfo)));
1163
1228 - getIt.registerFactoryParam<IoniaPaymentStatusViewModel, IoniaAnyPayPaymentInfo,
1229 - AnyPayPaymentCommittedInfo>(
1230 - (IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo) =>
1231 - IoniaPaymentStatusViewModel(getIt.get<IoniaService>(),
1232 - paymentInfo: paymentInfo, committedInfo: committedInfo));
1233 -
1234 - getIt.registerFactoryParam<IoniaPaymentStatusPage, IoniaAnyPayPaymentInfo,
1235 - AnyPayPaymentCommittedInfo>(
1236 - (IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo) =>
1237 - IoniaPaymentStatusPage(
1238 - getIt.get<IoniaPaymentStatusViewModel>(param1: paymentInfo, param2: committedInfo)));
1239 -
1164 getIt.registerFactoryParam<HomeSettingsPage, BalanceViewModel, void>((balanceViewModel, _) =>
1165 HomeSettingsPage(getIt.get<HomeSettingsViewModel>(param1: balanceViewModel)));
1166
lib/ionia/ionia_any_pay_payment_info.dart deleted
-9
@@ -1,9 +0,0 @@
1 -import 'package:cake_wallet/anypay/any_pay_payment.dart';
2 -import 'package:cake_wallet/ionia/ionia_order.dart';
3 -
4 -class IoniaAnyPayPaymentInfo {
5 - const IoniaAnyPayPaymentInfo(this.ioniaOrder, this.anyPayPayment);
6 -
7 - final IoniaOrder ioniaOrder;
8 - final AnyPayPayment anyPayPayment;
9 -}
lib/ionia/ionia_anypay.dart deleted
-91
@@ -1,91 +0,0 @@
1 -import 'package:cw_core/monero_amount_format.dart';
2 -import 'package:cw_core/monero_transaction_priority.dart';
3 -import 'package:cw_core/output_info.dart';
4 -import 'package:cw_core/pending_transaction.dart';
5 -import 'package:cw_core/wallet_base.dart';
6 -import 'package:cake_wallet/anypay/any_pay_payment.dart';
7 -import 'package:cake_wallet/anypay/any_pay_payment_instruction.dart';
8 -import 'package:cake_wallet/ionia/ionia_service.dart';
9 -import 'package:cake_wallet/anypay/anypay_api.dart';
10 -import 'package:cake_wallet/anypay/any_pay_chain.dart';
11 -import 'package:cake_wallet/anypay/any_pay_trasnaction.dart';
12 -import 'package:cake_wallet/bitcoin/bitcoin.dart';
13 -import 'package:cake_wallet/monero/monero.dart';
14 -import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart';
15 -import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart';
16 -
17 -class IoniaAnyPay {
18 - IoniaAnyPay(this.ioniaService, this.anyPayApi, this.wallet);
19 -
20 - final IoniaService ioniaService;
21 - final AnyPayApi anyPayApi;
22 - final WalletBase wallet;
23 -
24 - Future<IoniaAnyPayPaymentInfo> purchase({
25 - required String merchId,
26 - required double amount}) async {
27 - final invoice = await ioniaService.purchaseGiftCard(
28 - merchId: merchId,
29 - amount: amount,
30 - currency: wallet.currency.title.toUpperCase());
31 - final anypayPayment = await anyPayApi.paymentRequest(invoice.uri);
32 - return IoniaAnyPayPaymentInfo(invoice, anypayPayment);
33 - }
34 -
35 - Future<AnyPayPaymentCommittedInfo> commitInvoice(AnyPayPayment payment) async {
36 - final transactionCredentials = payment.instructions
37 - .where((instruction) => instruction.type == AnyPayPaymentInstruction.transactionType)
38 - .map((AnyPayPaymentInstruction instruction) {
39 - switch(payment.chain.toUpperCase()) {
40 - case AnyPayChain.xmr:
41 - return monero!.createMoneroTransactionCreationCredentialsRaw(
42 - outputs: instruction.outputs.map((out) =>
43 - OutputInfo(
44 - isParsedAddress: false,
45 - address: out.address,
46 - cryptoAmount: moneroAmountToString(amount: out.amount),
47 - formattedCryptoAmount: out.amount,
48 - sendAll: false)).toList(),
49 - priority: MoneroTransactionPriority.medium); // FIXME: HARDCODED PRIORITY
50 - case AnyPayChain.btc:
51 - return bitcoin!.createBitcoinTransactionCredentialsRaw(
52 - instruction.outputs.map((out) =>
53 - OutputInfo(
54 - isParsedAddress: false,
55 - address: out.address,
56 - formattedCryptoAmount: out.amount,
57 - sendAll: false)).toList(),
58 - feeRate: instruction.requiredFeeRate);
59 - case AnyPayChain.ltc:
60 - return bitcoin!.createBitcoinTransactionCredentialsRaw(
61 - instruction.outputs.map((out) =>
62 - OutputInfo(
63 - isParsedAddress: false,
64 - address: out.address,
65 - formattedCryptoAmount: out.amount,
66 - sendAll: false)).toList(),
67 - feeRate: instruction.requiredFeeRate);
68 - default:
69 - throw Exception('Incorrect transaction chain: ${payment.chain.toUpperCase()}');
70 - }
71 - });
72 - final transactions = (await Future.wait(transactionCredentials
73 - .map((Object credentials) async => await wallet.createTransaction(credentials))))
74 - .map((PendingTransaction pendingTransaction) {
75 - switch (payment.chain.toUpperCase()){
76 - case AnyPayChain.xmr:
77 - final ptx = monero!.pendingTransactionInfo(pendingTransaction);
78 - return AnyPayTransaction(ptx['hex'] ?? '', id: ptx['id'] ?? '', key: ptx['key']);
79 - default:
80 - return AnyPayTransaction(pendingTransaction.hex, id: pendingTransaction.id, key: null);
81 - }
82 - })
83 - .toList();
84 -
85 - return await anyPayApi.payment(
86 - payment.paymentUrl,
87 - chain: payment.chain,
88 - currency: payment.chain,
89 - transactions: transactions);
90 - }
91 -}
\ No newline at end of file
lib/ionia/ionia_api.dart deleted
-440
@@ -1,440 +0,0 @@
1 -import 'dart:convert';
2 -import 'package:cake_wallet/ionia/ionia_merchant.dart';
3 -import 'package:cake_wallet/ionia/ionia_order.dart';
4 -import 'package:http/http.dart';
5 -import 'package:cake_wallet/ionia/ionia_user_credentials.dart';
6 -import 'package:cake_wallet/ionia/ionia_virtual_card.dart';
7 -import 'package:cake_wallet/ionia/ionia_category.dart';
8 -import 'package:cake_wallet/ionia/ionia_gift_card.dart';
9 -
10 -class IoniaApi {
11 - static const baseUri = 'api.ionia.io';
12 - static const pathPrefix = 'cake';
13 - static const requestedUUIDHeader = 'requestedUUID';
14 - static final createUserUri = Uri.https(baseUri, '/$pathPrefix/CreateUser');
15 - static final verifyEmailUri = Uri.https(baseUri, '/$pathPrefix/VerifyEmail');
16 - static final signInUri = Uri.https(baseUri, '/$pathPrefix/SignIn');
17 - static final createCardUri = Uri.https(baseUri, '/$pathPrefix/CreateCard');
18 - static final getCardsUri = Uri.https(baseUri, '/$pathPrefix/GetCards');
19 - static final getMerchantsUrl = Uri.https(baseUri, '/$pathPrefix/GetMerchants');
20 - static final getMerchantsByFilterUrl = Uri.https(baseUri, '/$pathPrefix/GetMerchantsByFilter');
21 - static final getPurchaseMerchantsUrl = Uri.https(baseUri, '/$pathPrefix/PurchaseGiftCard');
22 - static final getCurrentUserGiftCardSummariesUrl = Uri.https(baseUri, '/$pathPrefix/GetCurrentUserGiftCardSummaries');
23 - static final changeGiftCardUrl = Uri.https(baseUri, '/$pathPrefix/ChargeGiftCard');
24 - static final getGiftCardUrl = Uri.https(baseUri, '/$pathPrefix/GetGiftCard');
25 - static final getPaymentStatusUrl = Uri.https(baseUri, '/$pathPrefix/PaymentStatus');
26 -
27 - // Create user
28 -
29 - Future<String> createUser(String email, {required String clientId}) async {
30 - final headers = <String, String>{'clientId': clientId};
31 - final query = <String, String>{'emailAddress': email};
32 - final uri = createUserUri.replace(queryParameters: query);
33 - final response = await put(uri, headers: headers);
34 -
35 - if (response.statusCode != 200) {
36 - throw Exception('Unexpected http status: ${response.statusCode}');
37 - }
38 -
39 - final bodyJson = json.decode(response.body) as Map<String, dynamic>;
40 - final data = bodyJson['Data'] as Map<String, dynamic>;
41 - final isSuccessful = bodyJson['Successful'] as bool;
42 -
43 - if (!isSuccessful) {
44 - throw Exception(data['ErrorMessage'] as String);
45 - }
46 -
47 - return data['username'] as String;
48 - }
49 -
50 - // Verify email
51 -
52 - Future<IoniaUserCredentials> verifyEmail({
53 - required String email,
54 - required String code,
55 - required String clientId}) async {
56 - final headers = <String, String>{
57 - 'clientId': clientId,
58 - 'EmailAddress': email};
59 - final query = <String, String>{'verificationCode': code};
60 - final uri = verifyEmailUri.replace(queryParameters: query);
61 - final response = await put(uri, headers: headers);
62 -
63 - if (response.statusCode != 200) {
64 - throw Exception('Unexpected http status: ${response.statusCode}');
65 - }
66 -
67 - final bodyJson = json.decode(response.body) as Map<String, dynamic>;
68 - final data = bodyJson['Data'] as Map<String, dynamic>;
69 - final isSuccessful = bodyJson['Successful'] as bool;
70 -
71 - if (!isSuccessful) {
72 - throw Exception(bodyJson['ErrorMessage'] as String);
73 - }
74 -
75 - final password = data['password'] as String;
76 - final username = data['username'] as String;
77 - return IoniaUserCredentials(username, password);
78 - }
79 -
80 - // Sign In
81 -
82 - Future<void> signIn(String email, {required String clientId}) async {
83 - final headers = <String, String>{'clientId': clientId};
84 - final query = <String, String>{'emailAddress': email};
85 - final uri = signInUri.replace(queryParameters: query);
86 - final response = await put(uri, headers: headers);
87 -
88 - if (response.statusCode != 200) {
89 - throw Exception('Unexpected http status: ${response.statusCode}');
90 - }
91 -
92 - final bodyJson = json.decode(response.body) as Map<String, dynamic>;
93 - final data = bodyJson['Data'] as Map<String, dynamic>;
94 - final isSuccessful = bodyJson['Successful'] as bool;
95 -
96 - if (!isSuccessful) {
97 - throw Exception(data['ErrorMessage'] as String);
98 - }
99 - }
100 -
101 - // Get virtual card
102 -
103 - Future<IoniaVirtualCard> getCards({
104 - required String username,
105 - required String password,
106 - required String clientId}) async {
107 - final headers = <String, String>{
108 - 'clientId': clientId,
109 - 'username': username,
110 - 'password': password};
111 - final response = await post(getCardsUri, headers: headers);
112 -
113 - if (response.statusCode != 200) {
114 - throw Exception('Unexpected http status: ${response.statusCode}');
115 - }
116 -
117 - final bodyJson = json.decode(response.body) as Map<String, dynamic>;
118 - final data = bodyJson['Data'] as Map<String, dynamic>;
119 - final isSuccessful = bodyJson['Successful'] as bool;
120 -
121 - if (!isSuccessful) {
122 - throw Exception(data['message'] as String);
123 - }
124 -
125 - final virtualCard = data['VirtualCard'] as Map<String, dynamic>;
126 - return IoniaVirtualCard.fromMap(virtualCard);
127 - }
128 -
129 - // Create virtual card
130 -
131 - Future<IoniaVirtualCard> createCard({
132 - required String username,
133 - required String password,
134 - required String clientId}) async {
135 - final headers = <String, String>{
136 - 'clientId': clientId,
137 - 'username': username,
138 - 'password': password};
139 - final response = await post(createCardUri, headers: headers);
140 -
141 - if (response.statusCode != 200) {
142 - throw Exception('Unexpected http status: ${response.statusCode}');
143 - }
144 -
145 - final bodyJson = json.decode(response.body) as Map<String, dynamic>;
146 - final data = bodyJson['Data'] as Map<String, dynamic>;
147 - final isSuccessful = bodyJson['Successful'] as bool? ?? false;
148 -
149 - if (!isSuccessful) {
150 - throw Exception(data['message'] as String);
151 - }
152 -
153 - return IoniaVirtualCard.fromMap(data);
154 - }
155 -
156 - // Get Merchants
157 -
158 - Future<List<IoniaMerchant>> getMerchants({
159 - required String username,
160 - required String password,
161 - required String clientId}) async {
162 - final headers = <String, String>{
163 - 'clientId': clientId,
164 - 'username': username,
165 - 'password': password};
166 - final response = await post(getMerchantsUrl, headers: headers);
167 -
168 - if (response.statusCode != 200) {
169 - return [];
170 - }
171 -
172 - final decodedBody = json.decode(response.body) as Map<String, dynamic>;
173 - final isSuccessful = decodedBody['Successful'] as bool? ?? false;
174 -
175 - if (!isSuccessful) {
176 - return [];
177 - }
178 -
179 - final data = decodedBody['Data'] as List<dynamic>;
180 - final merch = <IoniaMerchant>[];
181 -
182 - for (final item in data) {
183 - try {
184 - final element = item as Map<String, dynamic>;
185 - merch.add(IoniaMerchant.fromJsonMap(element));
186 - } catch(_) {}
187 - }
188 -
189 - return merch;
190 - }
191 -
192 - // Get Merchants By Filter
193 -
194 - Future<List<IoniaMerchant>> getMerchantsByFilter({
195 - required String username,
196 - required String password,
197 - required String clientId,
198 - String? search,
199 - List<IoniaCategory>? categories,
200 - int merchantFilterType = 0}) async {
201 - // MerchantFilterType: {All = 0, Nearby = 1, Popular = 2, Online = 3, MyFaves = 4, Search = 5}
202 -
203 - final headers = <String, String>{
204 - 'clientId': clientId,
205 - 'username': username,
206 - 'password': password,
207 - 'Content-Type': 'application/json'};
208 - final body = <String, dynamic>{'MerchantFilterType': merchantFilterType};
209 -
210 - if (search != null) {
211 - body['SearchCriteria'] = search;
212 - }
213 -
214 - if (categories != null) {
215 - body['Categories'] = categories
216 - .map((e) => e.ids)
217 - .expand((e) => e)
218 - .toList();
219 - }
220 -
221 - final response = await post(getMerchantsByFilterUrl, headers: headers, body: json.encode(body));
222 -
223 - if (response.statusCode != 200) {
224 - return [];
225 - }
226 -
227 - final decodedBody = json.decode(response.body) as Map<String, dynamic>;
228 - final isSuccessful = decodedBody['Successful'] as bool? ?? false;
229 -
230 - if (!isSuccessful) {
231 - return [];
232 - }
233 -
234 - final data = decodedBody['Data'] as List<dynamic>;
235 - final merch = <IoniaMerchant>[];
236 -
237 - for (final item in data) {
238 - try {
239 - final element = item['Merchant'] as Map<String, dynamic>;
240 - merch.add(IoniaMerchant.fromJsonMap(element));
241 - } catch(_) {}
242 - }
243 -
244 - return merch;
245 - }
246 -
247 - // Purchase Gift Card
248 -
249 - Future<IoniaOrder> purchaseGiftCard({
250 - required String requestedUUID,
251 - required String merchId,
252 - required double amount,
253 - required String currency,
254 - required String username,
255 - required String password,
256 - required String clientId}) async {
257 - final headers = <String, String>{
258 - 'clientId': clientId,
259 - 'username': username,
260 - 'password': password,
261 - requestedUUIDHeader: requestedUUID,
262 - 'Content-Type': 'application/json'};
263 - final body = <String, dynamic>{
264 - 'Amount': amount,
265 - 'Currency': currency,
266 - 'MerchantId': merchId};
267 - final response = await post(getPurchaseMerchantsUrl, headers: headers, body: json.encode(body));
268 -
269 - if (response.statusCode != 200) {
270 - throw Exception('Unexpected response');
271 - }
272 -
273 - final decodedBody = json.decode(response.body) as Map<String, dynamic>;
274 - final isSuccessful = decodedBody['Successful'] as bool? ?? false;
275 -
276 - if (!isSuccessful) {
277 - throw Exception(decodedBody['ErrorMessage'] as String);
278 - }
279 -
280 - final data = decodedBody['Data'] as Map<String, dynamic>;
281 - return IoniaOrder.fromMap(data);
282 - }
283 -
284 - // Get Current User Gift Card Summaries
285 -
286 - Future<List<IoniaGiftCard>> getCurrentUserGiftCardSummaries({
287 - required String username,
288 - required String password,
289 - required String clientId}) async {
290 - final headers = <String, String>{
291 - 'clientId': clientId,
292 - 'username': username,
293 - 'password': password};
294 - final response = await post(getCurrentUserGiftCardSummariesUrl, headers: headers);
295 -
296 - if (response.statusCode != 200) {
297 - return [];
298 - }
299 -
300 - final decodedBody = json.decode(response.body) as Map<String, dynamic>;
301 - final isSuccessful = decodedBody['Successful'] as bool? ?? false;
302 -
303 - if (!isSuccessful) {
304 - return [];
305 - }
306 -
307 - final data = decodedBody['Data'] as List<dynamic>;
308 - final cards = <IoniaGiftCard>[];
309 -
310 - for (final item in data) {
311 - try {
312 - final element = item as Map<String, dynamic>;
313 - cards.add(IoniaGiftCard.fromJsonMap(element));
314 - } catch(_) {}
315 - }
316 -
317 - return cards;
318 - }
319 -
320 - // Charge Gift Card
321 -
322 - Future<void> chargeGiftCard({
323 - required String username,
324 - required String password,
325 - required String clientId,
326 - required int giftCardId,
327 - required double amount}) async {
328 - final headers = <String, String>{
329 - 'clientId': clientId,
330 - 'username': username,
331 - 'password': password,
332 - 'Content-Type': 'application/json'};
333 - final body = <String, dynamic>{
334 - 'Id': giftCardId,
335 - 'Amount': amount};
336 - final response = await post(
337 - changeGiftCardUrl,
338 - headers: headers,
339 - body: json.encode(body));
340 -
341 - if (response.statusCode != 200) {
342 - throw Exception('Failed to update Gift Card with ID ${giftCardId};Incorrect response status: ${response.statusCode};');
343 - }
344 -
345 - final decodedBody = json.decode(response.body) as Map<String, dynamic>;
346 - final isSuccessful = decodedBody['Successful'] as bool? ?? false;
347 -
348 - if (!isSuccessful) {
349 - final data = decodedBody['Data'] as Map<String, dynamic>;
350 - final msg = data['Message'] as String? ?? '';
351 -
352 - if (msg.isNotEmpty) {
353 - throw Exception(msg);
354 - }
355 -
356 - throw Exception('Failed to update Gift Card with ID ${giftCardId};');
357 - }
358 - }
359 -
360 - // Get Gift Card
361 -
362 - Future<IoniaGiftCard> getGiftCard({
363 - required String username,
364 - required String password,
365 - required String clientId,
366 - required int id}) async {
367 - final headers = <String, String>{
368 - 'clientId': clientId,
369 - 'username': username,
370 - 'password': password,
371 - 'Content-Type': 'application/json'};
372 - final body = <String, dynamic>{'Id': id};
373 - final response = await post(
374 - getGiftCardUrl,
375 - headers: headers,
376 - body: json.encode(body));
377 -
378 - if (response.statusCode != 200) {
379 - throw Exception('Failed to get Gift Card with ID ${id};Incorrect response status: ${response.statusCode};');
380 - }
381 -
382 - final decodedBody = json.decode(response.body) as Map<String, dynamic>;
383 - final isSuccessful = decodedBody['Successful'] as bool? ?? false;
384 -
385 - if (!isSuccessful) {
386 - final msg = decodedBody['ErrorMessage'] as String ?? '';
387 -
388 - if (msg.isNotEmpty) {
389 - throw Exception(msg);
390 - }
391 -
392 - throw Exception('Failed to get Gift Card with ID ${id};');
393 - }
394 -
395 - final data = decodedBody['Data'] as Map<String, dynamic>;
396 - return IoniaGiftCard.fromJsonMap(data);
397 - }
398 -
399 - // Payment Status
400 -
401 - Future<int> getPaymentStatus({
402 - required String username,
403 - required String password,
404 - required String clientId,
405 - required String orderId,
406 - required String paymentId}) async {
407 - final headers = <String, String>{
408 - 'clientId': clientId,
409 - 'username': username,
410 - 'password': password,
411 - 'Content-Type': 'application/json'};
412 - final body = <String, dynamic>{
413 - 'order_id': orderId,
414 - 'paymentId': paymentId};
415 - final response = await post(
416 - getPaymentStatusUrl,
417 - headers: headers,
418 - body: json.encode(body));
419 -
420 - if (response.statusCode != 200) {
421 - throw Exception('Failed to get Payment Status for order_id ${orderId} paymentId ${paymentId};Incorrect response status: ${response.statusCode};');
422 - }
423 -
424 - final decodedBody = json.decode(response.body) as Map<String, dynamic>;
425 - final isSuccessful = decodedBody['Successful'] as bool? ?? false;
426 -
427 - if (!isSuccessful) {
428 - final msg = decodedBody['ErrorMessage'] as String ?? '';
429 -
430 - if (msg.isNotEmpty) {
431 - throw Exception(msg);
432 - }
433 -
434 - throw Exception('Failed to get Payment Status for order_id ${orderId} paymentId ${paymentId}');
435 - }
436 -
437 - final data = decodedBody['Data'] as Map<String, dynamic>;
438 - return data['gift_card_id'] as int;
439 - }
440 -}
\ No newline at end of file
lib/ionia/ionia_category.dart deleted
-22
@@ -1,22 +0,0 @@
1 -class IoniaCategory {
2 - const IoniaCategory({
3 - required this.index,
4 - required this.title,
5 - required this.ids,
6 - required this.iconPath});
7 -
8 - static const allCategories = <IoniaCategory>[all, apparel, onlineOnly, food, entertainment, delivery, travel];
9 - static const all = IoniaCategory(index: 0, title: 'All', ids: [], iconPath: 'assets/images/category.png');
10 - static const apparel = IoniaCategory(index: 1, title: 'Apparel', ids: [1], iconPath: 'assets/images/tshirt.png');
11 - static const onlineOnly = IoniaCategory(index: 2, title: 'Online Only', ids: [13, 43], iconPath: 'assets/images/global.png');
12 - static const food = IoniaCategory(index: 3, title: 'Food', ids: [4], iconPath: 'assets/images/food.png');
13 - static const entertainment = IoniaCategory(index: 4, title: 'Entertainment', ids: [5], iconPath: 'assets/images/gaming.png');
14 - static const delivery = IoniaCategory(index: 5, title: 'Delivery', ids: [114, 109], iconPath: 'assets/images/delivery.png');
15 - static const travel = IoniaCategory(index: 6, title: 'Travel', ids: [12], iconPath: 'assets/images/airplane.png');
16 -
17 -
18 - final int index;
19 - final String title;
20 - final List<int> ids;
21 - final String iconPath;
22 -}
lib/ionia/ionia_create_state.dart deleted
-68
@@ -1,68 +0,0 @@
1 -import 'package:cake_wallet/ionia/ionia_virtual_card.dart';
2 -import 'package:flutter/material.dart';
3 -
4 -abstract class IoniaCreateAccountState {}
5 -
6 -class IoniaInitialCreateState extends IoniaCreateAccountState {}
7 -
8 -class IoniaCreateStateSuccess extends IoniaCreateAccountState {}
9 -
10 -class IoniaCreateStateLoading extends IoniaCreateAccountState {}
11 -
12 -class IoniaCreateStateFailure extends IoniaCreateAccountState {
13 - IoniaCreateStateFailure({required this.error});
14 -
15 - final String error;
16 -}
17 -
18 -abstract class IoniaOtpState {}
19 -
20 -class IoniaOtpValidating extends IoniaOtpState {}
21 -
22 -class IoniaOtpSuccess extends IoniaOtpState {}
23 -
24 -class IoniaOtpSendDisabled extends IoniaOtpState {}
25 -
26 -class IoniaOtpSendEnabled extends IoniaOtpState {}
27 -
28 -class IoniaOtpFailure extends IoniaOtpState {
29 - IoniaOtpFailure({required this.error});
30 -
31 - final String error;
32 -}
33 -
34 -class IoniaCreateCardState {}
35 -
36 -class IoniaCreateCardSuccess extends IoniaCreateCardState {}
37 -
38 -class IoniaCreateCardLoading extends IoniaCreateCardState {}
39 -
40 -class IoniaCreateCardFailure extends IoniaCreateCardState {
41 - IoniaCreateCardFailure({required this.error});
42 -
43 - final String error;
44 -}
45 -
46 -class IoniaFetchCardState {}
47 -
48 -class IoniaNoCardState extends IoniaFetchCardState {}
49 -
50 -class IoniaFetchingCard extends IoniaFetchCardState {}
51 -
52 -class IoniaFetchCardFailure extends IoniaFetchCardState {}
53 -
54 -class IoniaCardSuccess extends IoniaFetchCardState {
55 - IoniaCardSuccess({required this.card});
56 -
57 - final IoniaVirtualCard card;
58 -}
59 -
60 -abstract class IoniaMerchantState {}
61 -
62 -class InitialIoniaMerchantLoadingState extends IoniaMerchantState {}
63 -
64 -class IoniaLoadingMerchantState extends IoniaMerchantState {}
65 -
66 -class IoniaLoadedMerchantState extends IoniaMerchantState {}
67 -
68 -
lib/ionia/ionia_gift_card.dart deleted
-70
@@ -1,70 +0,0 @@
1 -import 'dart:convert';
2 -import 'package:cake_wallet/ionia/ionia_gift_card_instruction.dart';
3 -import 'package:flutter/foundation.dart';
4 -
5 -class IoniaGiftCard {
6 - IoniaGiftCard({
7 - required this.id,
8 - required this.merchantId,
9 - required this.legalName,
10 - required this.systemName,
11 - required this.barcodeUrl,
12 - required this.cardNumber,
13 - required this.cardPin,
14 - required this.instructions,
15 - required this.tip,
16 - required this.purchaseAmount,
17 - required this.actualAmount,
18 - required this.totalTransactionAmount,
19 - required this.totalDashTransactionAmount,
20 - required this.remainingAmount,
21 - required this.createdDateFormatted,
22 - required this.lastTransactionDateFormatted,
23 - required this.isActive,
24 - required this.isEmpty,
25 - required this.logoUrl});
26 -
27 - factory IoniaGiftCard.fromJsonMap(Map<String, dynamic> element) {
28 - return IoniaGiftCard(
29 - id: element['Id'] as int,
30 - merchantId: element['MerchantId'] as int,
31 - legalName: element['LegalName'] as String,
32 - systemName: element['SystemName'] as String,
33 - barcodeUrl: element['BarcodeUrl'] as String,
34 - cardNumber: element['CardNumber'] as String,
35 - cardPin: element['CardPin'] as String,
36 - tip: element['Tip'] as double,
37 - purchaseAmount: element['PurchaseAmount'] as double,
38 - actualAmount: element['ActualAmount'] as double,
39 - totalTransactionAmount: element['TotalTransactionAmount'] as double,
40 - totalDashTransactionAmount: (element['TotalDashTransactionAmount'] as double?) ?? 0.0,
41 - remainingAmount: element['RemainingAmount'] as double,
42 - isActive: element['IsActive'] as bool,
43 - isEmpty: element['IsEmpty'] as bool,
44 - logoUrl: element['LogoUrl'] as String,
45 - createdDateFormatted: element['CreatedDate'] as String,
46 - lastTransactionDateFormatted: element['LastTransactionDate'] as String,
47 - instructions: IoniaGiftCardInstruction.parseListOfInstructions(element['PaymentInstructions'] as String));
48 - }
49 -
50 - final int id;
51 - final int merchantId;
52 - final String legalName;
53 - final String systemName;
54 - final String barcodeUrl;
55 - final String cardNumber;
56 - final String cardPin;
57 - final List<IoniaGiftCardInstruction> instructions;
58 - final double tip;
59 - final double purchaseAmount;
60 - final double actualAmount;
61 - final double totalTransactionAmount;
62 - final double totalDashTransactionAmount;
63 - double remainingAmount;
64 - final String createdDateFormatted;
65 - final String lastTransactionDateFormatted;
66 - final bool isActive;
67 - final bool isEmpty;
68 - final String logoUrl;
69 -
70 -}
\ No newline at end of file
lib/ionia/ionia_gift_card_instruction.dart deleted
-28
@@ -1,28 +0,0 @@
1 -import 'dart:convert';
2 -import 'package:intl/intl.dart' show toBeginningOfSentenceCase;
3 -
4 -class IoniaGiftCardInstruction {
5 - IoniaGiftCardInstruction(this.header, this.body);
6 -
7 - factory IoniaGiftCardInstruction.fromJsonMap(Map<String, dynamic> element) {
8 - return IoniaGiftCardInstruction(
9 - toBeginningOfSentenceCase(element['title'] as String? ?? '') ?? '',
10 - element['description'] as String);
11 - }
12 -
13 - static List<IoniaGiftCardInstruction> parseListOfInstructions(String instructionsJSON) {
14 - List<IoniaGiftCardInstruction> instructions = <IoniaGiftCardInstruction>[];
15 -
16 - if (instructionsJSON.isNotEmpty) {
17 - final decodedInstructions = json.decode(instructionsJSON) as List<dynamic>;
18 - instructions = decodedInstructions
19 - .map((dynamic e) =>IoniaGiftCardInstruction.fromJsonMap(e as Map<String, dynamic>))
20 - .toList();
21 - }
22 -
23 - return instructions;
24 - }
25 -
26 - final String header;
27 - final String body;
28 -}
\ No newline at end of file
lib/ionia/ionia_merchant.dart deleted
-101
@@ -1,101 +0,0 @@
1 -import 'package:cake_wallet/ionia/ionia_gift_card_instruction.dart';
2 -import 'package:cake_wallet/generated/i18n.dart';
3 -
4 -class IoniaMerchant {
5 - IoniaMerchant({
6 - required this.id,
7 - required this.legalName,
8 - required this.systemName,
9 - required this.description,
10 - required this.website,
11 - required this.termsAndConditions,
12 - required this.logoUrl,
13 - required this.cardImageUrl,
14 - required this.cardholderAgreement,
15 - required this.isActive,
16 - required this.isOnline,
17 - required this.isPhysical,
18 - required this.isVariablePurchase,
19 - required this.minimumCardPurchase,
20 - required this.maximumCardPurchase,
21 - required this.acceptsTips,
22 - required this.createdDateFormatted,
23 - required this.modifiedDateFormatted,
24 - required this.usageInstructions,
25 - required this.usageInstructionsBak,
26 - required this.hasBarcode,
27 - required this.instructions,
28 - required this.savingsPercentage});
29 -
30 - factory IoniaMerchant.fromJsonMap(Map<String, dynamic> element) {
31 - return IoniaMerchant(
32 - id: element["Id"] as int,
33 - legalName: element["LegalName"] as String,
34 - systemName: element["SystemName"] as String,
35 - description: element["Description"] as String,
36 - website: element["Website"] as String,
37 - termsAndConditions: element["TermsAndConditions"] as String,
38 - logoUrl: element["LogoUrl"] as String,
39 - cardImageUrl: element["CardImageUrl"] as String,
40 - cardholderAgreement: element["CardholderAgreement"] as String,
41 - isActive: element["IsActive"] as bool?,
42 - isOnline: element["IsOnline"] as bool,
43 - isPhysical: element["IsPhysical"] as bool,
44 - isVariablePurchase: element["IsVariablePurchase"] as bool,
45 - minimumCardPurchase: element["MinimumCardPurchase"] as double,
46 - maximumCardPurchase: element["MaximumCardPurchase"] as double,
47 - acceptsTips: element["AcceptsTips"] as bool,
48 - createdDateFormatted: element["CreatedDate"] as String?,
49 - modifiedDateFormatted: element["ModifiedDate"] as String?,
50 - usageInstructions: element["UsageInstructions"] as String?,
51 - usageInstructionsBak: element["UsageInstructionsBak"] as String?,
52 - hasBarcode: element["HasBarcode"] as bool,
53 - instructions: IoniaGiftCardInstruction.parseListOfInstructions(element['PaymentInstructions'] as String),
54 - savingsPercentage: element["SavingsPercentage"] as double);
55 - }
56 -
57 - final int id;
58 - final String legalName;
59 - final String systemName;
60 - final String description;
61 - final String website;
62 - final String termsAndConditions;
63 - final String logoUrl;
64 - final String cardImageUrl;
65 - final String cardholderAgreement;
66 - final bool? isActive;
67 - final bool isOnline;
68 - final bool? isPhysical;
69 - final bool isVariablePurchase;
70 - final double minimumCardPurchase;
71 - final double maximumCardPurchase;
72 - final bool acceptsTips;
73 - final String? createdDateFormatted;
74 - final String? modifiedDateFormatted;
75 - final String? usageInstructions;
76 - final String? usageInstructionsBak;
77 - final bool hasBarcode;
78 - final List<IoniaGiftCardInstruction> instructions;
79 - final double savingsPercentage;
80 -
81 - double get discount => savingsPercentage;
82 -
83 - String get avaibilityStatus {
84 - var status = '';
85 -
86 - if (isOnline) {
87 - status += S.current.online;
88 - }
89 -
90 - if (isPhysical ?? false) {
91 - if (status.isNotEmpty) {
92 - status = '$status & ';
93 - }
94 -
95 - status = '${status}${S.current.in_store}';
96 - }
97 -
98 - return status;
99 - }
100 -
101 -}
lib/ionia/ionia_order.dart deleted
-23
@@ -1,23 +0,0 @@
1 -import 'package:flutter/foundation.dart';
2 -
3 -class IoniaOrder {
4 - IoniaOrder({required this.id,
5 - required this.uri,
6 - required this.currency,
7 - required this.amount,
8 - required this.paymentId});
9 - factory IoniaOrder.fromMap(Map<String, dynamic> obj) {
10 - return IoniaOrder(
11 - id: obj['order_id'] as String,
12 - uri: obj['uri'] as String,
13 - currency: obj['currency'] as String,
14 - amount: obj['amount'] as double,
15 - paymentId: obj['paymentId'] as String);
16 - }
17 -
18 - final String id;
19 - final String uri;
20 - final String currency;
21 - final double amount;
22 - final String paymentId;
23 -}
\ No newline at end of file
lib/ionia/ionia_service.dart deleted
-171
@@ -1,171 +0,0 @@
1 -import 'package:cake_wallet/core/secure_storage.dart';
2 -import 'package:cake_wallet/ionia/ionia_merchant.dart';
3 -import 'package:cake_wallet/ionia/ionia_order.dart';
4 -import 'package:cake_wallet/ionia/ionia_virtual_card.dart';
5 -import 'package:cake_wallet/.secrets.g.dart' as secrets;
6 -import 'package:cake_wallet/ionia/ionia_api.dart';
7 -import 'package:cake_wallet/ionia/ionia_gift_card.dart';
8 -import 'package:cake_wallet/ionia/ionia_category.dart';
9 -
10 -class IoniaService {
11 - IoniaService(this.secureStorage, this.ioniaApi);
12 -
13 - static const ioniaEmailStorageKey = 'ionia_email';
14 - static const ioniaUsernameStorageKey = 'ionia_username';
15 - static const ioniaPasswordStorageKey = 'ionia_password';
16 -
17 - static String get clientId => secrets.ioniaClientId;
18 -
19 - final SecureStorage secureStorage;
20 - final IoniaApi ioniaApi;
21 -
22 - // Create user
23 -
24 - Future<void> createUser(String email) async {
25 - final username = await ioniaApi.createUser(email, clientId: clientId);
26 - await secureStorage.write(key: ioniaEmailStorageKey, value: email);
27 - await secureStorage.write(key: ioniaUsernameStorageKey, value: username);
28 - }
29 -
30 - // Verify email
31 -
32 - Future<void> verifyEmail(String code) async {
33 - final email = (await secureStorage.read(key: ioniaEmailStorageKey))!;
34 - final credentials = await ioniaApi.verifyEmail(email: email, code: code, clientId: clientId);
35 - await secureStorage.write(key: ioniaPasswordStorageKey, value: credentials.password);
36 - await secureStorage.write(key: ioniaUsernameStorageKey, value: credentials.username);
37 - }
38 -
39 - // Sign In
40 -
41 - Future<void> signIn(String email) async {
42 - await ioniaApi.signIn(email, clientId: clientId);
43 - await secureStorage.write(key: ioniaEmailStorageKey, value: email);
44 - }
45 -
46 - Future<String> getUserEmail() async {
47 - return (await secureStorage.read(key: ioniaEmailStorageKey))!;
48 - }
49 -
50 - // Check is user logined
51 -
52 - Future<bool> isLogined() async {
53 - final username = await secureStorage.read(key: ioniaUsernameStorageKey) ?? '';
54 - final password = await secureStorage.read(key: ioniaPasswordStorageKey) ?? '';
55 - return username.isNotEmpty && password.isNotEmpty;
56 - }
57 -
58 - // Logout
59 -
60 - Future<void> logout() async {
61 - await secureStorage.delete(key: ioniaUsernameStorageKey);
62 - await secureStorage.delete(key: ioniaPasswordStorageKey);
63 - }
64 -
65 - // Create virtual card
66 -
67 - Future<IoniaVirtualCard> createCard() async {
68 - final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!;
69 - final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!;
70 - return ioniaApi.createCard(username: username, password: password, clientId: clientId);
71 - }
72 -
73 - // Get virtual card
74 -
75 - Future<IoniaVirtualCard> getCard() async {
76 - final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!;
77 - final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!;
78 - return ioniaApi.getCards(username: username, password: password, clientId: clientId);
79 - }
80 -
81 - // Get Merchants
82 -
83 - Future<List<IoniaMerchant>> getMerchants() async {
84 - final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!;
85 - final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!;
86 - return ioniaApi.getMerchants(username: username, password: password, clientId: clientId);
87 - }
88 -
89 - // Get Merchants By Filter
90 -
91 - Future<List<IoniaMerchant>> getMerchantsByFilter({
92 - String? search,
93 - List<IoniaCategory>? categories,
94 - int merchantFilterType = 0}) async {
95 - final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!;
96 - final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!;
97 - return ioniaApi.getMerchantsByFilter(
98 - username: username,
99 - password: password,
100 - clientId: clientId,
101 - search: search,
102 - categories: categories,
103 - merchantFilterType: merchantFilterType);
104 - }
105 -
106 - // Purchase Gift Card
107 -
108 - Future<IoniaOrder> purchaseGiftCard({
109 - required String merchId,
110 - required double amount,
111 - required String currency}) async {
112 - final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!;
113 - final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!;
114 - final deviceId = '';
115 - return ioniaApi.purchaseGiftCard(
116 - requestedUUID: deviceId,
117 - merchId: merchId,
118 - amount: amount,
119 - currency: currency,
120 - username: username,
121 - password: password,
122 - clientId: clientId);
123 - }
124 -
125 - // Get Current User Gift Card Summaries
126 -
127 - Future<List<IoniaGiftCard>> getCurrentUserGiftCardSummaries() async {
128 - final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!;
129 - final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!;
130 - return ioniaApi.getCurrentUserGiftCardSummaries(username: username, password: password, clientId: clientId);
131 - }
132 -
133 - // Charge Gift Card
134 -
135 - Future<void> chargeGiftCard({
136 - required int giftCardId,
137 - required double amount}) async {
138 - final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!;
139 - final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!;
140 - await ioniaApi.chargeGiftCard(
141 - username: username,
142 - password: password,
143 - clientId: clientId,
144 - giftCardId: giftCardId,
145 - amount: amount);
146 - }
147 -
148 - // Redeem
149 -
150 - Future<void> redeem({required int giftCardId, required double amount}) async {
151 - await chargeGiftCard(giftCardId: giftCardId, amount: amount);
152 - }
153 -
154 - // Get Gift Card
155 -
156 - Future<IoniaGiftCard> getGiftCard({required int id}) async {
157 - final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!;
158 - final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!;
159 - return ioniaApi.getGiftCard(username: username, password: password, clientId: clientId,id: id);
160 - }
161 -
162 - // Payment Status
163 -
164 - Future<int> getPaymentStatus({
165 - required String orderId,
166 - required String paymentId}) async {
167 - final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!;
168 - final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!;
169 - return ioniaApi.getPaymentStatus(username: username, password: password, clientId: clientId, orderId: orderId, paymentId: paymentId);
170 - }
171 -}
\ No newline at end of file
lib/ionia/ionia_tip.dart deleted
-18
@@ -1,18 +0,0 @@
1 -class IoniaTip {
2 - const IoniaTip({
3 - required this.originalAmount,
4 - required this.percentage,
5 - this.isCustom = false});
6 -
7 - final double originalAmount;
8 - final double percentage;
9 - final bool isCustom;
10 -
11 - double get additionalAmount => double.parse((originalAmount * percentage / 100).toStringAsFixed(2));
12 -
13 - static const tipList = [
14 - IoniaTip(originalAmount: 0, percentage: 0),
15 - IoniaTip(originalAmount: 10, percentage: 10),
16 - IoniaTip(originalAmount: 20, percentage: 20)
17 - ];
18 -}
lib/ionia/ionia_token_data.dart deleted
-43
@@ -1,43 +0,0 @@
1 -import 'package:flutter/foundation.dart';
2 -import 'dart:convert';
3 -
4 -class IoniaTokenData {
5 - IoniaTokenData({required this.accessToken, required this.tokenType, required this.expiredAt});
6 -
7 - factory IoniaTokenData.fromJson(String source) {
8 - final decoded = json.decode(source) as Map<String, dynamic>;
9 - final accessToken = decoded['access_token'] as String;
10 - final expiresIn = decoded['expires_in'] as int;
11 - final tokenType = decoded['token_type'] as String;
12 - final expiredAtInMilliseconds = decoded['expired_at'] as int;
13 - DateTime expiredAt;
14 -
15 - if (expiredAtInMilliseconds != null) {
16 - expiredAt = DateTime.fromMillisecondsSinceEpoch(expiredAtInMilliseconds);
17 - } else {
18 - expiredAt = DateTime.now().add(Duration(seconds: expiresIn));
19 - }
20 -
21 - return IoniaTokenData(
22 - accessToken: accessToken,
23 - tokenType: tokenType,
24 - expiredAt: expiredAt);
25 - }
26 -
27 - final String accessToken;
28 - final String tokenType;
29 - final DateTime expiredAt;
30 -
31 - bool get isExpired => DateTime.now().isAfter(expiredAt);
32 -
33 - @override
34 - String toString() => '$tokenType $accessToken';
35 -
36 - String toJson() {
37 - return json.encode(<String, dynamic>{
38 - 'access_token': accessToken,
39 - 'token_type': tokenType,
40 - 'expired_at': expiredAt.millisecondsSinceEpoch
41 - });
42 - }
43 -}
\ No newline at end of file
lib/ionia/ionia_user_credentials.dart deleted
-6
@@ -1,6 +0,0 @@
1 -class IoniaUserCredentials {
2 - const IoniaUserCredentials(this.username, this.password);
3 -
4 - final String username;
5 - final String password;
6 -}
\ No newline at end of file
lib/ionia/ionia_virtual_card.dart deleted
-41
@@ -1,41 +0,0 @@
1 -class IoniaVirtualCard {
2 - IoniaVirtualCard({
3 - required this.token,
4 - required this.createdAt,
5 - required this.lastFour,
6 - required this.state,
7 - required this.pan,
8 - required this.cvv,
9 - required this.expirationMonth,
10 - required this.expirationYear,
11 - required this.fundsLimit,
12 - required this.spendLimit});
13 -
14 - factory IoniaVirtualCard.fromMap(Map<String, dynamic> source) {
15 - final created = source['created'] as String;
16 - final createdAt = DateTime.tryParse(created);
17 -
18 - return IoniaVirtualCard(
19 - token: source['token'] as String,
20 - createdAt: createdAt,
21 - lastFour: source['lastFour'] as String,
22 - state: source['state'] as String,
23 - pan: source['pan'] as String,
24 - cvv: source['cvv'] as String,
25 - expirationMonth: source['expirationMonth'] as String,
26 - expirationYear: source['expirationYear'] as String,
27 - fundsLimit: source['FundsLimit'] as double,
28 - spendLimit: source['spend_limit'] as double);
29 - }
30 -
31 - final String token;
32 - final String lastFour;
33 - final String state;
34 - final String pan;
35 - final String cvv;
36 - final String expirationMonth;
37 - final String expirationYear;
38 - final DateTime? createdAt;
39 - final double fundsLimit;
40 - final double spendLimit;
41 -}
\ No newline at end of file
lib/router.dart
+16 -67
@@ -1,6 +1,5 @@
1 import 'package:cake_wallet/anonpay/anonpay_info_base.dart';
2 import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
3 -import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart';
3 import 'package:cake_wallet/buy/order.dart';
4 import 'package:cake_wallet/core/totp_request_details.dart';
5 import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart';
@@ -10,7 +9,6 @@ import 'package:cake_wallet/entities/qr_view_data.dart';
9 import 'package:cake_wallet/entities/wallet_nft_response.dart';
10 import 'package:cake_wallet/exchange/trade.dart';
11 import 'package:cake_wallet/generated/i18n.dart';
13 -import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart';
12 import 'package:cake_wallet/routes.dart';
13 import 'package:cake_wallet/src/screens/anonpay_details/anonpay_details_page.dart';
14 import 'package:cake_wallet/src/screens/auth/auth_page.dart';
@@ -36,14 +34,6 @@ import 'package:cake_wallet/src/screens/exchange/exchange_template_page.dart';
34 import 'package:cake_wallet/src/screens/exchange_trade/exchange_confirm_page.dart';
35 import 'package:cake_wallet/src/screens/exchange_trade/exchange_trade_page.dart';
36 import 'package:cake_wallet/src/screens/faq/faq_page.dart';
39 -import 'package:cake_wallet/src/screens/ionia/cards/ionia_account_cards_page.dart';
40 -import 'package:cake_wallet/src/screens/ionia/cards/ionia_account_page.dart';
41 -import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_redeem_page.dart';
42 -import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_tip_page.dart';
43 -import 'package:cake_wallet/src/screens/ionia/cards/ionia_gift_card_detail_page.dart';
44 -import 'package:cake_wallet/src/screens/ionia/cards/ionia_more_options_page.dart';
45 -import 'package:cake_wallet/src/screens/ionia/cards/ionia_payment_status_page.dart';
46 -import 'package:cake_wallet/src/screens/ionia/ionia.dart';
37 import 'package:cake_wallet/src/screens/monero_accounts/monero_account_edit_or_create_page.dart';
38 import 'package:cake_wallet/src/screens/nano/nano_change_rep_page.dart';
39 import 'package:cake_wallet/src/screens/nano_accounts/nano_account_edit_or_create_page.dart';
@@ -76,9 +66,11 @@ import 'package:cake_wallet/src/screens/settings/manage_nodes_page.dart';
66 import 'package:cake_wallet/src/screens/settings/other_settings_page.dart';
67 import 'package:cake_wallet/src/screens/settings/privacy_page.dart';
68 import 'package:cake_wallet/src/screens/settings/security_backup_page.dart';
69 +import 'package:cake_wallet/src/screens/cake_pay/auth/cake_pay_account_page.dart';
70 import 'package:cake_wallet/src/screens/settings/silent_payments_settings.dart';
71 import 'package:cake_wallet/src/screens/settings/tor_page.dart';
72 import 'package:cake_wallet/src/screens/settings/trocador_providers_page.dart';
73 +import 'package:cake_wallet/src/screens/settings/tor_page.dart';
74 import 'package:cake_wallet/src/screens/setup_2fa/modify_2fa_page.dart';
75 import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa.dart';
76 import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_enter_code_page.dart';
@@ -120,7 +112,7 @@ import 'package:cw_core/wallet_type.dart';
112 import 'package:flutter/cupertino.dart';
113 import 'package:flutter/material.dart';
114 import 'package:flutter/services.dart';
123 -
115 +import 'package:cake_wallet/src/screens/cake_pay/cake_pay.dart';
116 import 'src/screens/dashboard/pages/nft_import_page.dart';
117
118 late RouteSettings currentRouteSettings;
@@ -518,73 +510,30 @@ Route<dynamic> createRoute(RouteSettings settings) {
510 param1: settings.arguments as QrViewData,
511 ));
512
521 - case Routes.ioniaWelcomePage:
522 - return CupertinoPageRoute<void>(
523 - fullscreenDialog: true,
524 - builder: (_) => getIt.get<IoniaWelcomePage>(),
525 - );
526 -
527 - case Routes.ioniaLoginPage:
528 - return CupertinoPageRoute<void>(builder: (_) => getIt.get<IoniaLoginPage>());
529 -
530 - case Routes.ioniaCreateAccountPage:
531 - return CupertinoPageRoute<void>(builder: (_) => getIt.get<IoniaCreateAccountPage>());
513 + case Routes.cakePayCardsPage:
514 + return CupertinoPageRoute<void>(builder: (_) => getIt.get<CakePayCardsPage>());
515
533 - case Routes.ioniaManageCardsPage:
534 - return CupertinoPageRoute<void>(builder: (_) => getIt.get<IoniaManageCardsPage>());
535 -
536 - case Routes.ioniaBuyGiftCardPage:
516 + case Routes.cakePayBuyCardPage:
517 final args = settings.arguments as List;
518 return CupertinoPageRoute<void>(
539 - builder: (_) => getIt.get<IoniaBuyGiftCardPage>(param1: args));
519 + builder: (_) => getIt.get<CakePayBuyCardPage>(param1: args));
520
541 - case Routes.ioniaBuyGiftCardDetailPage:
521 + case Routes.cakePayBuyCardDetailPage:
522 final args = settings.arguments as List;
523 return CupertinoPageRoute<void>(
544 - builder: (_) => getIt.get<IoniaBuyGiftCardDetailPage>(param1: args));
545 -
546 - case Routes.ioniaVerifyIoniaOtpPage:
547 - final args = settings.arguments as List;
548 - return CupertinoPageRoute<void>(builder: (_) => getIt.get<IoniaVerifyIoniaOtp>(param1: args));
549 -
550 - case Routes.ioniaDebitCardPage:
551 - return CupertinoPageRoute<void>(builder: (_) => getIt.get<IoniaDebitCardPage>());
552 -
553 - case Routes.ioniaActivateDebitCardPage:
554 - return CupertinoPageRoute<void>(builder: (_) => getIt.get<IoniaActivateDebitCardPage>());
555 -
556 - case Routes.ioniaAccountPage:
557 - return CupertinoPageRoute<void>(builder: (_) => getIt.get<IoniaAccountPage>());
524 + builder: (_) => getIt.get<CakePayBuyCardDetailPage>(param1: args));
525
559 - case Routes.ioniaAccountCardsPage:
560 - return CupertinoPageRoute<void>(builder: (_) => getIt.get<IoniaAccountCardsPage>());
561 -
562 - case Routes.ioniaCustomTipPage:
563 - final args = settings.arguments as List;
564 - return CupertinoPageRoute<void>(builder: (_) => getIt.get<IoniaCustomTipPage>(param1: args));
565 -
566 - case Routes.ioniaGiftCardDetailPage:
567 - final args = settings.arguments as List;
568 - return CupertinoPageRoute<void>(
569 - builder: (_) => getIt.get<IoniaGiftCardDetailPage>(param1: args.first));
570 -
571 - case Routes.ioniaCustomRedeemPage:
572 - final args = settings.arguments as List;
526 + case Routes.cakePayWelcomePage:
527 return CupertinoPageRoute<void>(
574 - builder: (_) => getIt.get<IoniaCustomRedeemPage>(param1: args));
528 + builder: (_) => getIt.get<CakePayWelcomePage>(),
529 + );
530
576 - case Routes.ioniaMoreOptionsPage:
531 + case Routes.cakePayVerifyOtpPage:
532 final args = settings.arguments as List;
578 - return CupertinoPageRoute<void>(
579 - builder: (_) => getIt.get<IoniaMoreOptionsPage>(param1: args));
533 + return CupertinoPageRoute<void>(builder: (_) => getIt.get<CakePayVerifyOtpPage>(param1: args));
534
581 - case Routes.ioniaPaymentStatusPage:
582 - final args = settings.arguments as List;
583 - final paymentInfo = args.first as IoniaAnyPayPaymentInfo;
584 - final commitedInfo = args[1] as AnyPayPaymentCommittedInfo;
585 - return CupertinoPageRoute<void>(
586 - builder: (_) =>
587 - getIt.get<IoniaPaymentStatusPage>(param1: paymentInfo, param2: commitedInfo));
535 + case Routes.cakePayAccountPage:
536 + return CupertinoPageRoute<void>(builder: (_) => getIt.get<CakePayAccountPage>());
537
538 case Routes.webViewPage:
539 final args = settings.arguments as List;
lib/routes.dart
+7 -16
@@ -64,22 +64,13 @@ class Routes {
64 static const unspentCoinsDetails = '/unspent_coins_details';
65 static const addressPage = '/address_page';
66 static const fullscreenQR = '/fullscreen_qr';
67 - static const ioniaWelcomePage = '/cake_pay_welcome_page';
68 - static const ioniaCreateAccountPage = '/cake_pay_create_account_page';
69 - static const ioniaLoginPage = '/cake_pay_login_page';
70 - static const ioniaManageCardsPage = '/manage_cards_page';
71 - static const ioniaBuyGiftCardPage = '/buy_gift_card_page';
72 - static const ioniaBuyGiftCardDetailPage = '/buy_gift_card_detail_page';
73 - static const ioniaVerifyIoniaOtpPage = '/cake_pay_verify_otp_page';
74 - static const ioniaDebitCardPage = '/debit_card_page';
75 - static const ioniaActivateDebitCardPage = '/activate_debit_card_page';
76 - static const ioniaAccountPage = 'ionia_account_page';
77 - static const ioniaAccountCardsPage = 'ionia_account_cards_page';
78 - static const ioniaCustomTipPage = 'ionia_custom_tip_page';
79 - static const ioniaGiftCardDetailPage = '/ionia_gift_card_detail_page';
80 - static const ioniaPaymentStatusPage = '/ionia_payment_status_page';
81 - static const ioniaMoreOptionsPage = '/ionia_more_options_page';
82 - static const ioniaCustomRedeemPage = '/ionia_custom_redeem_page';
67 + static const cakePayWelcomePage = '/cake_pay_welcome_page';
68 + static const cakePayLoginPage = '/cake_pay_login_page';
69 + static const cakePayCardsPage = '/cake_pay_cards_page';
70 + static const cakePayBuyCardPage = '/cake_pay_buy_card_page';
71 + static const cakePayBuyCardDetailPage = '/cake_pay_buy_card_detail_page';
72 + static const cakePayVerifyOtpPage = '/cake_pay_verify_otp_page';
73 + static const cakePayAccountPage = '/cake_pay_account_page';
74 static const webViewPage = '/web_view_page';
75 static const silentPaymentsSettings = '/silent_payments_settings';
76 static const connectionSync = '/connection_sync_page';
lib/src/screens/base_page.dart
+12 -2
@@ -7,7 +7,7 @@ import 'package:cake_wallet/store/settings_store.dart';
7 import 'package:cake_wallet/src/widgets/nav_bar.dart';
8 import 'package:cake_wallet/generated/i18n.dart';
9
10 -enum AppBarStyle { regular, withShadow, transparent }
10 +enum AppBarStyle { regular, withShadow, transparent, completelyTransparent }
11
12 abstract class BasePage extends StatelessWidget {
13 BasePage() : _scaffoldKey = GlobalKey<ScaffoldState>();
@@ -125,7 +125,7 @@ abstract class BasePage extends StatelessWidget {
125
126 Widget? floatingActionButton(BuildContext context) => null;
127
128 - ObstructingPreferredSizeWidget appBar(BuildContext context) {
128 + PreferredSizeWidget appBar(BuildContext context) {
129 final appBarColor = pageBackgroundColor(context);
130
131 switch (appBarStyle) {
@@ -156,6 +156,16 @@ abstract class BasePage extends StatelessWidget {
156 border: null,
157 );
158
159 + case AppBarStyle.completelyTransparent:
160 + return AppBar(
161 + leading: leading(context),
162 + title: middle(context),
163 + actions: <Widget>[if (trailing(context) != null) trailing(context)!],
164 + backgroundColor: Colors.transparent,
165 + elevation: 0,
166 + centerTitle: true,
167 + );
168 +
169 default:
170 // FIX-ME: NavBar no context
171 return NavBar(
lib/src/screens/cake_pay/auth/cake_pay_account_page.dart new
+90
@@ -0,0 +1,90 @@
1 +import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
2 +import 'package:cake_wallet/routes.dart';
3 +import 'package:cake_wallet/src/screens/base_page.dart';
4 +import 'package:cake_wallet/generated/i18n.dart';
5 +import 'package:cake_wallet/src/screens/cake_pay/widgets/cake_pay_tile.dart';
6 +import 'package:cake_wallet/src/widgets/primary_button.dart';
7 +import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
8 +import 'package:cake_wallet/typography.dart';
9 +import 'package:cake_wallet/view_model/cake_pay/cake_pay_account_view_model.dart';
10 +import 'package:flutter/material.dart';
11 +import 'package:flutter_mobx/flutter_mobx.dart';
12 +
13 +class CakePayAccountPage extends BasePage {
14 + CakePayAccountPage(this.cakePayAccountViewModel);
15 +
16 + final CakePayAccountViewModel cakePayAccountViewModel;
17 +
18 +
19 +
20 + @override
21 + Widget leading(BuildContext context) {
22 + return MergeSemantics(
23 + child: SizedBox(
24 + height: 37,
25 + width: 37,
26 + child: ButtonTheme(
27 + minWidth: double.minPositive,
28 + child: Semantics(
29 + label: S.of(context).seed_alert_back,
30 + child: TextButton(
31 + style: ButtonStyle(
32 + overlayColor: MaterialStateColor.resolveWith(
33 + (states) => Colors.transparent),
34 + ),
35 + onPressed: () => Navigator.pop(context),
36 + child: backButton(context),
37 + ),
38 + ),
39 + ),
40 + ),
41 + );
42 + }
43 +
44 + @override
45 + Widget middle(BuildContext context) {
46 + return Text(
47 + S.current.account,
48 + style: textMediumSemiBold(
49 + color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
50 + ),
51 + );
52 + }
53 +
54 + @override
55 + Widget body(BuildContext context) {
56 + return ScrollableWithBottomSection(
57 + contentPadding: EdgeInsets.all(24),
58 + content: Column(
59 + children: [
60 + SizedBox(height: 20),
61 + Observer(
62 + builder: (_) => Container(decoration: BoxDecoration(
63 + border: Border(
64 + bottom: BorderSide(
65 + width: 1.0,
66 + color:
67 + Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor),
68 + ),
69 + ),
70 + child: CakePayTile(title: S.of(context).email_address, subTitle: cakePayAccountViewModel.email)),
71 + ),
72 + ],
73 + ),
74 + bottomSectionPadding: EdgeInsets.all(30),
75 + bottomSection: Column(
76 + children: [
77 + PrimaryButton(
78 + color: Theme.of(context).primaryColor,
79 + textColor: Colors.white,
80 + text: S.of(context).logout,
81 + onPressed: () {
82 + cakePayAccountViewModel.logout();
83 + Navigator.pushNamedAndRemoveUntil(context, Routes.dashboard, (route) => false);
84 + },
85 + ),
86 + ],
87 + ),
88 + );
89 + }
90 +}
lib/src/screens/cake_pay/auth/cake_pay_verify_otp_page.dart renamed
+18 -22
@@ -1,39 +1,38 @@
1 -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
2 -import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
3 -import 'package:cake_wallet/ionia/ionia_create_state.dart';
1 +import 'package:cake_wallet/generated/i18n.dart';
2 +import 'package:cake_wallet/cake_pay/cake_pay_states.dart';
3 import 'package:cake_wallet/palette.dart';
5 -import 'package:cake_wallet/routes.dart';
4 import 'package:cake_wallet/src/screens/base_page.dart';
5 import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
6 import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
7 import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
8 import 'package:cake_wallet/src/widgets/primary_button.dart';
9 import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
10 +import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
11 +import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
12 import 'package:cake_wallet/typography.dart';
13 import 'package:cake_wallet/utils/show_pop_up.dart';
14 -import 'package:cake_wallet/view_model/ionia/ionia_auth_view_model.dart';
14 +import 'package:cake_wallet/view_model/cake_pay/cake_pay_auth_view_model.dart';
15 import 'package:flutter/material.dart';
16 -import 'package:cake_wallet/generated/i18n.dart';
16 import 'package:flutter_mobx/flutter_mobx.dart';
17 import 'package:keyboard_actions/keyboard_actions.dart';
18 import 'package:mobx/mobx.dart';
19
21 -class IoniaVerifyIoniaOtp extends BasePage {
22 - IoniaVerifyIoniaOtp(this._authViewModel, this._email, this.isSignIn)
20 +class CakePayVerifyOtpPage extends BasePage {
21 + CakePayVerifyOtpPage(this._authViewModel, this._email, this.isSignIn)
22 : _codeController = TextEditingController(),
23 _codeFocus = FocusNode() {
24 _codeController.addListener(() {
25 final otp = _codeController.text;
26 _authViewModel.otp = otp;
28 - if (otp.length > 3) {
29 - _authViewModel.otpState = IoniaOtpSendEnabled();
27 + if (otp.length > 5) {
28 + _authViewModel.otpState = CakePayOtpSendEnabled();
29 } else {
31 - _authViewModel.otpState = IoniaOtpSendDisabled();
30 + _authViewModel.otpState = CakePayOtpSendDisabled();
31 }
32 });
33 }
34
36 - final IoniaAuthViewModel _authViewModel;
35 + final CakePayAuthViewModel _authViewModel;
36 final bool isSignIn;
37
38 final String _email;
@@ -53,11 +52,11 @@ class IoniaVerifyIoniaOtp extends BasePage {
52
53 @override
54 Widget body(BuildContext context) {
56 - reaction((_) => _authViewModel.otpState, (IoniaOtpState state) {
57 - if (state is IoniaOtpFailure) {
55 + reaction((_) => _authViewModel.otpState, (CakePayOtpState state) {
56 + if (state is CakePayOtpFailure) {
57 _onOtpFailure(context, state.error);
58 }
60 - if (state is IoniaOtpSuccess) {
59 + if (state is CakePayOtpSuccess) {
60 _onOtpSuccessful(context);
61 }
62 });
@@ -98,9 +97,7 @@ class IoniaVerifyIoniaOtp extends BasePage {
97 Text(S.of(context).didnt_get_code),
98 SizedBox(width: 20),
99 InkWell(
101 - onTap: () => isSignIn
102 - ? _authViewModel.signIn(_email)
103 - : _authViewModel.createUser(_email),
100 + onTap: () => _authViewModel.logIn(_email),
101 child: Text(
102 S.of(context).resend_code,
103 style: textSmallSemiBold(color: Palette.blueCraiola),
@@ -120,8 +117,8 @@ class IoniaVerifyIoniaOtp extends BasePage {
117 builder: (_) => LoadingPrimaryButton(
118 text: S.of(context).continue_text,
119 onPressed: _verify,
123 - isDisabled: _authViewModel.otpState is IoniaOtpSendDisabled,
124 - isLoading: _authViewModel.otpState is IoniaOtpValidating,
120 + isDisabled: _authViewModel.otpState is CakePayOtpSendDisabled,
121 + isLoading: _authViewModel.otpState is CakePayOtpValidating,
122 color: Theme.of(context).primaryColor,
123 textColor: Colors.white,
124 ),
@@ -149,8 +146,7 @@ class IoniaVerifyIoniaOtp extends BasePage {
146 }
147
148 void _onOtpSuccessful(BuildContext context) =>
152 - Navigator.of(context)
153 - .pushNamedAndRemoveUntil(Routes.ioniaManageCardsPage, (route) => route.isFirst);
149 + Navigator.pop(context);
150
151 void _verify() async => await _authViewModel.verifyEmail(_codeController.text);
152 }
lib/src/screens/cake_pay/auth/cake_pay_welcome_page.dart renamed
+41 -24
@@ -1,22 +1,22 @@
1 import 'package:cake_wallet/core/email_validator.dart';
2 -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
3 -import 'package:cake_wallet/ionia/ionia_create_state.dart';
2 +import 'package:cake_wallet/generated/i18n.dart';
3 +import 'package:cake_wallet/cake_pay/cake_pay_states.dart';
4 import 'package:cake_wallet/routes.dart';
5 import 'package:cake_wallet/src/screens/base_page.dart';
6 import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
7 import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
8 import 'package:cake_wallet/src/widgets/primary_button.dart';
9 import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
10 +import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
11 import 'package:cake_wallet/typography.dart';
12 import 'package:cake_wallet/utils/show_pop_up.dart';
12 -import 'package:cake_wallet/view_model/ionia/ionia_auth_view_model.dart';
13 +import 'package:cake_wallet/view_model/cake_pay/cake_pay_auth_view_model.dart';
14 import 'package:flutter/material.dart';
14 -import 'package:cake_wallet/generated/i18n.dart';
15 import 'package:flutter_mobx/flutter_mobx.dart';
16 import 'package:mobx/mobx.dart';
17
18 -class IoniaLoginPage extends BasePage {
19 - IoniaLoginPage(this._authViewModel)
18 +class CakePayWelcomePage extends BasePage {
19 + CakePayWelcomePage(this._authViewModel)
20 : _formKey = GlobalKey<FormState>(),
21 _emailController = TextEditingController() {
22 _emailController.text = _authViewModel.email;
@@ -25,14 +25,14 @@ class IoniaLoginPage extends BasePage {
25
26 final GlobalKey<FormState> _formKey;
27
28 - final IoniaAuthViewModel _authViewModel;
28 + final CakePayAuthViewModel _authViewModel;
29
30 final TextEditingController _emailController;
31
32 @override
33 Widget middle(BuildContext context) {
34 return Text(
35 - S.current.login,
35 + S.current.welcome_to_cakepay,
36 style: textMediumSemiBold(
37 color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
38 ),
@@ -41,25 +41,40 @@ class IoniaLoginPage extends BasePage {
41
42 @override
43 Widget body(BuildContext context) {
44 - reaction((_) => _authViewModel.signInState, (IoniaCreateAccountState state) {
45 - if (state is IoniaCreateStateFailure) {
44 + reaction((_) => _authViewModel.userVerificationState, (CakePayUserVerificationState state) {
45 + if (state is CakePayUserVerificationStateFailure) {
46 _onLoginUserFailure(context, state.error);
47 }
48 - if (state is IoniaCreateStateSuccess) {
48 + if (state is CakePayUserVerificationStateSuccess) {
49 _onLoginSuccessful(context, _authViewModel);
50 }
51 });
52 return ScrollableWithBottomSection(
53 contentPadding: EdgeInsets.all(24),
54 - content: Form(
55 - key: _formKey,
56 - child: BaseTextFormField(
57 - hintText: S.of(context).email_address,
58 - keyboardType: TextInputType.emailAddress,
59 - validator: EmailValidator(),
60 - controller: _emailController,
61 - onSubmit: (text) => _login(),
62 - ),
54 + content: Column(
55 + children: [
56 + SizedBox(height: 90),
57 + Form(
58 + key: _formKey,
59 + child: BaseTextFormField(
60 + hintText: S.of(context).email_address,
61 + keyboardType: TextInputType.emailAddress,
62 + validator: EmailValidator(),
63 + controller: _emailController,
64 + onSubmit: (text) => _login(),
65 + ),
66 + ),
67 + SizedBox(height: 20),
68 + Text(
69 + S.of(context).about_cake_pay,
70 + style: textLarge(
71 + color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
72 + ),
73 + ),
74 + SizedBox(height: 20),
75 + Text(S.of(context).cake_pay_account_note,
76 + style: textLarge(color: Theme.of(context).extension<CakeTextTheme>()!.titleColor)),
77 + ],
78 ),
79 bottomSectionPadding: EdgeInsets.symmetric(vertical: 36, horizontal: 24),
80 bottomSection: Column(
@@ -71,7 +86,8 @@ class IoniaLoginPage extends BasePage {
86 builder: (_) => LoadingPrimaryButton(
87 text: S.of(context).login,
88 onPressed: _login,
74 - isLoading: _authViewModel.signInState is IoniaCreateStateLoading,
89 + isLoading:
90 + _authViewModel.userVerificationState is CakePayUserVerificationStateLoading,
91 color: Theme.of(context).primaryColor,
92 textColor: Colors.white,
93 ),
@@ -98,9 +114,10 @@ class IoniaLoginPage extends BasePage {
114 });
115 }
116
101 - void _onLoginSuccessful(BuildContext context, IoniaAuthViewModel authViewModel) => Navigator.pushNamed(
117 + void _onLoginSuccessful(BuildContext context, CakePayAuthViewModel authViewModel) =>
118 + Navigator.pushReplacementNamed(
119 context,
103 - Routes.ioniaVerifyIoniaOtpPage,
120 + Routes.cakePayVerifyOtpPage,
121 arguments: [authViewModel.email, true],
122 );
123
@@ -108,6 +125,6 @@ class IoniaLoginPage extends BasePage {
125 if (_formKey.currentState != null && !_formKey.currentState!.validate()) {
126 return;
127 }
111 - await _authViewModel.signIn(_emailController.text);
128 + await _authViewModel.logIn(_emailController.text);
129 }
130 }
lib/src/screens/cake_pay/cake_pay.dart new
+5
@@ -0,0 +1,5 @@
1 +export 'auth/cake_pay_welcome_page.dart';
2 +export 'auth/cake_pay_verify_otp_page.dart';
3 +export 'cards/cake_pay_confirm_purchase_card_page.dart';
4 +export 'cards/cake_pay_cards_page.dart';
5 +export 'cards/cake_pay_buy_card_page.dart';
lib/src/screens/cake_pay/cards/cake_pay_buy_card_page.dart new
+474
@@ -0,0 +1,474 @@
1 +import 'package:auto_size_text/auto_size_text.dart';
2 +import 'package:cake_wallet/cake_pay/cake_pay_card.dart';
3 +import 'package:cake_wallet/cake_pay/cake_pay_payment_credantials.dart';
4 +import 'package:cake_wallet/cake_pay/cake_pay_service.dart';
5 +import 'package:cake_wallet/generated/i18n.dart';
6 +import 'package:cake_wallet/routes.dart';
7 +import 'package:cake_wallet/src/screens/base_page.dart';
8 +import 'package:cake_wallet/src/screens/cake_pay/widgets/image_placeholder.dart';
9 +import 'package:cake_wallet/src/screens/cake_pay/widgets/link_extractor.dart';
10 +import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
11 +import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
12 +import 'package:cake_wallet/src/widgets/number_text_fild_widget.dart';
13 +import 'package:cake_wallet/src/widgets/primary_button.dart';
14 +import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
15 +import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
16 +import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
17 +import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
18 +import 'package:cake_wallet/typography.dart';
19 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
20 +import 'package:cake_wallet/view_model/cake_pay/cake_pay_buy_card_view_model.dart';
21 +import 'package:cake_wallet/view_model/dashboard/dropdown_filter_item_widget.dart';
22 +import 'package:flutter/material.dart';
23 +import 'package:flutter/services.dart';
24 +import 'package:flutter_mobx/flutter_mobx.dart';
25 +import 'package:keyboard_actions/keyboard_actions.dart';
26 +
27 +class CakePayBuyCardPage extends BasePage {
28 + CakePayBuyCardPage(
29 + this.cakePayBuyCardViewModel,
30 + this.cakePayService,
31 + ) : _amountFieldFocus = FocusNode(),
32 + _amountController = TextEditingController(),
33 + _quantityFieldFocus = FocusNode(),
34 + _quantityController =
35 + TextEditingController(text: cakePayBuyCardViewModel.quantity.toString()) {
36 + _amountController.addListener(() {
37 + cakePayBuyCardViewModel.onAmountChanged(_amountController.text);
38 + });
39 + }
40 +
41 + final CakePayBuyCardViewModel cakePayBuyCardViewModel;
42 + final CakePayService cakePayService;
43 +
44 + @override
45 + String get title => cakePayBuyCardViewModel.card.name;
46 +
47 + @override
48 + bool get extendBodyBehindAppBar => true;
49 +
50 + @override
51 + AppBarStyle get appBarStyle => AppBarStyle.completelyTransparent;
52 +
53 + @override
54 + Widget? middle(BuildContext context) {
55 + return Text(
56 + title,
57 + textAlign: TextAlign.center,
58 + maxLines: 2,
59 + style: TextStyle(
60 + fontSize: 18.0,
61 + fontWeight: FontWeight.bold,
62 + fontFamily: 'Lato',
63 + color: titleColor(context)),
64 + );
65 + }
66 +
67 + final TextEditingController _amountController;
68 + final FocusNode _amountFieldFocus;
69 + final TextEditingController _quantityController;
70 + final FocusNode _quantityFieldFocus;
71 +
72 + @override
73 + Widget body(BuildContext context) {
74 + final card = cakePayBuyCardViewModel.card;
75 + final vendor = cakePayBuyCardViewModel.vendor;
76 +
77 + return KeyboardActions(
78 + disableScroll: true,
79 + config: KeyboardActionsConfig(
80 + keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
81 + keyboardBarColor: Theme.of(context).extension<KeyboardTheme>()!.keyboardBarColor,
82 + nextFocus: false,
83 + actions: [
84 + KeyboardActionsItem(
85 + focusNode: _amountFieldFocus,
86 + toolbarButtons: [(_) => KeyboardDoneButton()],
87 + ),
88 + ]),
89 + child: Container(
90 + color: Theme.of(context).colorScheme.background,
91 + child: ScrollableWithBottomSection(
92 + contentPadding: EdgeInsets.zero,
93 + content: Column(
94 + children: [
95 + ClipRRect(
96 + borderRadius: BorderRadius.only(
97 + bottomLeft: Radius.circular(25.0), bottomRight: Radius.circular(25.0)),
98 + child: Container(
99 + decoration: BoxDecoration(
100 + gradient: LinearGradient(
101 + colors: [
102 + Theme.of(context).extension<SendPageTheme>()!.firstGradientColor,
103 + Theme.of(context).extension<SendPageTheme>()!.secondGradientColor,
104 + ],
105 + begin: Alignment.topLeft,
106 + end: Alignment.bottomRight,
107 + ),
108 + ),
109 + height: responsiveLayoutUtil.screenHeight * 0.35,
110 + width: double.infinity,
111 + child: Column(
112 + children: [
113 + Expanded(flex: 4, child: const SizedBox()),
114 + Expanded(
115 + flex: 7,
116 + child: ClipRRect(
117 + borderRadius: BorderRadius.all(Radius.circular(10)),
118 + child: Image.network(
119 + card.cardImageUrl ?? '',
120 + fit: BoxFit.cover,
121 + loadingBuilder: (BuildContext context, Widget child,
122 + ImageChunkEvent? loadingProgress) {
123 + if (loadingProgress == null) return child;
124 + return Center(child: CircularProgressIndicator());
125 + },
126 + errorBuilder: (context, error, stackTrace) =>
127 + CakePayCardImagePlaceholder(),
128 + ),
129 + ),
130 + ),
131 + Expanded(child: const SizedBox()),
132 + ],
133 + )),
134 + ),
135 + Padding(
136 + padding: const EdgeInsets.symmetric(horizontal: 24),
137 + child: Container(
138 + height: responsiveLayoutUtil.screenHeight * 0.5,
139 + child: Column(
140 + crossAxisAlignment: CrossAxisAlignment.start,
141 + children: [
142 + SizedBox(height: 24),
143 + Expanded(
144 + child: Text(S.of(context).enter_amount,
145 + style: TextStyle(
146 + color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
147 + fontSize: 24,
148 + fontWeight: FontWeight.w600,
149 + )),
150 + ),
151 + card.denominations.isNotEmpty
152 + ? Expanded(
153 + flex: 2,
154 + child: _DenominationsAmountWidget(
155 + fiatCurrency: card.fiatCurrency.title,
156 + denominations: card.denominations,
157 + amountFieldFocus: _amountFieldFocus,
158 + amountController: _amountController,
159 + quantityFieldFocus: _quantityFieldFocus,
160 + quantityController: _quantityController,
161 + onAmountChanged: cakePayBuyCardViewModel.onAmountChanged,
162 + onQuantityChanged: cakePayBuyCardViewModel.onQuantityChanged,
163 + cakePayBuyCardViewModel: cakePayBuyCardViewModel,
164 + ),
165 + )
166 + : Expanded(
167 + flex: 2,
168 + child: _EnterAmountWidget(
169 + minValue: card.minValue ?? '-',
170 + maxValue: card.maxValue ?? '-',
171 + fiatCurrency: card.fiatCurrency.title,
172 + amountFieldFocus: _amountFieldFocus,
173 + amountController: _amountController,
174 + onAmountChanged: cakePayBuyCardViewModel.onAmountChanged,
175 + ),
176 + ),
177 + Expanded(
178 + flex: 5,
179 + child: Column(
180 + children: [
181 + if (vendor.cakeWarnings != null)
182 + Padding(
183 + padding: const EdgeInsets.only(bottom: 8.0),
184 + child: Container(
185 + decoration: BoxDecoration(
186 + color: Theme.of(context).primaryColor,
187 + borderRadius: BorderRadius.circular(10),
188 + border: Border.all(color: Colors.white.withOpacity(0.20)),
189 + ),
190 + child: Padding(
191 + padding: const EdgeInsets.all(8.0),
192 + child: Text(
193 + vendor.cakeWarnings!,
194 + textAlign: TextAlign.center,
195 + style: textSmallSemiBold(color: Colors.white),
196 + ),
197 + ),
198 + ),
199 + ),
200 + Expanded(
201 + child: SingleChildScrollView(
202 + child: ClickableLinksText(
203 + text: card.description ?? '',
204 + textStyle: TextStyle(
205 + color: Theme.of(context)
206 + .extension<CakeTextTheme>()!
207 + .secondaryTextColor,
208 + fontSize: 18,
209 + fontWeight: FontWeight.w400,
210 + ),
211 + ),
212 + ),
213 + ),
214 + ],
215 + ),
216 + ),
217 + ],
218 + ),
219 + ),
220 + ),
221 + ],
222 + ),
223 + bottomSection: Column(
224 + children: [
225 + Observer(builder: (_) {
226 + return Padding(
227 + padding: EdgeInsets.only(bottom: 12),
228 + child: PrimaryButton(
229 + onPressed: () => navigateToCakePayBuyCardDetailPage(context, card),
230 + text: S.of(context).buy_now,
231 + isDisabled: !cakePayBuyCardViewModel.isEnablePurchase,
232 + color: Theme.of(context).primaryColor,
233 + textColor: Colors.white,
234 + ),
235 + );
236 + }),
237 + ],
238 + ),
239 + ),
240 + ),
241 + );
242 + }
243 +
244 + Future<void> navigateToCakePayBuyCardDetailPage(BuildContext context, CakePayCard card) async {
245 + final userName = await cakePayService.getUserEmail();
246 + final paymentCredential = PaymentCredential(
247 + amount: cakePayBuyCardViewModel.amount,
248 + quantity: cakePayBuyCardViewModel.quantity,
249 + totalAmount: cakePayBuyCardViewModel.totalAmount,
250 + userName: userName,
251 + fiatCurrency: card.fiatCurrency.title,
252 + );
253 +
254 + Navigator.pushNamed(
255 + context,
256 + Routes.cakePayBuyCardDetailPage,
257 + arguments: [paymentCredential, card],
258 + );
259 + }
260 +}
261 +
262 +class _DenominationsAmountWidget extends StatelessWidget {
263 + const _DenominationsAmountWidget({
264 + required this.fiatCurrency,
265 + required this.denominations,
266 + required this.amountFieldFocus,
267 + required this.amountController,
268 + required this.quantityFieldFocus,
269 + required this.quantityController,
270 + required this.cakePayBuyCardViewModel,
271 + required this.onAmountChanged,
272 + required this.onQuantityChanged,
273 + });
274 +
275 + final String fiatCurrency;
276 + final List<String> denominations;
277 + final FocusNode amountFieldFocus;
278 + final TextEditingController amountController;
279 + final FocusNode quantityFieldFocus;
280 + final TextEditingController quantityController;
281 + final CakePayBuyCardViewModel cakePayBuyCardViewModel;
282 + final Function(String) onAmountChanged;
283 + final Function(int?) onQuantityChanged;
284 +
285 + @override
286 + Widget build(BuildContext context) {
287 + return Row(
288 + crossAxisAlignment: CrossAxisAlignment.start,
289 + children: [
290 + Expanded(
291 + flex: 12,
292 + child: Column(
293 + children: [
294 + Expanded(
295 + child: DropdownFilterList(
296 + items: denominations,
297 + itemPrefix: fiatCurrency,
298 + selectedItem: denominations.first,
299 + textStyle: textMediumSemiBold(
300 + color: Theme.of(context).extension<CakeTextTheme>()!.titleColor),
301 + onItemSelected: (value) {
302 + amountController.text = value;
303 + onAmountChanged(value);
304 + },
305 + caption: '',
306 + ),
307 + ),
308 + const SizedBox(height: 4),
309 + Expanded(
310 + child: Container(
311 + width: double.infinity,
312 + decoration: BoxDecoration(
313 + border: Border(
314 + top: BorderSide(
315 + width: 1.0,
316 + color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor),
317 + ),
318 + ),
319 + child: Text(S.of(context).choose_card_value + ':',
320 + maxLines: 2,
321 + style: textSmall(
322 + color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor)),
323 + ),
324 + ),
325 + ],
326 + ),
327 + ),
328 + Expanded(child: const SizedBox()),
329 + Expanded(
330 + flex: 8,
331 + child: Column(
332 + children: [
333 + Expanded(
334 + child: NumberTextField(
335 + controller: quantityController,
336 + focusNode: quantityFieldFocus,
337 + min: 1,
338 + max: 99,
339 + onChanged: (value) => onQuantityChanged(value),
340 + ),
341 + ),
342 + const SizedBox(height: 4),
343 + Expanded(
344 + child: Container(
345 + width: double.infinity,
346 + decoration: BoxDecoration(
347 + border: Border(
348 + top: BorderSide(
349 + width: 1.0,
350 + color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor),
351 + ),
352 + ),
353 + child: Text(S.of(context).quantity + ':',
354 + maxLines: 1,
355 + style: textSmall(
356 + color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor)),
357 + ),
358 + ),
359 + ],
360 + ),
361 + ),
362 + Expanded(child: const SizedBox()),
363 + Expanded(
364 + flex: 12,
365 + child: Column(
366 + children: [
367 + Expanded(
368 + child: Container(
369 + alignment: Alignment.bottomCenter,
370 + child: Observer(
371 + builder: (_) => AutoSizeText(
372 + '$fiatCurrency ${cakePayBuyCardViewModel.totalAmount}',
373 + maxLines: 1,
374 + style: textMediumSemiBold(
375 + color:
376 + Theme.of(context).extension<CakeTextTheme>()!.titleColor)))),
377 + ),
378 + const SizedBox(height: 4),
379 + Expanded(
380 + child: Container(
381 + width: double.infinity,
382 + decoration: BoxDecoration(
383 + border: Border(
384 + top: BorderSide(
385 + width: 1.0,
386 + color:
387 + Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor),
388 + ),
389 + ),
390 + child: Text(S.of(context).total + ':',
391 + maxLines: 1,
392 + style: textSmall(
393 + color:
394 + Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor)),
395 + ),
396 + ),
397 + ],
398 + )),
399 + ],
400 + );
401 + }
402 +}
403 +
404 +class _EnterAmountWidget extends StatelessWidget {
405 + const _EnterAmountWidget({
406 + required this.minValue,
407 + required this.maxValue,
408 + required this.fiatCurrency,
409 + required this.amountFieldFocus,
410 + required this.amountController,
411 + required this.onAmountChanged,
412 + });
413 +
414 + final String minValue;
415 + final String maxValue;
416 + final String fiatCurrency;
417 + final FocusNode amountFieldFocus;
418 + final TextEditingController amountController;
419 + final Function(String) onAmountChanged;
420 +
421 + @override
422 + Widget build(BuildContext context) {
423 + return Column(
424 + children: [
425 + Container(
426 + decoration: BoxDecoration(
427 + border: Border(
428 + bottom: BorderSide(
429 + width: 1.0,
430 + color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor),
431 + ),
432 + ),
433 + child: BaseTextFormField(
434 + controller: amountController,
435 + keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true),
436 + hintText: '0.00',
437 + maxLines: null,
438 + borderColor: Colors.transparent,
439 + prefixIcon: Padding(
440 + padding: const EdgeInsets.only(top: 12),
441 + child: Text(
442 + '$fiatCurrency: ',
443 + style: textMediumSemiBold(
444 + color: Theme.of(context).extension<CakeTextTheme>()!.titleColor),
445 + ),
446 + ),
447 + textStyle:
448 + textMediumSemiBold(color: Theme.of(context).extension<CakeTextTheme>()!.titleColor),
449 + placeholderTextStyle: textMediumSemiBold(
450 + color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor),
451 + inputFormatters: [
452 + FilteringTextInputFormatter.deny(RegExp('[\-|\ ]')),
453 + FilteringTextInputFormatter.allow(
454 + RegExp(r'^\d+(\.|\,)?\d{0,2}'),
455 + ),
456 + ],
457 + ),
458 + ),
459 + SizedBox(height: 4),
460 + Row(
461 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
462 + children: [
463 + Text(S.of(context).min_amount(minValue) + ' $fiatCurrency',
464 + style: textSmall(
465 + color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor)),
466 + Text(S.of(context).max_amount(maxValue) + ' $fiatCurrency',
467 + style: textSmall(
468 + color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor)),
469 + ],
470 + ),
471 + ],
472 + );
473 + }
474 +}
lib/src/screens/cake_pay/cards/cake_pay_cards_page.dart renamed
+138 -102
@@ -1,42 +1,40 @@
1 -import 'package:cake_wallet/ionia/ionia_create_state.dart';
2 -import 'package:cake_wallet/ionia/ionia_merchant.dart';
1 +import 'package:cake_wallet/cake_pay/cake_pay_states.dart';
2 +import 'package:cake_wallet/cake_pay/cake_pay_vendor.dart';
3 +import 'package:cake_wallet/generated/i18n.dart';
4 import 'package:cake_wallet/routes.dart';
5 import 'package:cake_wallet/src/screens/base_page.dart';
5 -import 'package:cake_wallet/src/widgets/gradient_background.dart';
6 -import 'package:cake_wallet/src/screens/ionia/widgets/card_item.dart';
7 -import 'package:cake_wallet/src/screens/ionia/widgets/card_menu.dart';
8 -import 'package:cake_wallet/src/screens/ionia/widgets/ionia_filter_modal.dart';
6 +import 'package:cake_wallet/src/screens/cake_pay/widgets/card_item.dart';
7 +import 'package:cake_wallet/src/screens/cake_pay/widgets/card_menu.dart';
8 +import 'package:cake_wallet/src/screens/dashboard/widgets/filter_widget.dart';
9 import 'package:cake_wallet/src/widgets/cake_scrollbar.dart';
10 +import 'package:cake_wallet/src/widgets/gradient_background.dart';
11 +import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
12 +import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
13 import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
14 +import 'package:cake_wallet/themes/extensions/filter_theme.dart';
15 import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
12 -import 'package:cake_wallet/themes/theme_base.dart';
13 -import 'package:cake_wallet/utils/debounce.dart';
16 import 'package:cake_wallet/typography.dart';
17 +import 'package:cake_wallet/utils/debounce.dart';
18 +import 'package:cake_wallet/utils/responsive_layout_util.dart';
19 import 'package:cake_wallet/utils/show_pop_up.dart';
16 -import 'package:cake_wallet/view_model/ionia/ionia_gift_cards_list_view_model.dart';
17 -import 'package:flutter/cupertino.dart';
20 +import 'package:cake_wallet/view_model/cake_pay/cake_pay_cards_list_view_model.dart';
21 import 'package:flutter/material.dart';
19 -import 'package:cake_wallet/generated/i18n.dart';
22 import 'package:flutter_mobx/flutter_mobx.dart';
21 -import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
22 -import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
23 -import 'package:cake_wallet/themes/extensions/filter_theme.dart';
23
25 -class IoniaManageCardsPage extends BasePage {
26 - IoniaManageCardsPage(this._cardsListViewModel): searchFocusNode = FocusNode() {
24 +class CakePayCardsPage extends BasePage {
25 + CakePayCardsPage(this._cardsListViewModel) : searchFocusNode = FocusNode() {
26 _searchController.addListener(() {
27 if (_searchController.text != _cardsListViewModel.searchString) {
28 _searchDebounce.run(() {
30 - _cardsListViewModel.searchMerchant(_searchController.text);
29 + _cardsListViewModel.resetLoadingNextPageState();
30 + _cardsListViewModel.getVendors(text: _searchController.text);
31 });
32 }
33 });
34 -
35 - _cardsListViewModel.getMerchants();
36 -
34 }
35 +
36 final FocusNode searchFocusNode;
39 - final IoniaGiftCardsListViewModel _cardsListViewModel;
37 + final CakePayCardsListViewModel _cardsListViewModel;
38
39 final _searchDebounce = Debounce(Duration(milliseconds: 500));
40 final _searchController = TextEditingController();
@@ -46,8 +44,7 @@ class IoniaManageCardsPage extends BasePage {
44
45 @override
46 Widget Function(BuildContext, Widget) get rootWrapper =>
49 - (BuildContext context, Widget scaffold) =>
50 - GradientBackground(scaffold: scaffold);
47 + (BuildContext context, Widget scaffold) => GradientBackground(scaffold: scaffold);
48
49 @override
50 bool get resizeToAvoidBottomInset => false;
@@ -58,7 +55,7 @@ class IoniaManageCardsPage extends BasePage {
55 @override
56 Widget middle(BuildContext context) {
57 return Text(
61 - S.of(context).gift_cards,
58 + 'Cake Pay',
59 style: textMediumSemiBold(
60 color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
61 ),
@@ -68,9 +65,17 @@ class IoniaManageCardsPage extends BasePage {
65 @override
66 Widget trailing(BuildContext context) {
67 return _TrailingIcon(
71 - asset: 'assets/images/profile.png',
72 - onPressed: () => Navigator.pushNamed(context, Routes.ioniaAccountPage),
73 - );
68 + asset: 'assets/images/profile.png',
69 + iconColor: pageIconColor(context) ?? Colors.white,
70 + onPressed: () {
71 + _cardsListViewModel.isCakePayUserAuthenticated().then((value) {
72 + if (value) {
73 + Navigator.pushNamed(context, Routes.cakePayAccountPage);
74 + return;
75 + }
76 + Navigator.pushNamed(context, Routes.cakePayWelcomePage);
77 + });
78 + });
79 }
80
81 @override
@@ -79,8 +84,12 @@ class IoniaManageCardsPage extends BasePage {
84 label: S.of(context).filter_by,
85 child: InkWell(
86 onTap: () async {
82 - await showCategoryFilter(context);
83 - _cardsListViewModel.getMerchants();
87 + _cardsListViewModel.storeInitialFilterStates();
88 + await showFilterWidget(context);
89 + if (_cardsListViewModel.hasFiltersChanged) {
90 + _cardsListViewModel.resetLoadingNextPageState();
91 + _cardsListViewModel.getVendors();
92 + }
93 },
94 child: Container(
95 width: 32,
@@ -120,7 +129,7 @@ class IoniaManageCardsPage extends BasePage {
129 ),
130 SizedBox(height: 8),
131 Expanded(
123 - child: IoniaManageCardsPageBody(
132 + child: CakePayCardsPageBody(
133 cardsListViewModel: _cardsListViewModel,
134 ),
135 ),
@@ -129,36 +138,35 @@ class IoniaManageCardsPage extends BasePage {
138 );
139 }
140
132 - Future <void> showCategoryFilter(BuildContext context) async {
141 + Future<void> showFilterWidget(BuildContext context) async {
142 return showPopUp<void>(
143 context: context,
144 builder: (BuildContext context) {
136 - return IoniaFilterModal(
137 - ioniaGiftCardsListViewModel: _cardsListViewModel,
138 - );
145 + return FilterWidget(filterItems: _cardsListViewModel.createFilterItems);
146 },
147 );
148 }
149 }
150
144 -class IoniaManageCardsPageBody extends StatefulWidget {
145 - const IoniaManageCardsPageBody({
151 +class CakePayCardsPageBody extends StatefulWidget {
152 + const CakePayCardsPageBody({
153 Key? key,
154 required this.cardsListViewModel,
155 }) : super(key: key);
156
150 - final IoniaGiftCardsListViewModel cardsListViewModel;
157 + final CakePayCardsListViewModel cardsListViewModel;
158
159 @override
153 - _IoniaManageCardsPageBodyState createState() => _IoniaManageCardsPageBodyState();
160 + _CakePayCardsPageBodyState createState() => _CakePayCardsPageBodyState();
161 }
162
156 -class _IoniaManageCardsPageBodyState extends State<IoniaManageCardsPageBody> {
163 +class _CakePayCardsPageBodyState extends State<CakePayCardsPageBody> {
164 double get backgroundHeight => MediaQuery.of(context).size.height * 0.75;
165 double thumbHeight = 72;
159 - bool get isAlwaysShowScrollThumb => merchantsList == null ? false : merchantsList.length > 3;
166
161 - List<IoniaMerchant> get merchantsList => widget.cardsListViewModel.ioniaMerchants;
167 + bool get isAlwaysShowScrollThumb => merchantsList.isEmpty ? false : merchantsList.length > 3;
168 +
169 + List<CakePayVendor> get merchantsList => widget.cardsListViewModel.cakePayVendors;
170
171 final _scrollController = ScrollController();
172
@@ -166,61 +174,93 @@ class _IoniaManageCardsPageBodyState extends State<IoniaManageCardsPageBody> {
174 void initState() {
175 _scrollController.addListener(() {
176 final scrollOffsetFromTop = _scrollController.hasClients
169 - ? (_scrollController.offset / _scrollController.position.maxScrollExtent * (backgroundHeight - thumbHeight))
177 + ? (_scrollController.offset /
178 + _scrollController.position.maxScrollExtent *
179 + (backgroundHeight - thumbHeight))
180 : 0.0;
181 widget.cardsListViewModel.setScrollOffsetFromTop(scrollOffsetFromTop);
182 +
183 + double threshold = 200.0;
184 + bool isNearBottom =
185 + _scrollController.offset >= _scrollController.position.maxScrollExtent - threshold;
186 + if (isNearBottom && !_scrollController.position.outOfRange) {
187 + widget.cardsListViewModel.fetchNextPage();
188 + }
189 });
190 super.initState();
191 }
192
193 @override
194 Widget build(BuildContext context) {
178 - return Observer(
179 - builder: (_) {
180 - final merchantState = widget.cardsListViewModel.merchantState;
181 - if (merchantState is IoniaLoadedMerchantState) {
195 + return Observer(builder: (_) {
196 + final vendorsState = widget.cardsListViewModel.vendorsState;
197 + if (vendorsState is CakePayVendorLoadedState) {
198 + bool isLoadingMore = widget.cardsListViewModel.isLoadingNextPage;
199 + final vendors = widget.cardsListViewModel.cakePayVendors;
200 +
201 + if (vendors.isEmpty) {
202 + return Center(child: Text(S.of(context).no_cards_found));
203 + }
204 return Stack(children: [
183 - ListView.separated(
184 - padding: EdgeInsets.only(left: 2, right: 22),
185 - controller: _scrollController,
186 - itemCount: merchantsList.length,
187 - separatorBuilder: (_, __) => SizedBox(height: 4),
188 - itemBuilder: (_, index) {
189 - final merchant = merchantsList[index];
190 - return CardItem(
191 - logoUrl: merchant.logoUrl,
192 - onTap: () {
193 - Navigator.of(context).pushNamed(Routes.ioniaBuyGiftCardPage, arguments: [merchant]);
194 - },
195 - title: merchant.legalName,
196 - subTitle: merchant.avaibilityStatus,
197 - backgroundColor: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
198 - titleColor: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
199 - subtitleColor: Theme.of(context).extension<BalancePageTheme>()!.labelTextColor,
200 - discount: merchant.discount,
201 - );
202 - },
203 - ),
204 - isAlwaysShowScrollThumb
205 - ? CakeScrollbar(
206 - backgroundHeight: backgroundHeight,
207 - thumbHeight: thumbHeight,
208 - rightOffset: 1,
209 - width: 3,
210 - backgroundColor: Theme.of(context).extension<FilterTheme>()!.iconColor.withOpacity(0.05),
211 - thumbColor: Theme.of(context).extension<FilterTheme>()!.iconColor.withOpacity(0.5),
212 - fromTop: widget.cardsListViewModel.scrollOffsetFromTop,
213 - )
214 - : Offstage()
215 - ]);
216 - }
217 - return Center(
218 - child: CircularProgressIndicator(
219 - backgroundColor: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
220 - valueColor: AlwaysStoppedAnimation<Color>(Theme.of(context).extension<ExchangePageTheme>()!.firstGradientBottomPanelColor),
205 + GridView.builder(
206 + controller: _scrollController,
207 + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
208 + crossAxisCount: responsiveLayoutUtil.shouldRenderTabletUI ? 2 : 1,
209 + childAspectRatio: 5,
210 + crossAxisSpacing: responsiveLayoutUtil.shouldRenderTabletUI ? 10 : 5,
211 + mainAxisSpacing: responsiveLayoutUtil.shouldRenderTabletUI ? 10 : 5,
212 + ),
213 + padding: EdgeInsets.only(left: 2, right: 22),
214 + itemCount: vendors.length + (isLoadingMore ? 1 : 0),
215 + itemBuilder: (_, index) {
216 + if (index >= vendors.length) {
217 + return _VendorLoadedIndicator();
218 + }
219 + final vendor = vendors[index];
220 + return CardItem(
221 + logoUrl: vendor.card?.cardImageUrl,
222 + onTap: () {
223 + Navigator.of(context).pushNamed(Routes.cakePayBuyCardPage, arguments: [vendor]);
224 + },
225 + title: vendor.name,
226 + subTitle: vendor.card?.description ?? '',
227 + backgroundColor:
228 + Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
229 + titleColor: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
230 + subtitleColor: Theme.of(context).extension<BalancePageTheme>()!.labelTextColor,
231 + discount: 0.0,
232 + );
233 + },
234 ),
222 - );
235 + isAlwaysShowScrollThumb
236 + ? CakeScrollbar(
237 + backgroundHeight: backgroundHeight,
238 + thumbHeight: thumbHeight,
239 + rightOffset: 1,
240 + width: 3,
241 + backgroundColor:
242 + Theme.of(context).extension<FilterTheme>()!.iconColor.withOpacity(0.05),
243 + thumbColor:
244 + Theme.of(context).extension<FilterTheme>()!.iconColor.withOpacity(0.5),
245 + fromTop: widget.cardsListViewModel.scrollOffsetFromTop,
246 + )
247 + : Offstage()
248 + ]);
249 }
250 + return _VendorLoadedIndicator();
251 + });
252 + }
253 +}
254 +
255 +class _VendorLoadedIndicator extends StatelessWidget {
256 + @override
257 + Widget build(BuildContext context) {
258 + return Center(
259 + child: CircularProgressIndicator(
260 + backgroundColor: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
261 + valueColor: AlwaysStoppedAnimation<Color>(
262 + Theme.of(context).extension<ExchangePageTheme>()!.firstGradientBottomPanelColor),
263 + ),
264 );
265 }
266 }
@@ -233,6 +273,7 @@ class _SearchWidget extends StatelessWidget {
273 }) : super(key: key);
274 final TextEditingController controller;
275 final FocusNode focusNode;
276 +
277 @override
278 Widget build(BuildContext context) {
279 final searchIcon = ExcludeSemantics(
@@ -284,30 +325,25 @@ class _SearchWidget extends StatelessWidget {
325 }
326
327 class _TrailingIcon extends StatelessWidget {
287 - const _TrailingIcon({required this.asset, this.onPressed});
328 + const _TrailingIcon({required this.asset, this.onPressed, required this.iconColor});
329
330 final String asset;
331 final VoidCallback? onPressed;
332 + final Color iconColor;
333
334 @override
335 Widget build(BuildContext context) {
336 return Semantics(
295 - label: S.of(context).profile,
296 - child: Material(
297 - color: Colors.transparent,
298 - child: IconButton(
299 - padding: EdgeInsets.zero,
300 - constraints: BoxConstraints(),
301 - highlightColor: Colors.transparent,
302 - splashColor: Colors.transparent,
303 - iconSize: 25,
304 - onPressed: onPressed,
305 - icon: Image.asset(
306 - asset,
307 - color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
337 + label: S.of(context).profile,
338 + child: Material(
339 + color: Colors.transparent,
340 + child: IconButton(
341 + padding: EdgeInsets.zero,
342 + constraints: BoxConstraints(),
343 + highlightColor: Colors.transparent,
344 + onPressed: onPressed,
345 + icon: ImageIcon(AssetImage(asset), size: 25, color: iconColor),
346 ),
309 - ),
310 - ),
311 - );
347 + ));
348 }
349 }
lib/src/screens/cake_pay/cards/cake_pay_confirm_purchase_card_page.dart new
+403
@@ -0,0 +1,403 @@
1 +import 'package:cake_wallet/core/execution_state.dart';
2 +import 'package:cake_wallet/generated/i18n.dart';
3 +import 'package:cake_wallet/cake_pay/cake_pay_card.dart';
4 +import 'package:cake_wallet/routes.dart';
5 +import 'package:cake_wallet/src/screens/base_page.dart';
6 +import 'package:cake_wallet/src/screens/cake_pay/widgets/cake_pay_alert_modal.dart';
7 +import 'package:cake_wallet/src/screens/cake_pay/widgets/image_placeholder.dart';
8 +import 'package:cake_wallet/src/screens/cake_pay/widgets/link_extractor.dart';
9 +import 'package:cake_wallet/src/screens/cake_pay/widgets/text_icon_button.dart';
10 +import 'package:cake_wallet/src/screens/send/widgets/confirm_sending_alert.dart';
11 +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
12 +import 'package:cake_wallet/src/widgets/primary_button.dart';
13 +import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
14 +import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
15 +import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
16 +import 'package:cake_wallet/themes/extensions/picker_theme.dart';
17 +import 'package:cake_wallet/themes/extensions/receive_page_theme.dart';
18 +import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
19 +import 'package:cake_wallet/typography.dart';
20 +import 'package:cake_wallet/utils/show_pop_up.dart';
21 +import 'package:cake_wallet/view_model/cake_pay/cake_pay_purchase_view_model.dart';
22 +import 'package:cake_wallet/view_model/send/send_view_model_state.dart';
23 +import 'package:flutter/material.dart';
24 +import 'package:flutter_mobx/flutter_mobx.dart';
25 +import 'package:mobx/mobx.dart';
26 +
27 +class CakePayBuyCardDetailPage extends BasePage {
28 + CakePayBuyCardDetailPage(this.cakePayPurchaseViewModel);
29 +
30 + final CakePayPurchaseViewModel cakePayPurchaseViewModel;
31 +
32 + @override
33 + String get title => cakePayPurchaseViewModel.card.name;
34 +
35 + @override
36 + Widget? middle(BuildContext context) {
37 + return Text(
38 + title,
39 + textAlign: TextAlign.center,
40 + maxLines: 2,
41 + style: TextStyle(
42 + fontSize: 18.0,
43 + fontWeight: FontWeight.bold,
44 + fontFamily: 'Lato',
45 + color: titleColor(context)),
46 + );
47 + }
48 +
49 + @override
50 + Widget? trailing(BuildContext context) => null;
51 +
52 + bool _effectsInstalled = false;
53 +
54 + @override
55 + Widget body(BuildContext context) {
56 + _setEffects(context);
57 +
58 + final card = cakePayPurchaseViewModel.card;
59 +
60 + return ScrollableWithBottomSection(
61 + contentPadding: EdgeInsets.zero,
62 + content: Observer(builder: (_) {
63 + return Column(
64 + children: [
65 + SizedBox(height: 36),
66 + ClipRRect(
67 + borderRadius:
68 + BorderRadius.horizontal(left: Radius.circular(20), right: Radius.circular(20)),
69 + child: Container(
70 + decoration: BoxDecoration(
71 + color: Theme.of(context).extension<PickerTheme>()!.searchBackgroundFillColor,
72 + borderRadius: BorderRadius.circular(20),
73 + border: Border.all(color: Colors.white.withOpacity(0.20)),
74 + ),
75 + child: Row(
76 + children: [
77 + Expanded(
78 + child: Container(
79 + child: ClipRRect(
80 + borderRadius: BorderRadius.horizontal(
81 + left: Radius.circular(20), right: Radius.circular(20)),
82 + child: Image.network(
83 + card.cardImageUrl ?? '',
84 + fit: BoxFit.cover,
85 + loadingBuilder: (BuildContext context, Widget child,
86 + ImageChunkEvent? loadingProgress) {
87 + if (loadingProgress == null) return child;
88 + return Center(child: CircularProgressIndicator());
89 + },
90 + errorBuilder: (context, error, stackTrace) =>
91 + CakePayCardImagePlaceholder(),
92 + ),
93 + )),
94 + ),
95 + Expanded(
96 + child: Padding(
97 + padding: const EdgeInsets.symmetric(horizontal: 8.0),
98 + child: Column(children: [
99 + Row(
100 + children: [
101 + Text(
102 + S.of(context).value + ':',
103 + style: textLarge(
104 + color:
105 + Theme.of(context).extension<CakeTextTheme>()!.titleColor),
106 + ),
107 + SizedBox(width: 8),
108 + Text(
109 + '${cakePayPurchaseViewModel.amount.toStringAsFixed(2)} ${cakePayPurchaseViewModel.fiatCurrency}',
110 + style: textLarge(
111 + color:
112 + Theme.of(context).extension<CakeTextTheme>()!.titleColor),
113 + ),
114 + ],
115 + ),
116 + SizedBox(height: 16),
117 + Row(
118 + children: [
119 + Text(
120 + S.of(context).quantity + ':',
121 + style: textLarge(
122 + color:
123 + Theme.of(context).extension<CakeTextTheme>()!.titleColor),
124 + ),
125 + SizedBox(width: 8),
126 + Text(
127 + '${cakePayPurchaseViewModel.quantity}',
128 + style: textLarge(
129 + color:
130 + Theme.of(context).extension<CakeTextTheme>()!.titleColor),
131 + ),
132 + ],
133 + ),
134 + SizedBox(height: 16),
135 + Row(
136 + children: [
137 + Text(
138 + S.of(context).total + ':',
139 + style: textLarge(
140 + color:
141 + Theme.of(context).extension<CakeTextTheme>()!.titleColor),
142 + ),
143 + SizedBox(width: 8),
144 + Text(
145 + '${cakePayPurchaseViewModel.totalAmount.toStringAsFixed(2)} ${cakePayPurchaseViewModel.fiatCurrency}',
146 + style: textLarge(
147 + color:
148 + Theme.of(context).extension<CakeTextTheme>()!.titleColor),
149 + ),
150 + ],
151 + ),
152 + ]),
153 + ),
154 + )
155 + ],
156 + ),
157 + ),
158 + ),
159 + SizedBox(height: 20),
160 + Padding(
161 + padding: const EdgeInsets.symmetric(horizontal: 24.0),
162 + child: TextIconButton(
163 + label: S.of(context).how_to_use_card,
164 + onTap: () => _showHowToUseCard(context, card),
165 + ),
166 + ),
167 + SizedBox(height: 20),
168 + if (card.expiryAndValidity != null && card.expiryAndValidity!.isNotEmpty)
169 + Padding(
170 + padding: const EdgeInsets.symmetric(horizontal: 24.0),
171 + child: Column(
172 + crossAxisAlignment: CrossAxisAlignment.start,
173 + children: [
174 + Text(S.of(context).expiry_and_validity + ':',
175 + style: textMediumSemiBold(
176 + color: Theme.of(context).extension<CakeTextTheme>()!.titleColor)),
177 + SizedBox(height: 10),
178 + Container(
179 + width: double.infinity,
180 + decoration: BoxDecoration(
181 + border: Border(
182 + bottom: BorderSide(
183 + color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
184 + width: 1,
185 + ),
186 + ),
187 + ),
188 + child: Padding(
189 + padding: const EdgeInsets.only(bottom: 8.0),
190 + child: Text(
191 + card.expiryAndValidity ?? '',
192 + style: textMedium(
193 + color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
194 + ),
195 + ),
196 + ),
197 + ),
198 + ],
199 + ),
200 + ),
201 + ],
202 + );
203 + }),
204 + bottomSection: Column(
205 + children: [
206 + Padding(
207 + padding: EdgeInsets.only(bottom: 12),
208 + child: Observer(builder: (_) {
209 + return LoadingPrimaryButton(
210 + isLoading: cakePayPurchaseViewModel.sendViewModel.state is IsExecutingState,
211 + onPressed: () => purchaseCard(context),
212 + text: S.of(context).purchase_gift_card,
213 + color: Theme.of(context).primaryColor,
214 + textColor: Colors.white,
215 + );
216 + }),
217 + ),
218 + SizedBox(height: 8),
219 + InkWell(
220 + onTap: () => _showTermsAndCondition(context, card.termsAndConditions),
221 + child: Text(S.of(context).settings_terms_and_conditions,
222 + style: textMediumSemiBold(
223 + color: Theme.of(context).primaryColor,
224 + ).copyWith(fontSize: 12)),
225 + ),
226 + SizedBox(height: 16)
227 + ],
228 + ),
229 + );
230 + }
231 +
232 + void _showTermsAndCondition(BuildContext context, String? termsAndConditions) {
233 + showPopUp<void>(
234 + context: context,
235 + builder: (BuildContext context) {
236 + return CakePayAlertModal(
237 + title: S.of(context).settings_terms_and_conditions,
238 + content: Align(
239 + alignment: Alignment.bottomLeft,
240 + child: ClickableLinksText(
241 + text: termsAndConditions ?? '',
242 + textStyle: TextStyle(
243 + color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
244 + fontSize: 18,
245 + fontWeight: FontWeight.w400,
246 + ),
247 + ),
248 + ),
249 + actionTitle: S.of(context).agree,
250 + showCloseButton: false,
251 + heightFactor: 0.6,
252 + );
253 + });
254 + }
255 +
256 + Future<void> purchaseCard(BuildContext context) async {
257 + bool isLogged = await cakePayPurchaseViewModel.cakePayService.isLogged();
258 + if (!isLogged) {
259 + Navigator.of(context).pushNamed(Routes.cakePayWelcomePage);
260 + } else {
261 + await cakePayPurchaseViewModel.createOrder();
262 + }
263 + }
264 +
265 + void _showHowToUseCard(
266 + BuildContext context,
267 + CakePayCard card,
268 + ) {
269 + showPopUp<void>(
270 + context: context,
271 + builder: (BuildContext context) {
272 + return CakePayAlertModal(
273 + title: S.of(context).how_to_use_card,
274 + content: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
275 + Padding(
276 + padding: EdgeInsets.all(10),
277 + child: Text(
278 + card.name,
279 + style: textLargeSemiBold(
280 + color: Theme.of(context).extension<ReceivePageTheme>()!.tilesTextColor,
281 + ),
282 + )),
283 + ClickableLinksText(
284 + text: card.howToUse ?? '',
285 + textStyle: TextStyle(
286 + color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor,
287 + fontSize: 18,
288 + fontWeight: FontWeight.w400,
289 + ),
290 + linkStyle: TextStyle(
291 + color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
292 + fontSize: 18,
293 + fontStyle: FontStyle.italic,
294 + fontWeight: FontWeight.w400,
295 + ),
296 + ),
297 + ]),
298 + actionTitle: S.current.got_it,
299 + );
300 + });
301 + }
302 +
303 + Future<void> _showConfirmSendingAlert(BuildContext context) async {
304 + if (cakePayPurchaseViewModel.order == null) {
305 + return;
306 + }
307 + ReactionDisposer? disposer;
308 +
309 + disposer = reaction((_) => cakePayPurchaseViewModel.isOrderExpired, (bool isExpired) {
310 + if (isExpired) {
311 + if (Navigator.of(context).canPop()) {
312 + Navigator.of(context).pop();
313 + }
314 + if (disposer != null) {
315 + disposer();
316 + }
317 + }
318 + });
319 +
320 + final order = cakePayPurchaseViewModel.order;
321 + final pendingTransaction = cakePayPurchaseViewModel.sendViewModel.pendingTransaction!;
322 +
323 + await showPopUp<void>(
324 + context: context,
325 + builder: (_) {
326 + return Observer(
327 + builder: (_) => ConfirmSendingAlert(
328 + alertTitle: S.of(context).confirm_sending,
329 + paymentId: S.of(context).payment_id,
330 + paymentIdValue: order?.orderId,
331 + expirationTime: cakePayPurchaseViewModel.formattedRemainingTime,
332 + onDispose: () => _handleDispose(disposer),
333 + amount: S.of(context).send_amount,
334 + amountValue: pendingTransaction.amountFormatted,
335 + fiatAmountValue:
336 + cakePayPurchaseViewModel.sendViewModel.pendingTransactionFiatAmountFormatted,
337 + fee: S.of(context).send_fee,
338 + feeValue: pendingTransaction.feeFormatted,
339 + feeFiatAmount:
340 + cakePayPurchaseViewModel.sendViewModel.pendingTransactionFeeFiatAmountFormatted,
341 + feeRate: pendingTransaction.feeRate,
342 + outputs: cakePayPurchaseViewModel.sendViewModel.outputs,
343 + rightButtonText: S.of(context).send,
344 + leftButtonText: S.of(context).cancel,
345 + actionRightButton: () async {
346 + Navigator.of(context).pop();
347 + await cakePayPurchaseViewModel.sendViewModel.commitTransaction();
348 + },
349 + actionLeftButton: () => Navigator.of(context).pop()));
350 + },
351 + );
352 + }
353 +
354 + void _setEffects(BuildContext context) {
355 + if (_effectsInstalled) {
356 + return;
357 + }
358 +
359 + reaction((_) => cakePayPurchaseViewModel.sendViewModel.state, (ExecutionState state) {
360 + if (state is FailureState) {
361 + WidgetsBinding.instance.addPostFrameCallback((_) {
362 + showStateAlert(context, S.of(context).error, state.error);
363 + });
364 + }
365 +
366 + if (state is ExecutedSuccessfullyState) {
367 + WidgetsBinding.instance.addPostFrameCallback((_) async {
368 + await _showConfirmSendingAlert(context);
369 + });
370 + }
371 +
372 + if (state is TransactionCommitted) {
373 + WidgetsBinding.instance.addPostFrameCallback((_) {
374 + cakePayPurchaseViewModel.sendViewModel.clearOutputs();
375 + if (context.mounted) {
376 + showStateAlert(context, S.of(context).sending, S.of(context).transaction_sent);
377 + }
378 + });
379 + }
380 + });
381 +
382 + _effectsInstalled = true;
383 + }
384 +
385 + void showStateAlert(BuildContext context, String title, String content) {
386 + showPopUp<void>(
387 + context: context,
388 + builder: (BuildContext context) {
389 + return AlertWithOneAction(
390 + alertTitle: title,
391 + alertContent: content,
392 + buttonText: S.of(context).ok,
393 + buttonAction: () => Navigator.of(context).pop());
394 + });
395 + }
396 +
397 + void _handleDispose(ReactionDisposer? disposer) {
398 + cakePayPurchaseViewModel.dispose();
399 + if (disposer != null) {
400 + disposer();
401 + }
402 + }
403 +}
lib/src/screens/cake_pay/widgets/cake_pay_alert_modal.dart renamed
+2 -2
@@ -5,8 +5,8 @@ import 'package:cake_wallet/themes/extensions/cake_scrollbar_theme.dart';
5 import 'package:cake_wallet/typography.dart';
6 import 'package:flutter/material.dart';
7
8 -class IoniaAlertModal extends StatelessWidget {
9 - const IoniaAlertModal({
8 +class CakePayAlertModal extends StatelessWidget {
9 + const CakePayAlertModal({
10 Key? key,
11 required this.title,
12 required this.content,
lib/src/screens/cake_pay/widgets/cake_pay_tile.dart renamed
+2 -2
@@ -3,8 +3,8 @@ import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
3 import 'package:flutter/material.dart';
4 import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
5
6 -class IoniaTile extends StatelessWidget {
7 - const IoniaTile({
6 +class CakePayTile extends StatelessWidget {
7 + const CakePayTile({
8 Key? key,
9 required this.title,
10 required this.subTitle,
lib/src/screens/cake_pay/widgets/card_item.dart new
+104
@@ -0,0 +1,104 @@
1 +import 'package:flutter/material.dart';
2 +
3 +import 'image_placeholder.dart';
4 +
5 +class CardItem extends StatelessWidget {
6 + CardItem({
7 + required this.title,
8 + required this.subTitle,
9 + required this.backgroundColor,
10 + required this.titleColor,
11 + required this.subtitleColor,
12 + this.hideBorder = false,
13 + this.discount = 0.0,
14 + this.isAmount = false,
15 + this.discountBackground,
16 + this.onTap,
17 + this.logoUrl,
18 + });
19 +
20 + final VoidCallback? onTap;
21 + final String title;
22 + final String subTitle;
23 + final String? logoUrl;
24 + final double discount;
25 + final bool isAmount;
26 + final bool hideBorder;
27 + final Color backgroundColor;
28 + final Color titleColor;
29 + final Color subtitleColor;
30 + final AssetImage? discountBackground;
31 +
32 + @override
33 + Widget build(BuildContext context) {
34 + return Theme(
35 + data: ThemeData(
36 + splashColor: Colors.transparent,
37 + highlightColor: Colors.transparent,
38 + ),
39 + child: InkWell(
40 + onTap: onTap,
41 + child: Container(
42 + decoration: BoxDecoration(
43 + color: backgroundColor,
44 + borderRadius: BorderRadius.circular(10),
45 + border: hideBorder
46 + ? Border.all(color: Colors.transparent)
47 + : Border.all(color: Colors.white.withOpacity(0.20)),
48 + ),
49 + child: Row(
50 + children: [
51 + if (logoUrl != null)
52 + AspectRatio(
53 + aspectRatio: 1.8,
54 + child: ClipRRect(
55 + borderRadius: BorderRadius.all(Radius.circular(10)),
56 + child: Image.network(
57 + logoUrl!,
58 + fit: BoxFit.cover,
59 + loadingBuilder:
60 + (BuildContext context, Widget child, ImageChunkEvent? loadingProgress) {
61 + if (loadingProgress == null) return child;
62 + return Center(child: CircularProgressIndicator());
63 + },
64 + errorBuilder: (context, error, stackTrace) => CakePayCardImagePlaceholder(),
65 + ),
66 + ),
67 + ),
68 + Expanded(
69 + child: Padding(
70 + padding: const EdgeInsets.symmetric(horizontal: 8),
71 + child: Column(
72 + crossAxisAlignment: CrossAxisAlignment.start,
73 + children: [
74 + Text(
75 + title,
76 + maxLines: 1,
77 + overflow: TextOverflow.ellipsis,
78 + style: TextStyle(
79 + color: titleColor,
80 + fontSize: 18,
81 + fontWeight: FontWeight.w700,
82 + ),
83 + ),
84 + Text(
85 + subTitle,
86 + maxLines: 2,
87 + overflow: TextOverflow.ellipsis,
88 + style: TextStyle(
89 + color: titleColor,
90 + fontSize: 10,
91 + fontWeight: FontWeight.w700,
92 + ),
93 + ),
94 + ],
95 + ),
96 + ),
97 + ),
98 + ],
99 + ),
100 + ),
101 + ),
102 + );
103 + }
104 +}
lib/src/screens/cake_pay/widgets/card_menu.dart renamed
lib/src/screens/cake_pay/widgets/image_placeholder.dart new
+29
@@ -0,0 +1,29 @@
1 +import 'package:flutter/material.dart';
2 +
3 +class CakePayCardImagePlaceholder extends StatelessWidget {
4 + const CakePayCardImagePlaceholder({this.text});
5 +
6 + final String? text;
7 +
8 + @override
9 + Widget build(BuildContext context) {
10 + return AspectRatio(
11 + aspectRatio: 1.8,
12 + child: Container(
13 + child: Center(
14 + child: Text(
15 + text ?? 'Image not found!',
16 + style: TextStyle(
17 + color: Colors.black,
18 + fontSize: 12,
19 + fontWeight: FontWeight.w900,
20 + ),
21 + ),
22 + ),
23 + decoration: BoxDecoration(
24 + color: Colors.white,
25 + ),
26 + ),
27 + );
28 + }
29 +}
lib/src/screens/cake_pay/widgets/link_extractor.dart new
+66
@@ -0,0 +1,66 @@
1 +import 'package:flutter/gestures.dart';
2 +import 'package:flutter/material.dart';
3 +import 'package:url_launcher/url_launcher.dart';
4 +
5 +class ClickableLinksText extends StatelessWidget {
6 + const ClickableLinksText({
7 + required this.text,
8 + required this.textStyle,
9 + this.linkStyle,
10 + });
11 +
12 + final String text;
13 + final TextStyle textStyle;
14 + final TextStyle? linkStyle;
15 +
16 + @override
17 + Widget build(BuildContext context) {
18 + List<InlineSpan> spans = [];
19 + RegExp linkRegExp = RegExp(r'(https?://[^\s]+)');
20 + Iterable<Match> matches = linkRegExp.allMatches(text);
21 +
22 + int previousEnd = 0;
23 + matches.forEach((match) {
24 + if (match.start > previousEnd) {
25 + spans.add(TextSpan(text: text.substring(previousEnd, match.start), style: textStyle));
26 + }
27 + String url = text.substring(match.start, match.end);
28 + if (url.toLowerCase().endsWith('.md')) {
29 + spans.add(
30 + TextSpan(
31 + text: url,
32 + style: TextStyle(
33 + color: Colors.blue,
34 + fontSize: 18,
35 + fontWeight: FontWeight.w400,
36 + ),
37 + recognizer: TapGestureRecognizer()
38 + ..onTap = () async {
39 + if (await canLaunchUrl(Uri.parse(url))) {
40 + await launchUrl(Uri.parse(url), mode: LaunchMode.externalApplication);
41 + }
42 + },
43 + ),
44 + );
45 + } else {
46 + spans.add(
47 + TextSpan(
48 + text: url,
49 + style: linkStyle,
50 + recognizer: TapGestureRecognizer()
51 + ..onTap = () {
52 + launchUrl(Uri.parse(url));
53 + },
54 + ),
55 + );
56 + }
57 + previousEnd = match.end;
58 + });
59 +
60 + if (previousEnd < text.length) {
61 + spans.add(TextSpan(text: text.substring(previousEnd), style: textStyle));
62 + }
63 +
64 + return RichText(text: TextSpan(children: spans));
65 + }
66 +}
lib/src/screens/cake_pay/widgets/rounded_checkbox.dart renamed
lib/src/screens/cake_pay/widgets/text_icon_button.dart renamed
lib/src/screens/dashboard/pages/cake_features_page.dart
+33 -19
@@ -1,17 +1,18 @@
1 +import 'package:cake_wallet/generated/i18n.dart';
2 +import 'package:cake_wallet/routes.dart';
3 +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
4 import 'package:cake_wallet/src/widgets/dashboard_card_widget.dart';
5 +import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
6 +import 'package:cake_wallet/utils/show_pop_up.dart';
7 import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
8 +import 'package:cw_core/wallet_type.dart';
9 import 'package:cake_wallet/view_model/dashboard/cake_features_view_model.dart';
10 import 'package:flutter/material.dart';
5 -import 'package:cake_wallet/generated/i18n.dart';
11 import 'package:url_launcher/url_launcher.dart';
7 -import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
12 import 'package:flutter_svg/flutter_svg.dart';
13
14 class CakeFeaturesPage extends StatelessWidget {
11 - CakeFeaturesPage({
12 - required this.dashboardViewModel,
13 - required this.cakeFeaturesViewModel,
14 - });
15 + CakeFeaturesPage({required this.dashboardViewModel, required this.cakeFeaturesViewModel});
16
17 final DashboardViewModel dashboardViewModel;
18 final CakeFeaturesViewModel cakeFeaturesViewModel;
@@ -45,20 +46,11 @@ class CakeFeaturesPage extends StatelessWidget {
46 child: ListView(
47 controller: _scrollController,
48 children: <Widget>[
48 - // SizedBox(height: 20),
49 - // DashBoardRoundedCardWidget(
50 - // onTap: () => launchUrl(
51 - // Uri.parse("https://cakelabs.com/news/cake-pay-mobile-to-shut-down/"),
52 - // mode: LaunchMode.externalApplication,
53 - // ),
54 - // title: S.of(context).cake_pay_title,
55 - // subTitle: S.of(context).cake_pay_subtitle,
56 - // ),
49 SizedBox(height: 20),
50 DashBoardRoundedCardWidget(
59 - onTap: () => _launchUrl("buy.cakepay.com"),
60 - title: S.of(context).cake_pay_web_cards_title,
61 - subTitle: S.of(context).cake_pay_web_cards_subtitle,
51 + onTap: () => _navigatorToGiftCardsPage(context),
52 + title: 'Cake Pay',
53 + subTitle: S.of(context).cake_pay_subtitle,
54 svgPicture: SvgPicture.asset(
55 'assets/images/cards.svg',
56 height: 125,
@@ -88,6 +80,28 @@ class CakeFeaturesPage extends StatelessWidget {
80 Uri.https(url),
81 mode: LaunchMode.externalApplication,
82 );
91 - } catch (_) {}
83 + } catch (e) {
84 + print(e);
85 + }
86 + }
87 +
88 + void _navigatorToGiftCardsPage(BuildContext context) {
89 + final walletType = dashboardViewModel.type;
90 +
91 + switch (walletType) {
92 + case WalletType.haven:
93 + showPopUp<void>(
94 + context: context,
95 + builder: (BuildContext context) {
96 + return AlertWithOneAction(
97 + alertTitle: S.of(context).error,
98 + alertContent: S.of(context).gift_cards_unavailable,
99 + buttonText: S.of(context).ok,
100 + buttonAction: () => Navigator.of(context).pop());
101 + });
102 + break;
103 + default:
104 + Navigator.pushNamed(context, Routes.cakePayCardsPage);
105 + }
106 }
107 }
lib/src/screens/dashboard/widgets/filter_widget.dart
+89 -71
@@ -3,18 +3,21 @@ import 'package:cake_wallet/src/screens/dashboard/widgets/filter_tile.dart';
3 import 'package:cake_wallet/src/widgets/section_divider.dart';
4 import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
5 import 'package:cake_wallet/themes/extensions/menu_theme.dart';
6 -import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
6 +import 'package:cake_wallet/view_model/dashboard/dropdown_filter_item.dart';
7 +import 'package:cake_wallet/view_model/dashboard/dropdown_filter_item_widget.dart';
8 +import 'package:cake_wallet/view_model/dashboard/filter_item.dart';
9 import 'package:flutter/material.dart';
10 import 'package:cake_wallet/src/widgets/picker_wrapper_widget.dart';
11 import 'package:cake_wallet/generated/i18n.dart';
12 import 'package:flutter_mobx/flutter_mobx.dart';
13 +
14 //import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker;
15 import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
16
17 class FilterWidget extends StatelessWidget {
15 - FilterWidget({required this.dashboardViewModel});
18 + FilterWidget({required this.filterItems});
19
17 - final DashboardViewModel dashboardViewModel;
20 + final Map<String, List<FilterItem>> filterItems;
21
22 @override
23 Widget build(BuildContext context) {
@@ -27,75 +30,90 @@ class FilterWidget extends StatelessWidget {
30 borderRadius: BorderRadius.all(Radius.circular(24)),
31 child: Container(
32 color: Theme.of(context).extension<CakeMenuTheme>()!.backgroundColor,
30 - child: Column(
31 - crossAxisAlignment: CrossAxisAlignment.start,
32 - children: [
33 - Padding(
34 - padding: EdgeInsets.all(24.0),
35 - child: Text(
36 - S.of(context).filter_by,
37 - style: TextStyle(
38 - color: Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
39 - fontSize: 16,
40 - fontFamily: 'Lato',
41 - decoration: TextDecoration.none,
42 - ),
43 - ),
44 - ),
45 - sectionDivider,
46 - ListView.separated(
47 - padding: EdgeInsets.zero,
48 - shrinkWrap: true,
49 - physics: const NeverScrollableScrollPhysics(),
50 - itemCount: dashboardViewModel.filterItems.length,
51 - separatorBuilder: (context, _) => sectionDivider,
52 - itemBuilder: (_, index1) {
53 - final title = dashboardViewModel.filterItems.keys
54 - .elementAt(index1);
55 - final section = dashboardViewModel.filterItems.values
56 - .elementAt(index1);
57 - return Column(
58 - crossAxisAlignment: CrossAxisAlignment.start,
59 - children: <Widget>[
60 - Padding(
61 - padding:
62 - EdgeInsets.only(top: 20, left: 24, right: 24),
63 - child: Text(
64 - title,
65 - style: TextStyle(
66 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
67 - fontSize: 16,
68 - fontFamily: 'Lato',
69 - fontWeight: FontWeight.bold,
70 - decoration: TextDecoration.none),
71 - ),
72 - ),
73 - ListView.builder(
74 - padding: EdgeInsets.symmetric(vertical: 8.0),
75 - shrinkWrap: true,
76 - physics: const NeverScrollableScrollPhysics(),
77 - itemCount: section.length,
78 - itemBuilder: (_, index2) {
79 - final item = section[index2];
80 - final content = Observer(
81 - builder: (_) => StandardCheckbox(
82 - value: item.value(),
83 - caption: item.caption,
84 - gradientBackground: true,
85 - borderColor:
86 - Theme.of(context).dividerColor,
87 - iconColor: Colors.white,
88 - onChanged: (value) =>
89 - item.onChanged(),
90 - ));
91 - return FilterTile(child: content);
92 - },
93 - )
94 - ],
95 - );
96 - },
33 + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
34 + Padding(
35 + padding: EdgeInsets.all(24.0),
36 + child: Text(
37 + S.of(context).filter_by,
38 + style: TextStyle(
39 + color:
40 + Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
41 + fontSize: 16,
42 + fontFamily: 'Lato',
43 + decoration: TextDecoration.none,
44 ),
98 - ]),
45 + ),
46 + ),
47 + sectionDivider,
48 + ListView.separated(
49 + padding: EdgeInsets.zero,
50 + shrinkWrap: true,
51 + physics: const NeverScrollableScrollPhysics(),
52 + itemCount: filterItems.length,
53 + separatorBuilder: (context, _) => sectionDivider,
54 + itemBuilder: (_, index1) {
55 + final title = filterItems.keys.elementAt(index1);
56 + final section = filterItems.values.elementAt(index1);
57 + return Column(
58 + crossAxisAlignment: CrossAxisAlignment.start,
59 + children: <Widget>[
60 + Padding(
61 + padding: EdgeInsets.only(top: 20, left: 24, right: 24),
62 + child: Text(
63 + title,
64 + style: TextStyle(
65 + color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
66 + fontSize: 16,
67 + fontFamily: 'Lato',
68 + fontWeight: FontWeight.bold,
69 + decoration: TextDecoration.none),
70 + ),
71 + ),
72 + ListView.builder(
73 + padding: EdgeInsets.symmetric(horizontal: 28.0),
74 + shrinkWrap: true,
75 + physics: const NeverScrollableScrollPhysics(),
76 + itemCount: section.length,
77 + itemBuilder: (_, index2) {
78 + final item = section[index2];
79 +
80 + if (item is DropdownFilterItem) {
81 + return Padding(
82 + padding: EdgeInsets.fromLTRB(8, 0, 8, 16),
83 + child: Container(
84 + decoration: BoxDecoration(
85 + border: Border(
86 + bottom: BorderSide(
87 + width: 1.0,
88 + color: Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor),
89 + ),
90 + ),
91 + child: DropdownFilterList(
92 + items: item.items,
93 + caption: item.caption,
94 + selectedItem: item.selectedItem,
95 + onItemSelected: item.onItemSelected,
96 + ),
97 + ),
98 + );
99 + }
100 + final content = Observer(
101 + builder: (_) => StandardCheckbox(
102 + value: item.value(),
103 + caption: item.caption,
104 + gradientBackground: true,
105 + borderColor: Theme.of(context).dividerColor,
106 + iconColor: Colors.white,
107 + onChanged: (value) => item.onChanged(),
108 + ));
109 + return FilterTile(child: content);
110 + },
111 + )
112 + ],
113 + );
114 + },
115 + ),
116 + ]),
117 ),
118 ),
119 )
lib/src/screens/dashboard/widgets/header_row.dart
+1 -1
@@ -37,7 +37,7 @@ class HeaderRow extends StatelessWidget {
37 onTap: () {
38 showPopUp<void>(
39 context: context,
40 - builder: (context) => FilterWidget(dashboardViewModel: dashboardViewModel),
40 + builder: (context) => FilterWidget(filterItems: dashboardViewModel.filterItems),
41 );
42 },
43 child: Semantics(
lib/src/screens/dashboard/widgets/present_receive_option_picker.dart
+1 -1
@@ -1,6 +1,6 @@
1 import 'package:cake_wallet/src/widgets/alert_close_button.dart';
2 import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
3 -import 'package:cake_wallet/src/screens/ionia/widgets/rounded_checkbox.dart';
3 +import 'package:cake_wallet/src/screens/cake_pay/widgets/rounded_checkbox.dart';
4 import 'package:cake_wallet/src/widgets/alert_background.dart';
5 import 'package:cake_wallet/typography.dart';
6 import 'package:cake_wallet/utils/show_pop_up.dart';
lib/src/screens/ionia/auth/ionia_create_account_page.dart deleted
-159
@@ -1,159 +0,0 @@
1 -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
2 -import 'package:cake_wallet/core/email_validator.dart';
3 -import 'package:cake_wallet/ionia/ionia_create_state.dart';
4 -import 'package:cake_wallet/routes.dart';
5 -import 'package:cake_wallet/src/screens/base_page.dart';
6 -import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
7 -import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
8 -import 'package:cake_wallet/src/widgets/primary_button.dart';
9 -import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
10 -import 'package:cake_wallet/typography.dart';
11 -import 'package:cake_wallet/utils/show_pop_up.dart';
12 -import 'package:cake_wallet/view_model/ionia/ionia_auth_view_model.dart';
13 -import 'package:flutter/gestures.dart';
14 -import 'package:flutter/material.dart';
15 -import 'package:cake_wallet/generated/i18n.dart';
16 -import 'package:flutter_mobx/flutter_mobx.dart';
17 -import 'package:mobx/mobx.dart';
18 -import 'package:url_launcher/url_launcher.dart';
19 -
20 -class IoniaCreateAccountPage extends BasePage {
21 - IoniaCreateAccountPage(this._authViewModel)
22 - : _emailFocus = FocusNode(),
23 - _emailController = TextEditingController(),
24 - _formKey = GlobalKey<FormState>() {
25 - _emailController.text = _authViewModel.email;
26 - _emailController.addListener(() => _authViewModel.email = _emailController.text);
27 - }
28 -
29 - final IoniaAuthViewModel _authViewModel;
30 -
31 - final GlobalKey<FormState> _formKey;
32 -
33 - final FocusNode _emailFocus;
34 - final TextEditingController _emailController;
35 -
36 - static const privacyPolicyUrl = 'https://ionia.docsend.com/view/jhjvdn7qq7k3ukwt';
37 - static const termsAndConditionsUrl = 'https://ionia.docsend.com/view/uceirymz2ijacq5g';
38 -
39 - @override
40 - Widget middle(BuildContext context) {
41 - return Text(
42 - S.current.sign_up,
43 - style: textMediumSemiBold(
44 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
45 - ),
46 - );
47 - }
48 -
49 - @override
50 - Widget body(BuildContext context) {
51 - reaction((_) => _authViewModel.createUserState, (IoniaCreateAccountState state) {
52 - if (state is IoniaCreateStateFailure) {
53 - _onCreateUserFailure(context, state.error);
54 - }
55 - if (state is IoniaCreateStateSuccess) {
56 - _onCreateSuccessful(context, _authViewModel);
57 - }
58 - });
59 -
60 - return ScrollableWithBottomSection(
61 - contentPadding: EdgeInsets.all(24),
62 - content: Form(
63 - key: _formKey,
64 - child: BaseTextFormField(
65 - hintText: S.of(context).email_address,
66 - focusNode: _emailFocus,
67 - validator: EmailValidator(),
68 - keyboardType: TextInputType.emailAddress,
69 - controller: _emailController,
70 - onSubmit: (_) => _createAccount(),
71 - ),
72 - ),
73 - bottomSectionPadding: EdgeInsets.symmetric(vertical: 36, horizontal: 24),
74 - bottomSection: Column(
75 - children: [
76 - Column(
77 - mainAxisAlignment: MainAxisAlignment.end,
78 - children: <Widget>[
79 - Observer(
80 - builder: (_) => LoadingPrimaryButton(
81 - text: S.of(context).create_account,
82 - onPressed: _createAccount,
83 - isLoading:
84 - _authViewModel.createUserState is IoniaCreateStateLoading,
85 - color: Theme.of(context).primaryColor,
86 - textColor: Colors.white,
87 - ),
88 - ),
89 - SizedBox(
90 - height: 20,
91 - ),
92 - RichText(
93 - textAlign: TextAlign.center,
94 - text: TextSpan(
95 - text: S.of(context).agree_to,
96 - style: TextStyle(
97 - color: Color(0xff7A93BA),
98 - fontSize: 12,
99 - fontFamily: 'Lato',
100 - ),
101 - children: [
102 - TextSpan(
103 - text: S.of(context).settings_terms_and_conditions,
104 - style: TextStyle(
105 - color: Theme.of(context).primaryColor,
106 - fontWeight: FontWeight.w700,
107 - ),
108 - recognizer: TapGestureRecognizer()
109 - ..onTap = () async {
110 - if (await canLaunch(termsAndConditionsUrl)) await launch(termsAndConditionsUrl);
111 - },
112 - ),
113 - TextSpan(text: ' ${S.of(context).and} '),
114 - TextSpan(
115 - text: S.of(context).privacy_policy,
116 - style: TextStyle(
117 - color: Theme.of(context).primaryColor,
118 - fontWeight: FontWeight.w700,
119 - ),
120 - recognizer: TapGestureRecognizer()
121 - ..onTap = () async {
122 - if (await canLaunch(privacyPolicyUrl)) await launch(privacyPolicyUrl);
123 - }),
124 - TextSpan(text: ' ${S.of(context).by_cake_pay}'),
125 - ],
126 - ),
127 - ),
128 - ],
129 - ),
130 - ],
131 - ),
132 - );
133 - }
134 -
135 - void _onCreateUserFailure(BuildContext context, String error) {
136 - showPopUp<void>(
137 - context: context,
138 - builder: (BuildContext context) {
139 - return AlertWithOneAction(
140 - alertTitle: S.current.create_account,
141 - alertContent: error,
142 - buttonText: S.of(context).ok,
143 - buttonAction: () => Navigator.of(context).pop());
144 - });
145 - }
146 -
147 - void _onCreateSuccessful(BuildContext context, IoniaAuthViewModel authViewModel) => Navigator.pushNamed(
148 - context,
149 - Routes.ioniaVerifyIoniaOtpPage,
150 - arguments: [authViewModel.email, false],
151 - );
152 -
153 - void _createAccount() async {
154 - if (_formKey.currentState != null && !_formKey.currentState!.validate()) {
155 - return;
156 - }
157 - await _authViewModel.createUser(_emailController.text);
158 - }
159 -}
lib/src/screens/ionia/auth/ionia_welcome_page.dart deleted
-95
@@ -1,95 +0,0 @@
1 -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
2 -import 'package:cake_wallet/palette.dart';
3 -import 'package:cake_wallet/routes.dart';
4 -import 'package:cake_wallet/src/screens/base_page.dart';
5 -import 'package:cake_wallet/src/widgets/primary_button.dart';
6 -import 'package:cake_wallet/typography.dart';
7 -import 'package:flutter/material.dart';
8 -import 'package:cake_wallet/generated/i18n.dart';
9 -
10 -class IoniaWelcomePage extends BasePage {
11 - IoniaWelcomePage();
12 -
13 - @override
14 - Widget middle(BuildContext context) {
15 - return Text(
16 - S.current.welcome_to_cakepay,
17 - style: textMediumSemiBold(
18 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
19 - ),
20 - );
21 - }
22 -
23 - @override
24 - Widget body(BuildContext context) {
25 - return Padding(
26 - padding: const EdgeInsets.all(24.0),
27 - child: Column(
28 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
29 - children: [
30 - Column(
31 - children: [
32 - SizedBox(height: 90),
33 - Text(
34 - S.of(context).about_cake_pay,
35 - style: TextStyle(
36 - fontSize: 18,
37 - fontWeight: FontWeight.w400,
38 - fontFamily: 'Lato',
39 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
40 - ),
41 - ),
42 - SizedBox(height: 20),
43 - Text(
44 - S.of(context).cake_pay_account_note,
45 - style: TextStyle(
46 - fontSize: 18,
47 - fontWeight: FontWeight.w400,
48 - fontFamily: 'Lato',
49 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
50 - ),
51 - ),
52 - ],
53 - ),
54 - Column(
55 - mainAxisAlignment: MainAxisAlignment.end,
56 - children: <Widget>[
57 - PrimaryButton(
58 - text: S.of(context).create_account,
59 - onPressed: () => Navigator.of(context).pushNamed(Routes.ioniaCreateAccountPage),
60 - color: Theme.of(context).primaryColor,
61 - textColor: Colors.white,
62 - ),
63 - SizedBox(
64 - height: 16,
65 - ),
66 - Text(
67 - S.of(context).already_have_account,
68 - style: TextStyle(
69 - fontSize: 15,
70 - fontWeight: FontWeight.w500,
71 - fontFamily: 'Lato',
72 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
73 - ),
74 - ),
75 - SizedBox(height: 8),
76 - InkWell(
77 - onTap: () => Navigator.of(context).pushNamed(Routes.ioniaLoginPage),
78 - child: Text(
79 - S.of(context).login,
80 - style: TextStyle(
81 - color: Palette.blueCraiola,
82 - fontSize: 18,
83 - letterSpacing: 1.5,
84 - fontWeight: FontWeight.w900,
85 - ),
86 - ),
87 - ),
88 - SizedBox(height: 20)
89 - ],
90 - )
91 - ],
92 - ),
93 - );
94 - }
95 -}
lib/src/screens/ionia/cards/ionia_account_cards_page.dart deleted
-204
@@ -1,204 +0,0 @@
1 -
2 -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
3 -import 'package:cake_wallet/ionia/ionia_create_state.dart';
4 -import 'package:cake_wallet/ionia/ionia_gift_card.dart';
5 -import 'package:cake_wallet/routes.dart';
6 -import 'package:cake_wallet/src/screens/base_page.dart';
7 -import 'package:cake_wallet/src/screens/ionia/widgets/card_item.dart';
8 -import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
9 -import 'package:cake_wallet/themes/extensions/order_theme.dart';
10 -import 'package:cake_wallet/typography.dart';
11 -import 'package:cake_wallet/view_model/ionia/ionia_account_view_model.dart';
12 -import 'package:flutter/material.dart';
13 -import 'package:cake_wallet/generated/i18n.dart';
14 -import 'package:flutter_mobx/flutter_mobx.dart';
15 -import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
16 -import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
17 -
18 -class IoniaAccountCardsPage extends BasePage {
19 - IoniaAccountCardsPage(this.ioniaAccountViewModel);
20 -
21 - final IoniaAccountViewModel ioniaAccountViewModel;
22 -
23 - @override
24 - Widget middle(BuildContext context) {
25 - return Text(
26 - S.of(context).cards,
27 - style: textLargeSemiBold(
28 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
29 - ),
30 - );
31 - }
32 -
33 - @override
34 - Widget body(BuildContext context) {
35 - return _IoniaCardTabs(ioniaAccountViewModel);
36 - }
37 -}
38 -
39 -class _IoniaCardTabs extends StatefulWidget {
40 - _IoniaCardTabs(this.ioniaAccountViewModel);
41 -
42 - final IoniaAccountViewModel ioniaAccountViewModel;
43 -
44 - @override
45 - _IoniaCardTabsState createState() => _IoniaCardTabsState();
46 -}
47 -
48 -class _IoniaCardTabsState extends State<_IoniaCardTabs> with SingleTickerProviderStateMixin {
49 - _IoniaCardTabsState();
50 -
51 - TabController? _tabController;
52 -
53 - @override
54 - void initState() {
55 - _tabController = TabController(length: 2, vsync: this);
56 - super.initState();
57 - }
58 -
59 - @override
60 - void dispose() {
61 - super.dispose();
62 - _tabController?.dispose();
63 - }
64 -
65 - @override
66 - Widget build(BuildContext context) {
67 - return Padding(
68 - padding: const EdgeInsets.all(24.0),
69 - child: Column(
70 - crossAxisAlignment: CrossAxisAlignment.start,
71 - children: [
72 - Container(
73 - height: 45,
74 - width: 230,
75 - padding: EdgeInsets.all(5),
76 - decoration: BoxDecoration(
77 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor
78 - .withOpacity(0.1),
79 - borderRadius: BorderRadius.circular(
80 - 25.0,
81 - ),
82 - ),
83 - child: Theme(
84 - data: ThemeData(primaryTextTheme: TextTheme(bodyLarge: TextStyle(backgroundColor: Colors.transparent))),
85 - child: TabBar(
86 - controller: _tabController,
87 - indicator: BoxDecoration(
88 - borderRadius: BorderRadius.circular(
89 - 25.0,
90 - ),
91 - color: Theme.of(context).primaryColor,
92 - ),
93 - labelColor: Theme.of(context).extension<OrderTheme>()!.iconColor,
94 - unselectedLabelColor:
95 - Theme.of(context).extension<CakeTextTheme>()!.titleColor,
96 - tabs: [
97 - Tab(
98 - text: S.of(context).active,
99 - ),
100 - Tab(
101 - text: S.of(context).redeemed,
102 - ),
103 - ],
104 - ),
105 - ),
106 - ),
107 - SizedBox(height: 16),
108 - Expanded(
109 - child: Observer(builder: (_) {
110 - final viewModel = widget.ioniaAccountViewModel;
111 - return TabBarView(
112 - controller: _tabController,
113 - children: [
114 - _IoniaCardListView(
115 - emptyText: S.of(context).gift_card_balance_note,
116 - merchList: viewModel.activeMechs,
117 - isLoading: viewModel.merchantState is IoniaLoadingMerchantState,
118 - onTap: (giftCard) {
119 - Navigator.pushNamed(
120 - context,
121 - Routes.ioniaGiftCardDetailPage,
122 - arguments: [giftCard])
123 - .then((_) => viewModel.updateUserGiftCards());
124 - }),
125 - _IoniaCardListView(
126 - emptyText: S.of(context).gift_card_redeemed_note,
127 - merchList: viewModel.redeemedMerchs,
128 - isLoading: viewModel.merchantState is IoniaLoadingMerchantState,
129 - onTap: (giftCard) {
130 - Navigator.pushNamed(
131 - context,
132 - Routes.ioniaGiftCardDetailPage,
133 - arguments: [giftCard])
134 - .then((_) => viewModel.updateUserGiftCards());
135 - }),
136 - ],
137 - );
138 - }),
139 - ),
140 - ],
141 - ),
142 - );
143 - }
144 -}
145 -
146 -class _IoniaCardListView extends StatelessWidget {
147 - _IoniaCardListView({
148 - Key? key,
149 - required this.emptyText,
150 - required this.merchList,
151 - required this.onTap,
152 - this.isLoading = false,
153 - }) : super(key: key);
154 -
155 - final String emptyText;
156 - final List<IoniaGiftCard> merchList;
157 - final void Function(IoniaGiftCard giftCard) onTap;
158 - final bool isLoading;
159 -
160 - @override
161 - Widget build(BuildContext context) {
162 - if(isLoading){
163 - return Center(
164 - child: CircularProgressIndicator(
165 - backgroundColor: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
166 - valueColor: AlwaysStoppedAnimation<Color>(
167 - Theme.of(context).extension<ExchangePageTheme>()!.firstGradientBottomPanelColor),
168 - ),
169 - );
170 - }
171 - return merchList.isEmpty
172 - ? Center(
173 - child: Text(
174 - emptyText,
175 - textAlign: TextAlign.center,
176 - style: textSmall(
177 - color: Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
178 - ),
179 - ),
180 - )
181 - : ListView.builder(
182 - itemCount: merchList.length,
183 - itemBuilder: (context, index) {
184 - final merchant = merchList[index];
185 - return Padding(
186 - padding: const EdgeInsets.only(bottom: 16),
187 - child: CardItem(
188 - onTap: () => onTap?.call(merchant),
189 - title: merchant.legalName,
190 - backgroundColor: Theme.of(context).extension<CakeTextTheme>()!.titleColor
191 - .withOpacity(0.1),
192 - discount: 0,
193 - hideBorder: true,
194 - discountBackground: AssetImage('assets/images/red_badge_discount.png'),
195 - titleColor: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
196 - subtitleColor: Theme.of(context).hintColor,
197 - subTitle: '',
198 - logoUrl: merchant.logoUrl,
199 - ),
200 - );
201 - },
202 - );
203 - }
204 -}
lib/src/screens/ionia/cards/ionia_account_page.dart deleted
-178
@@ -1,178 +0,0 @@
1 -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
2 -import 'package:cake_wallet/routes.dart';
3 -import 'package:cake_wallet/src/screens/base_page.dart';
4 -import 'package:cake_wallet/generated/i18n.dart';
5 -import 'package:cake_wallet/src/screens/ionia/widgets/ionia_tile.dart';
6 -import 'package:cake_wallet/src/widgets/primary_button.dart';
7 -import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
8 -import 'package:cake_wallet/typography.dart';
9 -import 'package:cake_wallet/view_model/ionia/ionia_account_view_model.dart';
10 -import 'package:flutter/material.dart';
11 -import 'package:flutter_mobx/flutter_mobx.dart';
12 -import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
13 -
14 -class IoniaAccountPage extends BasePage {
15 - IoniaAccountPage(this.ioniaAccountViewModel);
16 -
17 - final IoniaAccountViewModel ioniaAccountViewModel;
18 -
19 - @override
20 - Widget middle(BuildContext context) {
21 - return Text(
22 - S.current.account,
23 - style: textMediumSemiBold(
24 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
25 - ),
26 - );
27 - }
28 -
29 - @override
30 - Widget body(BuildContext context) {
31 - return ScrollableWithBottomSection(
32 - contentPadding: EdgeInsets.all(24),
33 - content: Column(
34 - children: [
35 - _GradiantContainer(
36 - content: Row(
37 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
38 - children: [
39 - Observer(
40 - builder: (_) => RichText(
41 - text: TextSpan(
42 - text: '${ioniaAccountViewModel.countOfMerch}',
43 - style: textLargeSemiBold(),
44 - children: [
45 - TextSpan(
46 - text: ' ${S.of(context).active_cards}',
47 - style: textSmall(color: Colors.white.withOpacity(0.7))),
48 - ],
49 - ),
50 - )),
51 - InkWell(
52 - onTap: () {
53 - Navigator.pushNamed(context, Routes.ioniaAccountCardsPage)
54 - .then((_) => ioniaAccountViewModel.updateUserGiftCards());
55 - },
56 - child: Padding(
57 - padding: const EdgeInsets.all(8.0),
58 - child: Text(
59 - S.of(context).view_all,
60 - style: textSmallSemiBold(),
61 - ),
62 - ),
63 - )
64 - ],
65 - ),
66 - ),
67 - SizedBox(height: 8),
68 - //Row(
69 - // mainAxisAlignment: MainAxisAlignment.spaceBetween,
70 - // children: [
71 - // _GradiantContainer(
72 - // padding: EdgeInsets.all(16),
73 - // width: deviceWidth * 0.28,
74 - // content: Column(
75 - // crossAxisAlignment: CrossAxisAlignment.start,
76 - // children: [
77 - // Text(
78 - // S.of(context).total_saving,
79 - // style: textSmall(),
80 - // ),
81 - // SizedBox(height: 8),
82 - // Text(
83 - // '\$100',
84 - // style: textMediumSemiBold(),
85 - // ),
86 - // ],
87 - // ),
88 - // ),
89 - // _GradiantContainer(
90 - // padding: EdgeInsets.all(16),
91 - // width: deviceWidth * 0.28,
92 - // content: Column(
93 - // crossAxisAlignment: CrossAxisAlignment.start,
94 - // children: [
95 - // Text(
96 - // S.of(context).last_30_days,
97 - // style: textSmall(),
98 - // ),
99 - // SizedBox(height: 8),
100 - // Text(
101 - // '\$100',
102 - // style: textMediumSemiBold(),
103 - // ),
104 - // ],
105 - // ),
106 - // ),
107 - // _GradiantContainer(
108 - // padding: EdgeInsets.all(16),
109 - // width: deviceWidth * 0.28,
110 - // content: Column(
111 - // crossAxisAlignment: CrossAxisAlignment.start,
112 - // children: [
113 - // Text(
114 - // S.of(context).avg_savings,
115 - // style: textSmall(),
116 - // ),
117 - // SizedBox(height: 8),
118 - // Text(
119 - // '10%',
120 - // style: textMediumSemiBold(),
121 - // ),
122 - // ],
123 - // ),
124 - // ),
125 - // ],
126 - //),
127 - SizedBox(height: 40),
128 - Observer(
129 - builder: (_) => IoniaTile(title: S.of(context).email_address, subTitle: ioniaAccountViewModel.email ?? ''),
130 - ),
131 - Divider()
132 - ],
133 - ),
134 - bottomSectionPadding: EdgeInsets.all(30),
135 - bottomSection: Column(
136 - children: [
137 - PrimaryButton(
138 - color: Theme.of(context).primaryColor,
139 - textColor: Colors.white,
140 - text: S.of(context).logout,
141 - onPressed: () {
142 - ioniaAccountViewModel.logout();
143 - Navigator.pushNamedAndRemoveUntil(context, Routes.dashboard, (route) => false);
144 - },
145 - ),
146 - ],
147 - ),
148 - );
149 - }
150 -}
151 -
152 -class _GradiantContainer extends StatelessWidget {
153 - const _GradiantContainer({
154 - Key? key,
155 - required this.content,
156 - }) : super(key: key);
157 -
158 - final Widget content;
159 -
160 - @override
161 - Widget build(BuildContext context) {
162 - return Container(
163 - child: content,
164 - padding: EdgeInsets.all(24),
165 - decoration: BoxDecoration(
166 - borderRadius: BorderRadius.circular(15),
167 - gradient: LinearGradient(
168 - colors: [
169 - Theme.of(context).extension<SendPageTheme>()!.secondGradientColor,
170 - Theme.of(context).extension<SendPageTheme>()!.firstGradientColor,
171 - ],
172 - begin: Alignment.topRight,
173 - end: Alignment.bottomLeft,
174 - ),
175 - ),
176 - );
177 - }
178 -}
lib/src/screens/ionia/cards/ionia_activate_debit_card_page.dart deleted
-115
@@ -1,115 +0,0 @@
1 -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
2 -import 'package:cake_wallet/ionia/ionia_create_state.dart';
3 -import 'package:cake_wallet/routes.dart';
4 -import 'package:cake_wallet/src/screens/base_page.dart';
5 -import 'package:cake_wallet/src/screens/ionia/widgets/text_icon_button.dart';
6 -import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
7 -import 'package:cake_wallet/src/widgets/primary_button.dart';
8 -import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
9 -import 'package:cake_wallet/typography.dart';
10 -import 'package:cake_wallet/utils/show_pop_up.dart';
11 -import 'package:cake_wallet/view_model/ionia/ionia_gift_cards_list_view_model.dart';
12 -import 'package:flutter/material.dart';
13 -import 'package:cake_wallet/generated/i18n.dart';
14 -import 'package:mobx/mobx.dart';
15 -
16 -class IoniaActivateDebitCardPage extends BasePage {
17 -
18 - IoniaActivateDebitCardPage(this._cardsListViewModel);
19 -
20 - final IoniaGiftCardsListViewModel _cardsListViewModel;
21 -
22 - @override
23 - Widget middle(BuildContext context) {
24 - return Text(
25 - S.current.debit_card,
26 - style: textMediumSemiBold(
27 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
28 - ),
29 - );
30 - }
31 -
32 - @override
33 - Widget body(BuildContext context) {
34 - reaction((_) => _cardsListViewModel.createCardState, (IoniaCreateCardState state) {
35 - if (state is IoniaCreateCardFailure) {
36 - _onCreateCardFailure(context, state.error);
37 - }
38 - if (state is IoniaCreateCardSuccess) {
39 - _onCreateCardSuccess(context);
40 - }
41 - });
42 - return ScrollableWithBottomSection(
43 - contentPadding: EdgeInsets.zero,
44 - content: Padding(
45 - padding: const EdgeInsets.all(16.0),
46 - child: Column(
47 - children: [
48 - SizedBox(height: 16),
49 - Text(S.of(context).debit_card_terms),
50 - SizedBox(height: 24),
51 - Text(S.of(context).please_reference_document),
52 - SizedBox(height: 40),
53 - Padding(
54 - padding: const EdgeInsets.symmetric(horizontal: 8.0),
55 - child: Column(
56 - children: [
57 - TextIconButton(
58 - label: S.current.cardholder_agreement,
59 - onTap: () {},
60 - ),
61 - SizedBox(
62 - height: 24,
63 - ),
64 - TextIconButton(
65 - label: S.current.e_sign_consent,
66 - onTap: () {},
67 - ),
68 - ],
69 - ),
70 - ),
71 - ],
72 - ),
73 - ),
74 - bottomSection: LoadingPrimaryButton(
75 - onPressed: () {
76 - _cardsListViewModel.createCard();
77 - },
78 - isLoading: _cardsListViewModel.createCardState is IoniaCreateCardLoading,
79 - text: S.of(context).agree_and_continue,
80 - color: Theme.of(context).primaryColor,
81 - textColor: Colors.white,
82 - ),
83 - );
84 - }
85 -
86 - void _onCreateCardFailure(BuildContext context, String errorMessage) {
87 - showPopUp<void>(
88 - context: context,
89 - builder: (BuildContext context) {
90 - return AlertWithOneAction(
91 - alertTitle: S.current.error,
92 - alertContent: errorMessage,
93 - buttonText: S.of(context).ok,
94 - buttonAction: () => Navigator.of(context).pop());
95 - });
96 - }
97 -
98 - void _onCreateCardSuccess(BuildContext context) {
99 - Navigator.pushNamed(
100 - context,
101 - Routes.ioniaDebitCardPage,
102 - );
103 - showPopUp<void>(
104 - context: context,
105 - builder: (BuildContext context) {
106 - return AlertWithOneAction(
107 - alertTitle: S.of(context).congratulations,
108 - alertContent: S.of(context).you_now_have_debit_card,
109 - buttonText: S.of(context).ok,
110 - buttonAction: () => Navigator.of(context).pop(),
111 - );
112 - },
113 - );
114 - }
115 -}
lib/src/screens/ionia/cards/ionia_buy_card_detail_page.dart deleted
-478
@@ -1,478 +0,0 @@
1 -import 'package:cake_wallet/core/execution_state.dart';
2 -import 'package:cake_wallet/themes/extensions/receive_page_theme.dart';
3 -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
4 -import 'package:cake_wallet/ionia/ionia_merchant.dart';
5 -import 'package:cake_wallet/ionia/ionia_tip.dart';
6 -import 'package:cake_wallet/palette.dart';
7 -import 'package:cake_wallet/routes.dart';
8 -import 'package:cake_wallet/src/screens/ionia/widgets/ionia_alert_model.dart';
9 -import 'package:cake_wallet/src/screens/ionia/widgets/text_icon_button.dart';
10 -import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
11 -import 'package:cake_wallet/src/widgets/discount_badge.dart';
12 -import 'package:cake_wallet/src/widgets/primary_button.dart';
13 -import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
14 -import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
15 -import 'package:cake_wallet/typography.dart';
16 -import 'package:cake_wallet/utils/show_pop_up.dart';
17 -import 'package:cake_wallet/view_model/ionia/ionia_purchase_merch_view_model.dart';
18 -import 'package:flutter/material.dart';
19 -import 'package:cake_wallet/generated/i18n.dart';
20 -import 'package:flutter_mobx/flutter_mobx.dart';
21 -import 'package:mobx/mobx.dart';
22 -import 'package:cake_wallet/src/screens/base_page.dart';
23 -import 'package:cake_wallet/src/screens/send/widgets/confirm_sending_alert.dart';
24 -import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
25 -import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
26 -
27 -class IoniaBuyGiftCardDetailPage extends BasePage {
28 - IoniaBuyGiftCardDetailPage(this.ioniaPurchaseViewModel);
29 -
30 - final IoniaMerchPurchaseViewModel ioniaPurchaseViewModel;
31 -
32 - @override
33 - Widget middle(BuildContext context) {
34 - return Text(
35 - ioniaPurchaseViewModel.ioniaMerchant.legalName,
36 - style: textMediumSemiBold(color: Theme.of(context).extension<CakeTextTheme>()!.titleColor),
37 - );
38 - }
39 -
40 - @override
41 - Widget? trailing(BuildContext context)
42 - => ioniaPurchaseViewModel.ioniaMerchant.discount > 0
43 - ? DiscountBadge(percentage: ioniaPurchaseViewModel.ioniaMerchant.discount)
44 - : null;
45 -
46 - @override
47 - Widget body(BuildContext context) {
48 - reaction((_) => ioniaPurchaseViewModel.invoiceCreationState, (ExecutionState state) {
49 - if (state is FailureState) {
50 - WidgetsBinding.instance.addPostFrameCallback((_) {
51 - showPopUp<void>(
52 - context: context,
53 - builder: (BuildContext context) {
54 - return AlertWithOneAction(
55 - alertTitle: S.of(context).error,
56 - alertContent: state.error,
57 - buttonText: S.of(context).ok,
58 - buttonAction: () => Navigator.of(context).pop());
59 - });
60 - });
61 - }
62 - });
63 -
64 - reaction((_) => ioniaPurchaseViewModel.invoiceCommittingState, (ExecutionState state) {
65 - if (state is FailureState) {
66 - WidgetsBinding.instance.addPostFrameCallback((_) {
67 - showPopUp<void>(
68 - context: context,
69 - builder: (BuildContext context) {
70 - return AlertWithOneAction(
71 - alertTitle: S.of(context).error,
72 - alertContent: state.error,
73 - buttonText: S.of(context).ok,
74 - buttonAction: () => Navigator.of(context).pop());
75 - });
76 - });
77 - }
78 -
79 - if (state is ExecutedSuccessfullyState) {
80 - WidgetsBinding.instance.addPostFrameCallback((_) {
81 - Navigator.of(context).pushReplacementNamed(
82 - Routes.ioniaPaymentStatusPage,
83 - arguments: [
84 - ioniaPurchaseViewModel.paymentInfo,
85 - ioniaPurchaseViewModel.committedInfo]);
86 - });
87 - }
88 - });
89 -
90 - return ScrollableWithBottomSection(
91 - contentPadding: EdgeInsets.zero,
92 - content: Observer(builder: (_) {
93 - final tipAmount = ioniaPurchaseViewModel.tipAmount;
94 - return Column(
95 - children: [
96 - SizedBox(height: 36),
97 - Container(
98 - padding: EdgeInsets.symmetric(vertical: 24),
99 - margin: EdgeInsets.symmetric(horizontal: 16),
100 - decoration: BoxDecoration(
101 - borderRadius: BorderRadius.circular(20),
102 - gradient: LinearGradient(
103 - colors: [
104 - Theme.of(context).extension<SendPageTheme>()!.firstGradientColor,
105 - Theme.of(context).extension<SendPageTheme>()!.secondGradientColor,
106 - ],
107 - begin: Alignment.topLeft,
108 - end: Alignment.bottomRight,
109 - ),
110 - ),
111 - child: Column(
112 - children: [
113 - Text(
114 - S.of(context).gift_card_amount,
115 - style: textSmall(),
116 - ),
117 - SizedBox(height: 4),
118 - Text(
119 - '\$${ioniaPurchaseViewModel.giftCardAmount.toStringAsFixed(2)}',
120 - style: textXLargeSemiBold(),
121 - ),
122 - SizedBox(height: 24),
123 - Padding(
124 - padding: const EdgeInsets.symmetric(horizontal: 24.0),
125 - child: Row(
126 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
127 - children: [
128 - Column(
129 - crossAxisAlignment: CrossAxisAlignment.start,
130 - children: [
131 - Text(
132 - S.of(context).bill_amount,
133 - style: textSmall(),
134 - ),
135 - SizedBox(height: 4),
136 - Text(
137 - '\$${ioniaPurchaseViewModel.billAmount.toStringAsFixed(2)}',
138 - style: textLargeSemiBold(),
139 - ),
140 - ],
141 - ),
142 - Column(
143 - crossAxisAlignment: CrossAxisAlignment.end,
144 - children: [
145 - Text(
146 - S.of(context).tip,
147 - style: textSmall(),
148 - ),
149 - SizedBox(height: 4),
150 - Text(
151 - '\$${tipAmount.toStringAsFixed(2)}',
152 - style: textLargeSemiBold(),
153 - ),
154 - ],
155 - ),
156 - ],
157 - ),
158 - ),
159 - ],
160 - ),
161 - ),
162 - if(ioniaPurchaseViewModel.ioniaMerchant.acceptsTips)
163 - Padding(
164 - padding: const EdgeInsets.fromLTRB(24.0, 24.0, 0, 24.0),
165 - child: Column(
166 - crossAxisAlignment: CrossAxisAlignment.start,
167 - children: [
168 - Text(
169 - S.of(context).tip,
170 - style: TextStyle(
171 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
172 - fontWeight: FontWeight.w700,
173 - fontSize: 14,
174 - ),
175 - ),
176 - SizedBox(height: 4),
177 - Observer(
178 - builder: (_) => TipButtonGroup(
179 - selectedTip: ioniaPurchaseViewModel.selectedTip!.percentage,
180 - tipsList: ioniaPurchaseViewModel.tips,
181 - onSelect: (value) => ioniaPurchaseViewModel.addTip(value),
182 - amount: ioniaPurchaseViewModel.amount,
183 - merchant: ioniaPurchaseViewModel.ioniaMerchant,
184 - ),
185 - )
186 - ],
187 - ),
188 - ),
189 - SizedBox(height: 20),
190 - Padding(
191 - padding: const EdgeInsets.symmetric(horizontal: 24.0),
192 - child: TextIconButton(
193 - label: S.of(context).how_to_use_card,
194 - onTap: () => _showHowToUseCard(context, ioniaPurchaseViewModel.ioniaMerchant),
195 - ),
196 - ),
197 - ],
198 - );
199 - }),
200 - bottomSection: Column(
201 - children: [
202 - Padding(
203 - padding: EdgeInsets.only(bottom: 12),
204 - child: Observer(builder: (_) {
205 - return LoadingPrimaryButton(
206 - isLoading: ioniaPurchaseViewModel.invoiceCreationState is IsExecutingState ||
207 - ioniaPurchaseViewModel.invoiceCommittingState is IsExecutingState,
208 - onPressed: () => purchaseCard(context),
209 - text: S.of(context).purchase_gift_card,
210 - color: Theme.of(context).primaryColor,
211 - textColor: Colors.white,
212 - );
213 - }),
214 - ),
215 - SizedBox(height: 8),
216 - InkWell(
217 - onTap: () => _showTermsAndCondition(context),
218 - child: Text(S.of(context).settings_terms_and_conditions,
219 - style: textMediumSemiBold(
220 - color: Theme.of(context).extension<ExchangePageTheme>()!.firstGradientBottomPanelColor,
221 - ).copyWith(fontSize: 12)),
222 - ),
223 - SizedBox(height: 16)
224 - ],
225 - ),
226 - );
227 - }
228 -
229 - void _showTermsAndCondition(BuildContext context) {
230 - showPopUp<void>(
231 - context: context,
232 - builder: (BuildContext context) {
233 - return IoniaAlertModal(
234 - title: S.of(context).settings_terms_and_conditions,
235 - content: Align(
236 - alignment: Alignment.bottomLeft,
237 - child: Text(
238 - ioniaPurchaseViewModel.ioniaMerchant.termsAndConditions,
239 - style: textMedium(
240 - color: Theme.of(context).extension<ReceivePageTheme>()!.tilesTextColor,
241 - ),
242 - ),
243 - ),
244 - actionTitle: S.of(context).agree,
245 - showCloseButton: false,
246 - heightFactor: 0.6,
247 - );
248 - });
249 - }
250 -
251 - Future<void> purchaseCard(BuildContext context) async {
252 - await ioniaPurchaseViewModel.createInvoice();
253 -
254 - if (ioniaPurchaseViewModel.invoiceCreationState is ExecutedSuccessfullyState) {
255 - await _presentSuccessfulInvoiceCreationPopup(context);
256 - }
257 - }
258 -
259 - void _showHowToUseCard(
260 - BuildContext context,
261 - IoniaMerchant merchant,
262 - ) {
263 - showPopUp<void>(
264 - context: context,
265 - builder: (BuildContext context) {
266 - return IoniaAlertModal(
267 - title: S.of(context).how_to_use_card,
268 - content: Column(
269 - crossAxisAlignment: CrossAxisAlignment.start,
270 - children: merchant.instructions
271 - .map((instruction) {
272 - return [
273 - Padding(
274 - padding: EdgeInsets.all(10),
275 - child: Text(
276 - instruction.header,
277 - style: textLargeSemiBold(
278 - color: Theme.of(context).extension<ReceivePageTheme>()!.tilesTextColor,
279 - ),
280 - )),
281 - Text(
282 - instruction.body,
283 - style: textMedium(
284 - color: Theme.of(context).extension<ReceivePageTheme>()!.tilesTextColor,
285 - ),
286 - )
287 - ];
288 - })
289 - .expand((e) => e)
290 - .toList()),
291 - actionTitle: S.current.got_it,
292 - );
293 - });
294 - }
295 -
296 - Future<void> _presentSuccessfulInvoiceCreationPopup(BuildContext context) async {
297 - if (ioniaPurchaseViewModel.invoice == null) {
298 - return;
299 - }
300 -
301 - final amount = ioniaPurchaseViewModel.invoice!.totalAmount;
302 - final addresses = ioniaPurchaseViewModel.invoice!.outAddresses;
303 - ioniaPurchaseViewModel.sendViewModel.outputs.first.setCryptoAmount(amount);
304 - ioniaPurchaseViewModel.sendViewModel.outputs.first.address = addresses.first;
305 -
306 - await showPopUp<void>(
307 - context: context,
308 - builder: (_) {
309 - return ConfirmSendingAlert(
310 - alertTitle: S.of(context).confirm_sending,
311 - paymentId: S.of(context).payment_id,
312 - paymentIdValue: ioniaPurchaseViewModel.invoice!.paymentId,
313 - amount: S.of(context).send_amount,
314 - amountValue: '$amount ${ioniaPurchaseViewModel.invoice!.chain}',
315 - fiatAmountValue:
316 - '~ ${ioniaPurchaseViewModel.sendViewModel.outputs.first.fiatAmount} '
317 - '${ioniaPurchaseViewModel.sendViewModel.fiat.title}',
318 - fee: S.of(context).send_fee,
319 - feeValue:
320 - '${ioniaPurchaseViewModel.sendViewModel.outputs.first.estimatedFee} '
321 - '${ioniaPurchaseViewModel.invoice!.chain}',
322 - feeFiatAmount:
323 - '${ioniaPurchaseViewModel.sendViewModel.outputs.first.estimatedFeeFiatAmount} '
324 - '${ioniaPurchaseViewModel.sendViewModel.fiat.title}',
325 - outputs: ioniaPurchaseViewModel.sendViewModel.outputs,
326 - rightButtonText: S.of(context).ok,
327 - leftButtonText: S.of(context).cancel,
328 - alertLeftActionButtonTextColor: Colors.white,
329 - alertRightActionButtonTextColor: Colors.white,
330 - alertLeftActionButtonColor: Palette.brightOrange,
331 - alertRightActionButtonColor: Theme.of(context).primaryColor,
332 - actionRightButton: () async {
333 - Navigator.of(context).pop();
334 - await ioniaPurchaseViewModel.commitPaymentInvoice();
335 - },
336 - actionLeftButton: () => Navigator.of(context).pop());
337 - },
338 - );
339 - }
340 -}
341 -
342 -class TipButtonGroup extends StatelessWidget {
343 - const TipButtonGroup({
344 - Key? key,
345 - required this.selectedTip,
346 - required this.onSelect,
347 - required this.tipsList,
348 - required this.amount,
349 - required this.merchant,
350 - }) : super(key: key);
351 -
352 - final Function(IoniaTip) onSelect;
353 - final double selectedTip;
354 - final List<IoniaTip> tipsList;
355 - final double amount;
356 - final IoniaMerchant merchant;
357 -
358 - bool _isSelected(double value) => selectedTip == value;
359 - Set<double> get filter => tipsList.map((e) => e.percentage).toSet();
360 - bool get _isCustomSelected => !filter.contains(selectedTip);
361 -
362 - @override
363 - Widget build(BuildContext context) {
364 - return Container(
365 - height: 50,
366 - child: ListView.builder(
367 - scrollDirection: Axis.horizontal,
368 - itemCount: tipsList.length,
369 - itemBuilder: (BuildContext context, int index) {
370 - final tip = tipsList[index];
371 - return Padding(
372 - padding: EdgeInsets.only(right: 5),
373 - child: TipButton(
374 - isSelected: tip.isCustom ? _isCustomSelected : _isSelected(tip.percentage),
375 - onTap: () async {
376 - IoniaTip ioniaTip = tip;
377 - if(tip.isCustom){
378 - final customTip = await Navigator.pushNamed(context, Routes.ioniaCustomTipPage, arguments: [amount, merchant, tip]) as IoniaTip?;
379 - ioniaTip = customTip ?? tip;
380 - }
381 - onSelect(ioniaTip);
382 - },
383 - caption: tip.isCustom ? S.of(context).custom : '${tip.percentage.toStringAsFixed(0)}%',
384 - subTitle: tip.isCustom ? null : '\$${tip.additionalAmount.toStringAsFixed(2)}',
385 - ));
386 - }));
387 - }
388 -}
389 -
390 -class TipButton extends StatelessWidget {
391 - const TipButton({
392 - required this.caption,
393 - required this.onTap,
394 - this.subTitle,
395 - this.isSelected = false,
396 - });
397 -
398 - final String caption;
399 - final String? subTitle;
400 - final bool isSelected;
401 - final void Function() onTap;
402 -
403 - bool isDark(BuildContext context) => Theme.of(context).brightness == Brightness.dark;
404 -
405 - Color captionTextColor(BuildContext context) {
406 - if (isDark(context)) {
407 - return Theme.of(context).extension<CakeTextTheme>()!.titleColor;
408 - }
409 -
410 - return isSelected
411 - ? Theme.of(context).dialogTheme.backgroundColor!
412 - : Theme.of(context).extension<CakeTextTheme>()!.titleColor;
413 - }
414 -
415 - Color subTitleTextColor(BuildContext context) {
416 - if (isDark(context)) {
417 - return Theme.of(context).extension<CakeTextTheme>()!.titleColor;
418 - }
419 -
420 - return isSelected
421 - ? Theme.of(context).dialogTheme.backgroundColor!
422 - : Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor;
423 - }
424 -
425 - Color? backgroundColor(BuildContext context) {
426 - if (isDark(context)) {
427 - return isSelected
428 - ? null
429 - : Theme.of(context).extension<CakeTextTheme>()!.titleColor.withOpacity(0.01);
430 - }
431 -
432 - return isSelected
433 - ? null
434 - : Theme.of(context).extension<CakeTextTheme>()!.titleColor.withOpacity(0.1);
435 - }
436 -
437 - @override
438 - Widget build(BuildContext context) {
439 - return InkWell(
440 - onTap: onTap,
441 - child: Container(
442 - height: 49,
443 - child: Column(
444 - mainAxisAlignment: MainAxisAlignment.center,
445 - children: [
446 - Text(caption,
447 - style: textSmallSemiBold(
448 - color: captionTextColor(context))),
449 - if (subTitle != null) ...[
450 - SizedBox(height: 4),
451 - Text(
452 - subTitle!,
453 - style: textXxSmallSemiBold(
454 - color: subTitleTextColor(context),
455 - ),
456 - ),
457 - ]
458 - ],
459 - ),
460 - padding: EdgeInsets.symmetric(horizontal: 18, vertical: 8),
461 - decoration: BoxDecoration(
462 - borderRadius: BorderRadius.circular(10),
463 - color: backgroundColor(context),
464 - gradient: isSelected
465 - ? LinearGradient(
466 - colors: [
467 - Theme.of(context).extension<SendPageTheme>()!.firstGradientColor,
468 - Theme.of(context).extension<SendPageTheme>()!.secondGradientColor,
469 - ],
470 - begin: Alignment.topLeft,
471 - end: Alignment.bottomRight,
472 - )
473 - : null,
474 - ),
475 - ),
476 - );
477 - }
478 -}
lib/src/screens/ionia/cards/ionia_buy_gift_card.dart deleted
-186
@@ -1,186 +0,0 @@
1 -import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
2 -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
3 -import 'package:cake_wallet/routes.dart';
4 -import 'package:cake_wallet/src/screens/base_page.dart';
5 -import 'package:cake_wallet/src/screens/ionia/widgets/card_item.dart';
6 -import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
7 -import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
8 -import 'package:cake_wallet/src/widgets/primary_button.dart';
9 -import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
10 -import 'package:cake_wallet/themes/theme_base.dart';
11 -import 'package:cake_wallet/utils/responsive_layout_util.dart';
12 -import 'package:cake_wallet/view_model/ionia/ionia_buy_card_view_model.dart';
13 -import 'package:flutter/material.dart';
14 -import 'package:flutter/services.dart';
15 -import 'package:flutter_mobx/flutter_mobx.dart';
16 -import 'package:keyboard_actions/keyboard_actions.dart';
17 -import 'package:cake_wallet/generated/i18n.dart';
18 -import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
19 -
20 -class IoniaBuyGiftCardPage extends BasePage {
21 - IoniaBuyGiftCardPage(
22 - this.ioniaBuyCardViewModel,
23 - ) : _amountFieldFocus = FocusNode(),
24 - _amountController = TextEditingController() {
25 - _amountController.addListener(() {
26 - ioniaBuyCardViewModel.onAmountChanged(_amountController.text);
27 - });
28 - }
29 -
30 - final IoniaBuyCardViewModel ioniaBuyCardViewModel;
31 -
32 - @override
33 - String get title => S.current.enter_amount;
34 -
35 - @override
36 - bool get extendBodyBehindAppBar => true;
37 -
38 - @override
39 - AppBarStyle get appBarStyle => AppBarStyle.transparent;
40 -
41 - Color get textColor => currentTheme.type == ThemeType.dark ? Colors.white : Color(0xff393939);
42 -
43 - final TextEditingController _amountController;
44 - final FocusNode _amountFieldFocus;
45 -
46 - @override
47 - Widget body(BuildContext context) {
48 - final merchant = ioniaBuyCardViewModel.ioniaMerchant;
49 - return KeyboardActions(
50 - disableScroll: true,
51 - config: KeyboardActionsConfig(
52 - keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
53 - keyboardBarColor: Theme.of(context).extension<KeyboardTheme>()!.keyboardBarColor,
54 - nextFocus: false,
55 - actions: [
56 - KeyboardActionsItem(
57 - focusNode: _amountFieldFocus,
58 - toolbarButtons: [(_) => KeyboardDoneButton()],
59 - ),
60 - ]),
61 - child: Container(
62 - color: Theme.of(context).colorScheme.background,
63 - child: ScrollableWithBottomSection(
64 - contentPadding: EdgeInsets.zero,
65 - content: Column(
66 - children: [
67 - Container(
68 - padding: EdgeInsets.symmetric(horizontal: 25),
69 - decoration: BoxDecoration(
70 - borderRadius: BorderRadius.only(
71 - bottomLeft: Radius.circular(24),
72 - bottomRight: Radius.circular(24),
73 - ),
74 - gradient: LinearGradient(colors: [
75 - Theme.of(context).extension<SendPageTheme>()!.firstGradientColor,
76 - Theme.of(context).extension<SendPageTheme>()!.secondGradientColor,
77 - ], begin: Alignment.topLeft, end: Alignment.bottomRight),
78 - ),
79 - child: Column(
80 - mainAxisSize: MainAxisSize.min,
81 - mainAxisAlignment: MainAxisAlignment.center,
82 - children: [
83 - SizedBox(height: 150),
84 - SizedBox(
85 - width: 200,
86 - child: BaseTextFormField(
87 - controller: _amountController,
88 - focusNode: _amountFieldFocus,
89 - keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true),
90 - inputFormatters: [
91 - FilteringTextInputFormatter.deny(RegExp('[\-|\ ]')),
92 - FilteringTextInputFormatter.allow(
93 - RegExp(r'^\d+(\.|\,)?\d{0,2}'),
94 - ),
95 - ],
96 - hintText: '1000',
97 - placeholderTextStyle: TextStyle(
98 - color: Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor,
99 - fontWeight: FontWeight.w600,
100 - fontSize: 36,
101 - ),
102 - prefixIcon: Text(
103 - 'USD: ',
104 - style: TextStyle(
105 - color: Colors.white,
106 - fontWeight: FontWeight.w600,
107 - fontSize: 36,
108 - ),
109 - ),
110 - textColor: Colors.white,
111 - textStyle: TextStyle(
112 - color: Colors.white,
113 - fontSize: 36,
114 - ),
115 - ),
116 - ),
117 - Divider(
118 - color: Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor,
119 - height: 1,
120 - ),
121 - SizedBox(height: 8),
122 - Row(
123 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
124 - crossAxisAlignment: CrossAxisAlignment.start,
125 - children: [
126 - Text(
127 - S.of(context).min_amount(merchant.minimumCardPurchase.toStringAsFixed(2)),
128 - style: TextStyle(
129 - color: Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor,
130 - ),
131 - ),
132 - Text(
133 - S.of(context).max_amount(merchant.maximumCardPurchase.toStringAsFixed(2)),
134 - style: TextStyle(
135 - color: Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor,
136 - ),
137 - ),
138 - ],
139 - ),
140 - SizedBox(height: 24),
141 - ],
142 - ),
143 - ),
144 - Padding(
145 - padding: const EdgeInsets.all(24.0),
146 - child: CardItem(
147 - title: merchant.legalName,
148 - backgroundColor: Theme.of(context).extension<CakeTextTheme>()!.titleColor
149 - .withOpacity(0.1),
150 - discount: merchant.discount,
151 - titleColor: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
152 - subtitleColor: Theme.of(context).hintColor,
153 - subTitle: merchant.avaibilityStatus,
154 - logoUrl: merchant.logoUrl,
155 - ),
156 - )
157 - ],
158 - ),
159 - bottomSection: Column(
160 - children: [
161 - Observer(builder: (_) {
162 - return Padding(
163 - padding: EdgeInsets.only(bottom: 12),
164 - child: PrimaryButton(
165 - onPressed: () => Navigator.of(context).pushNamed(
166 - Routes.ioniaBuyGiftCardDetailPage,
167 - arguments: [
168 - ioniaBuyCardViewModel.amount,
169 - ioniaBuyCardViewModel.ioniaMerchant,
170 - ],
171 - ),
172 - text: S.of(context).continue_text,
173 - isDisabled: !ioniaBuyCardViewModel.isEnablePurchase,
174 - color: Theme.of(context).primaryColor,
175 - textColor: Colors.white,
176 - ),
177 - );
178 - }),
179 - SizedBox(height: 30),
180 - ],
181 - ),
182 - ),
183 - ),
184 - );
185 - }
186 -}
lib/src/screens/ionia/cards/ionia_custom_redeem_page.dart deleted
-175
@@ -1,175 +0,0 @@
1 -import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
2 -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
3 -import 'package:cake_wallet/core/execution_state.dart';
4 -import 'package:cake_wallet/src/screens/base_page.dart';
5 -import 'package:cake_wallet/src/screens/ionia/widgets/card_item.dart';
6 -import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
7 -import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
8 -import 'package:cake_wallet/src/widgets/primary_button.dart';
9 -import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
10 -import 'package:cake_wallet/themes/theme_base.dart';
11 -import 'package:cake_wallet/view_model/ionia/ionia_custom_redeem_view_model.dart';
12 -import 'package:flutter/material.dart';
13 -import 'package:flutter/services.dart';
14 -import 'package:flutter_mobx/flutter_mobx.dart';
15 -import 'package:keyboard_actions/keyboard_actions.dart';
16 -import 'package:cake_wallet/generated/i18n.dart';
17 -import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
18 -
19 -class IoniaCustomRedeemPage extends BasePage {
20 - IoniaCustomRedeemPage(
21 - this.ioniaCustomRedeemViewModel,
22 - ) : _amountFieldFocus = FocusNode(),
23 - _amountController = TextEditingController() {
24 - _amountController.addListener(() {
25 - ioniaCustomRedeemViewModel.updateAmount(_amountController.text);
26 - });
27 - }
28 -
29 - final IoniaCustomRedeemViewModel ioniaCustomRedeemViewModel;
30 -
31 - @override
32 - String get title => S.current.custom_redeem_amount;
33 -
34 - @override
35 - bool get extendBodyBehindAppBar => true;
36 -
37 - @override
38 - AppBarStyle get appBarStyle => AppBarStyle.transparent;
39 -
40 - Color get textColor => currentTheme.type == ThemeType.dark ? Colors.white : Color(0xff393939);
41 -
42 - final TextEditingController _amountController;
43 - final FocusNode _amountFieldFocus;
44 -
45 - @override
46 - Widget body(BuildContext context) {
47 - final _width = MediaQuery.of(context).size.width;
48 - final giftCard = ioniaCustomRedeemViewModel.giftCard;
49 - return KeyboardActions(
50 - disableScroll: true,
51 - config: KeyboardActionsConfig(
52 - keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
53 - keyboardBarColor: Theme.of(context).extension<KeyboardTheme>()!.keyboardBarColor,
54 - nextFocus: false,
55 - actions: [
56 - KeyboardActionsItem(
57 - focusNode: _amountFieldFocus,
58 - toolbarButtons: [(_) => KeyboardDoneButton()],
59 - ),
60 - ]),
61 - child: Container(
62 - color: Theme.of(context).colorScheme.background,
63 - child: ScrollableWithBottomSection(
64 - contentPadding: EdgeInsets.zero,
65 - content: Column(
66 - children: [
67 - Container(
68 - padding: EdgeInsets.symmetric(horizontal: 25),
69 - decoration: BoxDecoration(
70 - borderRadius: BorderRadius.only(
71 - bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
72 - gradient: LinearGradient(colors: [
73 - Theme.of(context).extension<SendPageTheme>()!.firstGradientColor,
74 - Theme.of(context).extension<SendPageTheme>()!.secondGradientColor,
75 - ], begin: Alignment.topLeft, end: Alignment.bottomRight),
76 - ),
77 - child: Column(
78 - mainAxisSize: MainAxisSize.min,
79 - crossAxisAlignment: CrossAxisAlignment.stretch,
80 - children: [
81 - SizedBox(height: 150),
82 - BaseTextFormField(
83 - controller: _amountController,
84 - focusNode: _amountFieldFocus,
85 - keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true),
86 - inputFormatters: [FilteringTextInputFormatter.deny(RegExp('[\-|\ ]'))],
87 - hintText: '1000',
88 - placeholderTextStyle: TextStyle(
89 - color: Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor,
90 - fontWeight: FontWeight.w500,
91 - fontSize: 36,
92 - ),
93 - borderColor: Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor,
94 - textColor: Colors.white,
95 - textStyle: TextStyle(
96 - color: Colors.white,
97 - fontSize: 36,
98 - ),
99 - suffixIcon: SizedBox(
100 - width: _width / 6,
101 - ),
102 - prefixIcon: Padding(
103 - padding: EdgeInsets.only(
104 - top: 5.0,
105 - left: _width / 4,
106 - ),
107 - child: Text(
108 - 'USD: ',
109 - style: TextStyle(
110 - color: Colors.white,
111 - fontWeight: FontWeight.w900,
112 - fontSize: 36,
113 - ),
114 - ),
115 - ),
116 - ),
117 - SizedBox(height: 8),
118 - Observer(
119 - builder: (_) => !ioniaCustomRedeemViewModel.disableRedeem
120 - ? Center(
121 - child: Text(
122 - '\$${giftCard.remainingAmount} - \$${ioniaCustomRedeemViewModel.amount} = \$${ioniaCustomRedeemViewModel.formattedRemaining} ${S.of(context).remaining}',
123 - style: TextStyle(
124 - color: Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor,
125 - ),
126 - ),
127 - )
128 - : SizedBox.shrink(),
129 - ),
130 - SizedBox(height: 24),
131 - ],
132 - ),
133 - ),
134 - Padding(
135 - padding: const EdgeInsets.all(24.0),
136 - child: CardItem(
137 - title: giftCard.legalName,
138 - backgroundColor: Theme.of(context).extension<CakeTextTheme>()!.titleColor
139 - .withOpacity(0.1),
140 - discount: giftCard.remainingAmount,
141 - isAmount: true,
142 - discountBackground: AssetImage('assets/images/red_badge_discount.png'),
143 - titleColor: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
144 - subtitleColor: Theme.of(context).hintColor,
145 - subTitle: S.of(context).online,
146 - logoUrl: giftCard.logoUrl,
147 - ),
148 - ),
149 - ],
150 - ),
151 - bottomSection: Column(
152 - children: [
153 - Observer(
154 - builder: (_) => Padding(
155 - padding: EdgeInsets.only(bottom: 12),
156 - child: LoadingPrimaryButton(
157 - isLoading: ioniaCustomRedeemViewModel.redeemState is IsExecutingState,
158 - isDisabled: ioniaCustomRedeemViewModel.disableRedeem,
159 - text: S.of(context).add_custom_redemption,
160 - color: Theme.of(context).primaryColor,
161 - textColor: Colors.white,
162 - onPressed: () => ioniaCustomRedeemViewModel.addCustomRedeem().then((value) {
163 - Navigator.of(context).pop(ioniaCustomRedeemViewModel.remaining.toString());
164 - }),
165 - ),
166 - ),
167 - ),
168 - SizedBox(height: 30),
169 - ],
170 - ),
171 - ),
172 - ),
173 - );
174 - }
175 -}
lib/src/screens/ionia/cards/ionia_custom_tip_page.dart deleted
-177
@@ -1,177 +0,0 @@
1 -import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
2 -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
3 -import 'package:cake_wallet/ionia/ionia_merchant.dart';
4 -import 'package:cake_wallet/src/screens/base_page.dart';
5 -import 'package:cake_wallet/src/screens/ionia/widgets/card_item.dart';
6 -import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
7 -import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
8 -import 'package:cake_wallet/src/widgets/primary_button.dart';
9 -import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
10 -import 'package:cake_wallet/themes/theme_base.dart';
11 -import 'package:cake_wallet/view_model/ionia/ionia_custom_tip_view_model.dart';
12 -import 'package:flutter/material.dart';
13 -import 'package:flutter/services.dart';
14 -import 'package:flutter_mobx/flutter_mobx.dart';
15 -import 'package:keyboard_actions/keyboard_actions.dart';
16 -import 'package:cake_wallet/generated/i18n.dart';
17 -import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
18 -
19 -class IoniaCustomTipPage extends BasePage {
20 - IoniaCustomTipPage(
21 - this.customTipViewModel,
22 - ) : _amountFieldFocus = FocusNode(),
23 - _amountController = TextEditingController() {
24 - _amountController.addListener(() {
25 - customTipViewModel.onTipChanged(_amountController.text);
26 - });
27 - }
28 -
29 - final IoniaCustomTipViewModel customTipViewModel;
30 -
31 -
32 - @override
33 - String get title => S.current.enter_amount;
34 -
35 - @override
36 - bool get extendBodyBehindAppBar => true;
37 -
38 - @override
39 - AppBarStyle get appBarStyle => AppBarStyle.transparent;
40 -
41 - Color get textColor => currentTheme.type == ThemeType.dark ? Colors.white : Color(0xff393939);
42 -
43 - final TextEditingController _amountController;
44 - final FocusNode _amountFieldFocus;
45 -
46 - @override
47 - Widget body(BuildContext context) {
48 - final _width = MediaQuery.of(context).size.width;
49 - final merchant = customTipViewModel.ioniaMerchant;
50 - return KeyboardActions(
51 - disableScroll: true,
52 - config: KeyboardActionsConfig(
53 - keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
54 - keyboardBarColor: Theme.of(context).extension<KeyboardTheme>()!.keyboardBarColor,
55 - nextFocus: false,
56 - actions: [
57 - KeyboardActionsItem(
58 - focusNode: _amountFieldFocus,
59 - toolbarButtons: [(_) => KeyboardDoneButton()],
60 - ),
61 - ]),
62 - child: Container(
63 - color: Theme.of(context).colorScheme.background,
64 - child: ScrollableWithBottomSection(
65 - contentPadding: EdgeInsets.zero,
66 - content: Column(
67 - children: [
68 - Container(
69 - padding: EdgeInsets.symmetric(horizontal: 25),
70 - decoration: BoxDecoration(
71 - borderRadius: BorderRadius.only(bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
72 - gradient: LinearGradient(colors: [
73 - Theme.of(context).extension<SendPageTheme>()!.firstGradientColor,
74 - Theme.of(context).extension<SendPageTheme>()!.secondGradientColor,
75 - ], begin: Alignment.topLeft, end: Alignment.bottomRight),
76 - ),
77 - child: Column(
78 - mainAxisSize: MainAxisSize.min,
79 - crossAxisAlignment: CrossAxisAlignment.stretch,
80 - children: [
81 - SizedBox(height: 150),
82 - BaseTextFormField(
83 - controller: _amountController,
84 - focusNode: _amountFieldFocus,
85 - keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true),
86 - inputFormatters: [FilteringTextInputFormatter.deny(RegExp('[\-|\ ]'))],
87 - hintText: '1000',
88 - placeholderTextStyle: TextStyle(
89 - color: Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor,
90 - fontWeight: FontWeight.w500,
91 - fontSize: 36,
92 - ),
93 - borderColor: Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor,
94 - textColor: Colors.white,
95 - textStyle: TextStyle(
96 - color: Colors.white,
97 - fontSize: 36,
98 - ),
99 - suffixIcon: SizedBox(
100 - width: _width / 6,
101 - ),
102 - prefixIcon: Padding(
103 - padding: EdgeInsets.only(
104 - top: 5.0,
105 - left: _width / 4,
106 - ),
107 - child: Text(
108 - 'USD: ',
109 - style: TextStyle(
110 - color: Colors.white,
111 - fontWeight: FontWeight.w900,
112 - fontSize: 36,
113 - ),
114 - ),
115 - ),
116 - ),
117 - SizedBox(height: 8),
118 - Observer(builder: (_) {
119 - if (customTipViewModel.percentage == 0.0) {
120 - return SizedBox.shrink();
121 - }
122 -
123 - return RichText(
124 - textAlign: TextAlign.center,
125 - text: TextSpan(
126 - text: '\$${_amountController.text}',
127 - style: TextStyle(
128 - color: Theme.of(context).extension<SendPageTheme>()!.textFieldBorderColor,
129 - ),
130 - children: [
131 - TextSpan(text: ' ${S.of(context).is_percentage} '),
132 - TextSpan(text: '${customTipViewModel.percentage.toStringAsFixed(2)}%'),
133 - TextSpan(text: ' ${S.of(context).percentageOf(customTipViewModel.amount.toStringAsFixed(2))} '),
134 - ],
135 - ),
136 - );
137 - }),
138 - SizedBox(height: 24),
139 - ],
140 - ),
141 - ),
142 - Padding(
143 - padding: const EdgeInsets.all(24.0),
144 - child: CardItem(
145 - title: merchant.legalName,
146 - backgroundColor: Theme.of(context).extension<CakeTextTheme>()!.titleColor
147 - .withOpacity(0.1),
148 - discount: 0.0,
149 - titleColor: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
150 - subtitleColor: Theme.of(context).hintColor,
151 - subTitle: merchant.isOnline ? S.of(context).online : S.of(context).offline,
152 - logoUrl: merchant.logoUrl,
153 - ),
154 - )
155 - ],
156 - ),
157 - bottomSection: Column(
158 - children: [
159 - Padding(
160 - padding: EdgeInsets.only(bottom: 12),
161 - child: PrimaryButton(
162 - onPressed: () {
163 - Navigator.of(context).pop(customTipViewModel.customTip);
164 - },
165 - text: S.of(context).add_tip,
166 - color: Theme.of(context).primaryColor,
167 - textColor: Colors.white,
168 - ),
169 - ),
170 - SizedBox(height: 30),
171 - ],
172 - ),
173 - ),
174 - ),
175 - );
176 - }
177 -}
lib/src/screens/ionia/cards/ionia_debit_card_page.dart deleted
-393
@@ -1,393 +0,0 @@
1 -import 'package:cake_wallet/ionia/ionia_create_state.dart';
2 -import 'package:cake_wallet/themes/extensions/receive_page_theme.dart';
3 -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
4 -import 'package:cake_wallet/ionia/ionia_virtual_card.dart';
5 -import 'package:cake_wallet/routes.dart';
6 -import 'package:cake_wallet/src/screens/base_page.dart';
7 -import 'package:cake_wallet/src/screens/ionia/widgets/text_icon_button.dart';
8 -import 'package:cake_wallet/src/widgets/alert_background.dart';
9 -import 'package:cake_wallet/src/widgets/primary_button.dart';
10 -import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
11 -import 'package:cake_wallet/themes/extensions/cake_scrollbar_theme.dart';
12 -import 'package:cake_wallet/typography.dart';
13 -import 'package:cake_wallet/utils/show_pop_up.dart';
14 -import 'package:cake_wallet/view_model/ionia/ionia_gift_cards_list_view_model.dart';
15 -import 'package:flutter/material.dart';
16 -import 'package:cake_wallet/generated/i18n.dart';
17 -import 'package:flutter_mobx/flutter_mobx.dart';
18 -import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
19 -
20 -class IoniaDebitCardPage extends BasePage {
21 - final IoniaGiftCardsListViewModel _cardsListViewModel;
22 -
23 - IoniaDebitCardPage(this._cardsListViewModel);
24 -
25 - @override
26 - Widget middle(BuildContext context) {
27 - return Text(
28 - S.current.debit_card,
29 - style: textMediumSemiBold(
30 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
31 - ),
32 - );
33 - }
34 -
35 - @override
36 - Widget body(BuildContext context) {
37 - return Observer(
38 - builder: (_) {
39 - final cardState = _cardsListViewModel.cardState;
40 - if (cardState is IoniaFetchingCard) {
41 - return Center(child: CircularProgressIndicator());
42 - }
43 - if (cardState is IoniaCardSuccess) {
44 - return ScrollableWithBottomSection(
45 - contentPadding: EdgeInsets.zero,
46 - content: Padding(
47 - padding: const EdgeInsets.all(16.0),
48 - child: _IoniaDebitCard(
49 - cardInfo: cardState.card,
50 - ),
51 - ),
52 - bottomSection: Column(
53 - children: [
54 - Padding(
55 - padding: const EdgeInsets.symmetric(horizontal: 20.0),
56 - child: Text(
57 - S.of(context).billing_address_info,
58 - style: textSmall(
59 - color: Theme.of(context).extension<ReceivePageTheme>()!.iconsColor),
60 - textAlign: TextAlign.center,
61 - ),
62 - ),
63 - SizedBox(height: 24),
64 - PrimaryButton(
65 - text: S.of(context).order_physical_card,
66 - onPressed: () {},
67 - color: Color(0xffE9F2FC),
68 - textColor: Theme.of(context).extension<ReceivePageTheme>()!.tilesTextColor,
69 - ),
70 - SizedBox(height: 8),
71 - PrimaryButton(
72 - text: S.of(context).add_value,
73 - onPressed: () {},
74 - color: Theme.of(context).primaryColor,
75 - textColor: Colors.white,
76 - ),
77 - SizedBox(height: 16)
78 - ],
79 - ),
80 - );
81 - }
82 - return ScrollableWithBottomSection(
83 - contentPadding: EdgeInsets.zero,
84 - content: Padding(
85 - padding: const EdgeInsets.all(16.0),
86 - child: Column(
87 - children: [
88 - _IoniaDebitCard(isCardSample: true),
89 - SizedBox(height: 40),
90 - Padding(
91 - padding: const EdgeInsets.symmetric(horizontal: 8.0),
92 - child: Column(
93 - children: [
94 - TextIconButton(
95 - label: S.current.how_to_use_card,
96 - onTap: () => _showHowToUseCard(context),
97 - ),
98 - SizedBox(
99 - height: 24,
100 - ),
101 - TextIconButton(
102 - label: S.current.frequently_asked_questions,
103 - onTap: () {},
104 - ),
105 - ],
106 - ),
107 - ),
108 - SizedBox(height: 50),
109 - Container(
110 - padding: EdgeInsets.all(20),
111 - margin: EdgeInsets.all(8),
112 - width: double.infinity,
113 - decoration: BoxDecoration(
114 - color: Color.fromRGBO(233, 242, 252, 1),
115 - borderRadius: BorderRadius.circular(20),
116 - ),
117 - child: RichText(
118 - text: TextSpan(
119 - text: S.of(context).get_a,
120 - style: textMedium(
121 - color:
122 - Theme.of(context).extension<ReceivePageTheme>()!.tilesTextColor),
123 - children: [
124 - TextSpan(
125 - text: S.of(context).digital_and_physical_card,
126 - style: textMediumBold(
127 - color: Theme.of(context).extension<ReceivePageTheme>()!.tilesTextColor),
128 - ),
129 - TextSpan(
130 - text: S.of(context).get_card_note,
131 - )
132 - ],
133 - )),
134 - ),
135 - ],
136 - ),
137 - ),
138 - bottomSectionPadding: EdgeInsets.symmetric(
139 - horizontal: 16,
140 - vertical: 32,
141 - ),
142 - bottomSection: PrimaryButton(
143 - text: S.of(context).activate,
144 - onPressed: () => _showHowToUseCard(context, activate: true),
145 - color: Theme.of(context).primaryColor,
146 - textColor: Colors.white,
147 - ),
148 - );
149 - },
150 - );
151 - }
152 -
153 - void _showHowToUseCard(BuildContext context, {bool activate = false}) {
154 - showPopUp<void>(
155 - context: context,
156 - builder: (BuildContext context) {
157 - return AlertBackground(
158 - child: Material(
159 - color: Colors.transparent,
160 - child: Column(
161 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
162 - children: [
163 - SizedBox(height: 10),
164 - Container(
165 - padding: EdgeInsets.only(top: 24, left: 24, right: 24),
166 - margin: EdgeInsets.all(24),
167 - decoration: BoxDecoration(
168 - color: Theme.of(context).colorScheme.background,
169 - borderRadius: BorderRadius.circular(30),
170 - ),
171 - child: Column(
172 - children: [
173 - Text(
174 - S.of(context).how_to_use_card,
175 - style: textLargeSemiBold(
176 - color:
177 - Theme.of(context).extension<CakeScrollbarTheme>()!.thumbColor,
178 - ),
179 - ),
180 - SizedBox(height: 24),
181 - Align(
182 - alignment: Alignment.bottomLeft,
183 - child: Text(
184 - S.of(context).signup_for_card_accept_terms,
185 - style: textSmallSemiBold(
186 - color: Theme.of(context).extension<ReceivePageTheme>()!.tilesTextColor,
187 - ),
188 - ),
189 - ),
190 - SizedBox(height: 24),
191 - _TitleSubtitleTile(
192 - title: S.of(context).add_fund_to_card('1000'),
193 - subtitle: S.of(context).use_card_info_two,
194 - ),
195 - SizedBox(height: 21),
196 - _TitleSubtitleTile(
197 - title: S.of(context).use_card_info_three,
198 - subtitle: S.of(context).optionally_order_card,
199 - ),
200 - SizedBox(height: 35),
201 - PrimaryButton(
202 - onPressed: () => activate
203 - ? Navigator.pushNamed(context, Routes.ioniaActivateDebitCardPage)
204 - : Navigator.pop(context),
205 - text: S.of(context).got_it,
206 - color: Color.fromRGBO(233, 242, 252, 1),
207 - textColor:
208 - Theme.of(context).extension<ReceivePageTheme>()!.tilesTextColor,
209 - ),
210 - SizedBox(height: 21),
211 - ],
212 - ),
213 - ),
214 - InkWell(
215 - onTap: () => Navigator.pop(context),
216 - child: Container(
217 - margin: EdgeInsets.only(bottom: 40),
218 - child: CircleAvatar(
219 - child: Icon(
220 - Icons.close,
221 - color: Colors.black,
222 - ),
223 - backgroundColor: Colors.white,
224 - ),
225 - ),
226 - )
227 - ],
228 - ),
229 - ),
230 - );
231 - });
232 - }
233 -}
234 -
235 -class _IoniaDebitCard extends StatefulWidget {
236 - const _IoniaDebitCard({
237 - Key? key,
238 - this.cardInfo,
239 - this.isCardSample = false,
240 - }) : super(key: key);
241 -
242 - final bool isCardSample;
243 - final IoniaVirtualCard? cardInfo;
244 -
245 - @override
246 - _IoniaDebitCardState createState() => _IoniaDebitCardState();
247 -}
248 -
249 -class _IoniaDebitCardState extends State<_IoniaDebitCard> {
250 - bool _showDetails = false;
251 - void _toggleVisibility() {
252 - setState(() => _showDetails = !_showDetails);
253 - }
254 -
255 - String _formatPan(String pan) {
256 - if (pan == null) return '';
257 - return pan.replaceAllMapped(RegExp(r'.{4}'), (match) => '${match.group(0)} ');
258 - }
259 -
260 - String get _getLast4 => widget.isCardSample ? '0000' : widget.cardInfo!.pan.substring(widget.cardInfo!.pan.length - 5);
261 -
262 - String get _getSpendLimit => widget.isCardSample ? '10000' : widget.cardInfo!.spendLimit.toStringAsFixed(2);
263 -
264 - @override
265 - Widget build(BuildContext context) {
266 - return Container(
267 - padding: EdgeInsets.symmetric(horizontal: 24, vertical: 19),
268 - decoration: BoxDecoration(
269 - borderRadius: BorderRadius.circular(24),
270 - gradient: LinearGradient(
271 - colors: [
272 - Theme.of(context).extension<SendPageTheme>()!.firstGradientColor,
273 - Theme.of(context).extension<SendPageTheme>()!.secondGradientColor,
274 - ],
275 - begin: Alignment.topLeft,
276 - end: Alignment.bottomRight,
277 - ),
278 - ),
279 - child: Column(
280 - crossAxisAlignment: CrossAxisAlignment.start,
281 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
282 - children: [
283 - SizedBox(height: 16),
284 - Row(
285 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
286 - children: [
287 - Text(
288 - S.current.cakepay_prepaid_card,
289 - style: textSmall(),
290 - ),
291 - Image.asset(
292 - 'assets/images/mastercard.png',
293 - width: 54,
294 - ),
295 - ],
296 - ),
297 - Text(
298 - widget.isCardSample ? S.of(context).upto(_getSpendLimit) : '\$$_getSpendLimit',
299 - style: textXLargeSemiBold(),
300 - ),
301 - SizedBox(height: 16),
302 - Text(
303 - _showDetails ? _formatPan(widget.cardInfo?.pan ?? '') : '**** **** **** $_getLast4',
304 - style: textMediumSemiBold(),
305 - ),
306 - SizedBox(height: 32),
307 - Row(
308 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
309 - children: [
310 - if (widget.isCardSample)
311 - Text(
312 - S.current.no_id_needed,
313 - style: textMediumBold(),
314 - )
315 - else ...[
316 - Column(
317 - children: [
318 - Text(
319 - 'CVV',
320 - style: textXSmallSemiBold(),
321 - ),
322 - SizedBox(height: 4),
323 - Text(
324 - _showDetails ? widget.cardInfo!.cvv : '***',
325 - style: textMediumSemiBold(),
326 - )
327 - ],
328 - ),
329 - Column(
330 - crossAxisAlignment: CrossAxisAlignment.start,
331 - children: [
332 - Text(
333 - S.of(context).expires,
334 - style: textXSmallSemiBold(),
335 - ),
336 - SizedBox(height: 4),
337 - Text(
338 - '${widget.cardInfo?.expirationMonth ?? S.of(context).mm}/${widget.cardInfo?.expirationYear ?? S.of(context).yy}',
339 - style: textMediumSemiBold(),
340 - )
341 - ],
342 - ),
343 - ]
344 - ],
345 - ),
346 - if (!widget.isCardSample) ...[
347 - SizedBox(height: 8),
348 - Center(
349 - child: InkWell(
350 - onTap: () => _toggleVisibility(),
351 - child: Text(
352 - _showDetails ? S.of(context).hide_details : S.of(context).show_details,
353 - style: textSmall(),
354 - ),
355 - ),
356 - ),
357 - ],
358 - ],
359 - ),
360 - );
361 - }
362 -}
363 -
364 -class _TitleSubtitleTile extends StatelessWidget {
365 - const _TitleSubtitleTile({
366 - Key? key,
367 - required this.title,
368 - required this.subtitle,
369 - }) : super(key: key);
370 -
371 - final String title;
372 - final String subtitle;
373 -
374 - @override
375 - Widget build(BuildContext context) {
376 - return Column(
377 - crossAxisAlignment: CrossAxisAlignment.start,
378 - children: [
379 - Text(
380 - title,
381 - style: textSmallSemiBold(
382 - color: Theme.of(context).extension<ReceivePageTheme>()!.tilesTextColor),
383 - ),
384 - SizedBox(height: 4),
385 - Text(
386 - subtitle,
387 - style: textSmall(
388 - color: Theme.of(context).extension<ReceivePageTheme>()!.tilesTextColor),
389 - ),
390 - ],
391 - );
392 - }
393 -}
lib/src/screens/ionia/cards/ionia_gift_card_detail_page.dart deleted
-215
@@ -1,215 +0,0 @@
1 -import 'package:cake_wallet/core/execution_state.dart';
2 -import 'package:cake_wallet/themes/extensions/receive_page_theme.dart';
3 -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
4 -import 'package:cake_wallet/ionia/ionia_gift_card.dart';
5 -import 'package:cake_wallet/routes.dart';
6 -import 'package:cake_wallet/src/screens/base_page.dart';
7 -import 'package:cake_wallet/src/screens/ionia/widgets/ionia_alert_model.dart';
8 -import 'package:cake_wallet/src/screens/ionia/widgets/ionia_tile.dart';
9 -import 'package:cake_wallet/src/screens/ionia/widgets/text_icon_button.dart';
10 -import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
11 -import 'package:cake_wallet/src/widgets/primary_button.dart';
12 -import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
13 -import 'package:cake_wallet/typography.dart';
14 -import 'package:cake_wallet/utils/show_bar.dart';
15 -import 'package:cake_wallet/utils/show_pop_up.dart';
16 -import 'package:cake_wallet/utils/route_aware.dart';
17 -import 'package:cake_wallet/view_model/ionia/ionia_gift_card_details_view_model.dart';
18 -import 'package:device_display_brightness/device_display_brightness.dart';
19 -import 'package:flutter/material.dart';
20 -import 'package:flutter/services.dart';
21 -import 'package:cake_wallet/generated/i18n.dart';
22 -import 'package:flutter_mobx/flutter_mobx.dart';
23 -import 'package:mobx/mobx.dart';
24 -
25 -class IoniaGiftCardDetailPage extends BasePage {
26 - IoniaGiftCardDetailPage(this.viewModel);
27 -
28 - final IoniaGiftCardDetailsViewModel viewModel;
29 -
30 - @override
31 - Widget? leading(BuildContext context) {
32 - if (ModalRoute.of(context)!.isFirst) {
33 - return null;
34 - }
35 -
36 - final _backButton = Icon(
37 - Icons.arrow_back_ios,
38 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
39 - size: 16,
40 - );
41 - return Padding(
42 - padding: const EdgeInsets.only(left: 10.0),
43 - child: SizedBox(
44 - height: 37,
45 - width: 37,
46 - child: ButtonTheme(
47 - minWidth: double.minPositive,
48 - child: TextButton(
49 - // FIX-ME: Style
50 - //highlightColor: Colors.transparent,
51 - //splashColor: Colors.transparent,
52 - //padding: EdgeInsets.all(0),
53 - onPressed: ()=> onClose(context),
54 - child: _backButton),
55 - ),
56 - ),
57 - );
58 - }
59 -
60 - @override
61 - Widget middle(BuildContext context) {
62 - return Text(
63 - viewModel.giftCard.legalName,
64 - style: textMediumSemiBold(
65 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor),
66 - );
67 - }
68 -
69 - @override
70 - Widget body(BuildContext context) {
71 - reaction((_) => viewModel.redeemState, (ExecutionState state) {
72 - if (state is FailureState) {
73 - WidgetsBinding.instance.addPostFrameCallback((_) {
74 - showPopUp<void>(
75 - context: context,
76 - builder: (BuildContext context) {
77 - return AlertWithOneAction(
78 - alertTitle: S.of(context).error,
79 - alertContent: state.error,
80 - buttonText: S.of(context).ok,
81 - buttonAction: () => Navigator.of(context).pop());
82 - });
83 - });
84 - }
85 - });
86 -
87 - return ScrollableWithBottomSection(
88 - contentPadding: EdgeInsets.all(24),
89 - content: Column(
90 - children: [
91 - if (viewModel.giftCard.barcodeUrl != null && viewModel.giftCard.barcodeUrl.isNotEmpty)
92 - Padding(
93 - padding: const EdgeInsets.symmetric(
94 - horizontal: 24.0,
95 - vertical: 24,
96 - ),
97 - child: Image.network(viewModel.giftCard.barcodeUrl),
98 - ),
99 - SizedBox(height: 24),
100 - buildIoniaTile(
101 - context,
102 - title: S.of(context).gift_card_number,
103 - subTitle: viewModel.giftCard.cardNumber,
104 - ),
105 - if (viewModel.giftCard.cardPin.isNotEmpty) ...[
106 - Divider(height: 30),
107 - buildIoniaTile(
108 - context,
109 - title: S.of(context).pin_number,
110 - subTitle: viewModel.giftCard.cardPin,
111 - )
112 - ],
113 - Divider(height: 30),
114 - Observer(
115 - builder: (_) => buildIoniaTile(
116 - context,
117 - title: S.of(context).amount,
118 - subTitle: viewModel.remainingAmount.toStringAsFixed(2),
119 - )),
120 - Divider(height: 50),
121 - TextIconButton(
122 - label: S.of(context).how_to_use_card,
123 - onTap: () => _showHowToUseCard(context, viewModel.giftCard),
124 - ),
125 - ],
126 - ),
127 - bottomSection: Padding(
128 - padding: EdgeInsets.only(bottom: 12),
129 - child: Observer(
130 - builder: (_) {
131 - if (!viewModel.giftCard.isEmpty) {
132 - return Column(
133 - children: [
134 - PrimaryButton(
135 - onPressed: () async {
136 - await Navigator.of(context).pushNamed(
137 - Routes.ioniaMoreOptionsPage,
138 - arguments: [viewModel.giftCard]) as String?;
139 - viewModel.refeshCard();
140 - },
141 - text: S.of(context).more_options,
142 - color: Theme.of(context).cardColor,
143 - textColor: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
144 - ),
145 - SizedBox(height: 12),
146 - LoadingPrimaryButton(
147 - isLoading: viewModel.redeemState is IsExecutingState,
148 - onPressed: () => viewModel.redeem().then(
149 - (_) {
150 - Navigator.of(context).pushNamedAndRemoveUntil(
151 - Routes.ioniaManageCardsPage, (route) => route.isFirst);
152 - },
153 - ),
154 - text: S.of(context).mark_as_redeemed,
155 - color: Theme.of(context).primaryColor,
156 - textColor: Colors.white,
157 - ),
158 - ],
159 - );
160 - }
161 -
162 - return Container();
163 - },
164 - ),
165 - ),
166 - );
167 - }
168 -
169 - Widget buildIoniaTile(BuildContext context, {required String title, required String subTitle}) {
170 - return IoniaTile(
171 - title: title,
172 - subTitle: subTitle,
173 - onTap: () {
174 - Clipboard.setData(ClipboardData(text: subTitle));
175 - showBar<void>(context, S.of(context).transaction_details_copied(title));
176 - });
177 - }
178 -
179 - void _showHowToUseCard(
180 - BuildContext context,
181 - IoniaGiftCard merchant,
182 - ) {
183 - showPopUp<void>(
184 - context: context,
185 - builder: (BuildContext context) {
186 - return IoniaAlertModal(
187 - title: S.of(context).how_to_use_card,
188 - content: Column(
189 - crossAxisAlignment: CrossAxisAlignment.start,
190 - children: viewModel.giftCard.instructions
191 - .map((instruction) {
192 - return [
193 - Padding(
194 - padding: EdgeInsets.all(10),
195 - child: Text(
196 - instruction.header,
197 - style: textLargeSemiBold(
198 - color: Theme.of(context).extension<ReceivePageTheme>()!.tilesTextColor,
199 - ),
200 - )),
201 - Text(
202 - instruction.body,
203 - style: textMedium(
204 - color: Theme.of(context).extension<ReceivePageTheme>()!.tilesTextColor,
205 - ),
206 - )
207 - ];
208 - })
209 - .expand((e) => e)
210 - .toList()),
211 - actionTitle: S.of(context).got_it,
212 - );
213 - });
214 - }
215 -}
lib/src/screens/ionia/cards/ionia_more_options_page.dart deleted
-91
@@ -1,91 +0,0 @@
1 -import 'package:cake_wallet/ionia/ionia_gift_card.dart';
2 -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
3 -import 'package:cake_wallet/routes.dart';
4 -import 'package:cake_wallet/src/screens/base_page.dart';
5 -import 'package:cake_wallet/generated/i18n.dart';
6 -import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
7 -import 'package:cake_wallet/typography.dart';
8 -import 'package:flutter/material.dart';
9 -
10 -class IoniaMoreOptionsPage extends BasePage {
11 - IoniaMoreOptionsPage(this.giftCard);
12 -
13 - final IoniaGiftCard giftCard;
14 -
15 - @override
16 - Widget middle(BuildContext context) {
17 - return Text(
18 - S.current.more_options,
19 - style: textMediumSemiBold(
20 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
21 - ),
22 - );
23 - }
24 -
25 - @override
26 - Widget body(BuildContext context) {
27 - return Padding(
28 - padding: const EdgeInsets.all(16.0),
29 - child: Column(
30 - crossAxisAlignment: CrossAxisAlignment.stretch,
31 - children: [
32 - SizedBox(
33 - height: 10,
34 - ),
35 - Center(
36 - child: Text(
37 - S.of(context).choose_from_available_options,
38 - style: textMedium(
39 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
40 - ),
41 - ),
42 - ),
43 - SizedBox(height: 40),
44 - InkWell(
45 - onTap: () async {
46 - final amount = await Navigator.of(context)
47 - .pushNamed(Routes.ioniaCustomRedeemPage, arguments: [giftCard]) as String?;
48 - if (amount != null && amount.isNotEmpty) {
49 - Navigator.pop(context);
50 - }
51 - },
52 - child: _GradiantContainer(
53 - content: Padding(
54 - padding: const EdgeInsets.only(top: 24, left: 20, right: 24, bottom: 50),
55 - child: Text(
56 - S.of(context).custom_redeem_amount,
57 - style: textXLargeSemiBold(),
58 - ),
59 - ),
60 - ),
61 - )
62 - ],
63 - ),
64 - );
65 - }
66 -}
67 -
68 -class _GradiantContainer extends StatelessWidget {
69 - const _GradiantContainer({Key? key, required this.content}) : super(key: key);
70 -
71 - final Widget content;
72 -
73 - @override
74 - Widget build(BuildContext context) {
75 - return Container(
76 - child: content,
77 - padding: EdgeInsets.all(24),
78 - decoration: BoxDecoration(
79 - borderRadius: BorderRadius.circular(15),
80 - gradient: LinearGradient(
81 - colors: [
82 - Theme.of(context).extension<DashboardPageTheme>()!.secondGradientBackgroundColor,
83 - Theme.of(context).extension<DashboardPageTheme>()!.firstGradientBackgroundColor,
84 - ],
85 - begin: Alignment.topRight,
86 - end: Alignment.bottomLeft,
87 - ),
88 - ),
89 - );
90 - }
91 -}
lib/src/screens/ionia/cards/ionia_payment_status_page.dart deleted
-222
@@ -1,222 +0,0 @@
1 -import 'package:cake_wallet/ionia/ionia_gift_card.dart';
2 -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
3 -import 'package:cake_wallet/routes.dart';
4 -import 'package:cake_wallet/src/screens/base_page.dart';
5 -import 'package:cake_wallet/src/widgets/primary_button.dart';
6 -import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
7 -import 'package:cake_wallet/typography.dart';
8 -import 'package:cake_wallet/utils/show_bar.dart';
9 -import 'package:cake_wallet/view_model/ionia/ionia_payment_status_view_model.dart';
10 -import 'package:flutter/material.dart';
11 -import 'package:cake_wallet/generated/i18n.dart';
12 -import 'package:flutter/services.dart';
13 -import 'package:flutter_mobx/flutter_mobx.dart';
14 -import 'package:mobx/mobx.dart';
15 -import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
16 -
17 -class IoniaPaymentStatusPage extends BasePage {
18 - IoniaPaymentStatusPage(this.viewModel);
19 -
20 - final IoniaPaymentStatusViewModel viewModel;
21 -
22 - @override
23 - Widget middle(BuildContext context) {
24 - return Text(
25 - S.of(context).generating_gift_card,
26 - textAlign: TextAlign.center,
27 - style: textMediumSemiBold(
28 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor));
29 - }
30 -
31 - @override
32 - Widget body(BuildContext context) {
33 - return _IoniaPaymentStatusPageBody(viewModel);
34 - }
35 -}
36 -
37 -class _IoniaPaymentStatusPageBody extends StatefulWidget {
38 - _IoniaPaymentStatusPageBody(this.viewModel);
39 -
40 - final IoniaPaymentStatusViewModel viewModel;
41 -
42 - @override
43 - _IoniaPaymentStatusPageBodyBodyState createState() => _IoniaPaymentStatusPageBodyBodyState();
44 -}
45 -
46 -class _IoniaPaymentStatusPageBodyBodyState extends State<_IoniaPaymentStatusPageBody> {
47 - ReactionDisposer? _onGiftCardReaction;
48 -
49 - @override
50 - void initState() {
51 - if (widget.viewModel.giftCard != null) {
52 - WidgetsBinding.instance.addPostFrameCallback((_) {
53 - Navigator.of(context)
54 - .pushReplacementNamed(Routes.ioniaGiftCardDetailPage, arguments: [widget.viewModel.giftCard]);
55 - });
56 - }
57 -
58 - _onGiftCardReaction = reaction((_) => widget.viewModel.giftCard, (IoniaGiftCard? giftCard) {
59 - WidgetsBinding.instance.addPostFrameCallback((_) {
60 - Navigator.of(context)
61 - .pushReplacementNamed(Routes.ioniaGiftCardDetailPage, arguments: [giftCard]);
62 - });
63 - });
64 -
65 - super.initState();
66 - }
67 -
68 - @override
69 - void dispose() {
70 - _onGiftCardReaction?.reaction.dispose();
71 - widget.viewModel.timer?.cancel();
72 - super.dispose();
73 - }
74 -
75 - @override
76 - Widget build(BuildContext context) {
77 - return ScrollableWithBottomSection(
78 - contentPadding: EdgeInsets.all(24),
79 - content: Column(
80 - crossAxisAlignment: CrossAxisAlignment.start,
81 - mainAxisAlignment: MainAxisAlignment.start,
82 - children: [
83 - Row(children: [
84 - Padding(
85 - padding: EdgeInsets.only(right: 10),
86 - child: Container(
87 - decoration: BoxDecoration(
88 - borderRadius: BorderRadius.circular(10),
89 - color: Colors.green),
90 - height: 10,
91 - width: 10)),
92 - Text(
93 - S.of(context).awaiting_payment_confirmation,
94 - style: textLargeSemiBold(
95 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor))
96 - ]),
97 - SizedBox(height: 40),
98 - Row(children: [
99 - SizedBox(width: 20),
100 - Expanded(child:
101 - Column(
102 - crossAxisAlignment: CrossAxisAlignment.start,
103 - mainAxisAlignment: MainAxisAlignment.start,
104 - children: [
105 - ...widget.viewModel
106 - .committedInfo
107 - .transactions
108 - .map((transaction) => buildDescriptionTileWithCopy(context, S.of(context).transaction_details_transaction_id, transaction.id)),
109 - if (widget.viewModel.paymentInfo.ioniaOrder.id != null)
110 - ...[Divider(height: 30),
111 - buildDescriptionTileWithCopy(context, S.of(context).order_id, widget.viewModel.paymentInfo.ioniaOrder.id)],
112 - if (widget.viewModel.paymentInfo.ioniaOrder.paymentId != null)
113 - ...[Divider(height: 30),
114 - buildDescriptionTileWithCopy(context, S.of(context).payment_id, widget.viewModel.paymentInfo.ioniaOrder.paymentId)],
115 - ]))
116 - ]),
117 - SizedBox(height: 40),
118 - Observer(builder: (_) {
119 - if (widget.viewModel.giftCard != null) {
120 - return Container(
121 - padding: EdgeInsets.only(top: 40),
122 - child: Row(children: [
123 - Padding(
124 - padding: EdgeInsets.only(right: 10,),
125 - child: Container(
126 - decoration: BoxDecoration(
127 - borderRadius: BorderRadius.circular(10),
128 - color: Colors.green),
129 - height: 10,
130 - width: 10)),
131 - Text(
132 - S.of(context).gift_card_is_generated,
133 - style: textLargeSemiBold(
134 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor))
135 - ]));
136 - }
137 -
138 - return Row(children: [
139 - Padding(
140 - padding: EdgeInsets.only(right: 10),
141 - child: Observer(builder: (_) {
142 - return Container(
143 - decoration: BoxDecoration(
144 - borderRadius: BorderRadius.circular(10),
145 - color: widget.viewModel.giftCard == null ? Colors.grey : Colors.green),
146 - height: 10,
147 - width: 10);
148 - })),
149 - Text(
150 - S.of(context).generating_gift_card,
151 - style: textLargeSemiBold(
152 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor))]);
153 - }),
154 - ],
155 - ),
156 - bottomSection: Padding(
157 - padding: EdgeInsets.only(bottom: 12),
158 - child: Column(children: [
159 - Container(
160 - padding: EdgeInsets.only(left: 40, right: 40, bottom: 20),
161 - child: Text(
162 - widget.viewModel.payingByBitcoin ? S.of(context).bitcoin_payments_require_1_confirmation
163 - : S.of(context).proceed_after_one_minute,
164 - style: textMedium(
165 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
166 - ).copyWith(fontWeight: FontWeight.w500),
167 - textAlign: TextAlign.center,
168 - )),
169 - Observer(builder: (_) {
170 - if (widget.viewModel.giftCard != null) {
171 - return PrimaryButton(
172 - onPressed: () => Navigator.of(context)
173 - .pushReplacementNamed(
174 - Routes.ioniaGiftCardDetailPage,
175 - arguments: [widget.viewModel.giftCard]),
176 - text: S.of(context).open_gift_card,
177 - color: Theme.of(context).primaryColor,
178 - textColor: Colors.white);
179 - }
180 -
181 - return PrimaryButton(
182 - onPressed: () => Navigator.of(context).pushNamed(Routes.support),
183 - text: S.of(context).contact_support,
184 - color: Theme.of(context).cardColor,
185 - textColor: Theme.of(context).extension<CakeTextTheme>()!.titleColor);
186 - })
187 - ])
188 - ),
189 - );
190 - }
191 -
192 - Widget buildDescriptionTile(BuildContext context, String title, String subtitle, VoidCallback onTap) {
193 - return GestureDetector(
194 - onTap: () => onTap(),
195 - child: Column(
196 - crossAxisAlignment: CrossAxisAlignment.start,
197 - children: [
198 - Text(
199 - title,
200 - style: textXSmall(
201 - color: Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor,
202 - ),
203 - ),
204 - SizedBox(height: 8),
205 - Text(
206 - subtitle,
207 - style: textMedium(
208 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
209 - ),
210 - ),
211 - ],
212 - ));
213 - }
214 -
215 - Widget buildDescriptionTileWithCopy(BuildContext context, String title, String subtitle) {
216 - return buildDescriptionTile(context, title, subtitle, () {
217 - Clipboard.setData(ClipboardData(text: subtitle));
218 - showBar<void>(context,
219 - S.of(context).transaction_details_copied(title));
220 - });
221 - }
222 -}
\ No newline at end of file
lib/src/screens/ionia/ionia.dart deleted
-9
@@ -1,9 +0,0 @@
1 -export 'auth/ionia_welcome_page.dart';
2 -export 'auth/ionia_create_account_page.dart';
3 -export 'auth/ionia_login_page.dart';
4 -export 'auth/ionia_verify_otp_page.dart';
5 -export 'cards/ionia_activate_debit_card_page.dart';
6 -export 'cards/ionia_buy_card_detail_page.dart';
7 -export 'cards/ionia_manage_cards_page.dart';
8 -export 'cards/ionia_debit_card_page.dart';
9 -export 'cards/ionia_buy_gift_card.dart';
lib/src/screens/ionia/widgets/card_item.dart deleted
-144
@@ -1,144 +0,0 @@
1 -import 'package:cake_wallet/src/widgets/discount_badge.dart';
2 -import 'package:flutter/material.dart';
3 -
4 -class CardItem extends StatelessWidget {
5 - CardItem({
6 - required this.title,
7 - required this.subTitle,
8 - required this.backgroundColor,
9 - required this.titleColor,
10 - required this.subtitleColor,
11 - this.hideBorder = false,
12 - this.discount = 0.0,
13 - this.isAmount = false,
14 - this.discountBackground,
15 - this.onTap,
16 - this.logoUrl,
17 - });
18 -
19 - final VoidCallback? onTap;
20 - final String title;
21 - final String subTitle;
22 - final String? logoUrl;
23 - final double discount;
24 - final bool isAmount;
25 - final bool hideBorder;
26 - final Color backgroundColor;
27 - final Color titleColor;
28 - final Color subtitleColor;
29 - final AssetImage? discountBackground;
30 -
31 - @override
32 - Widget build(BuildContext context) {
33 - return InkWell(
34 - onTap: onTap,
35 - child: Stack(
36 - children: [
37 - Container(
38 - padding: EdgeInsets.all(12),
39 - width: double.infinity,
40 - decoration: BoxDecoration(
41 - color: backgroundColor,
42 - borderRadius: BorderRadius.circular(20),
43 - border: hideBorder ? Border.symmetric(horizontal: BorderSide.none, vertical: BorderSide.none) : Border.all(
44 - color: Colors.white.withOpacity(0.20),
45 - ),
46 - ),
47 - child: Row(
48 - children: [
49 - if (logoUrl != null) ...[
50 - ClipOval(
51 - child: Image.network(
52 - logoUrl!,
53 - width: 40.0,
54 - height: 40.0,
55 - fit: BoxFit.cover,
56 - loadingBuilder: (BuildContext _, Widget child, ImageChunkEvent? loadingProgress) {
57 - if (loadingProgress == null) {
58 - return child;
59 - } else {
60 - return _PlaceholderContainer(text: 'Logo');
61 - }
62 - },
63 - errorBuilder: (_, __, ___) => _PlaceholderContainer(text: '!'),
64 - ),
65 - ),
66 - SizedBox(width: 5),
67 - ],
68 - Column(
69 - crossAxisAlignment: (subTitle?.isEmpty ?? false)
70 - ? CrossAxisAlignment.center
71 - : CrossAxisAlignment.start,
72 - children: [
73 - SizedBox(
74 - width: 200,
75 - child: Text(
76 - title,
77 - overflow: TextOverflow.ellipsis,
78 - style: TextStyle(
79 - color: titleColor,
80 - fontSize: 20,
81 - fontWeight: FontWeight.w900,
82 - ),
83 - ),
84 - ),
85 - if (subTitle?.isNotEmpty ?? false)
86 - Padding(
87 - padding: EdgeInsets.only(top: 5),
88 - child: Text(
89 - subTitle,
90 - style: TextStyle(
91 - color: subtitleColor,
92 - fontWeight: FontWeight.w500,
93 - fontFamily: 'Lato')),
94 - )
95 - ],
96 - ),
97 - ],
98 - ),
99 - ),
100 - if (discount != 0.0)
101 - Align(
102 - alignment: Alignment.topRight,
103 - child: Padding(
104 - padding: const EdgeInsets.only(top: 20.0),
105 - child: DiscountBadge(
106 - percentage: discount,
107 - isAmount: isAmount,
108 - discountBackground: discountBackground,
109 - ),
110 - ),
111 - ),
112 - ],
113 - ),
114 - );
115 - }
116 -}
117 -
118 -class _PlaceholderContainer extends StatelessWidget {
119 - const _PlaceholderContainer({required this.text});
120 -
121 - final String text;
122 -
123 - @override
124 - Widget build(BuildContext context) {
125 - return Container(
126 - height: 42,
127 - width: 42,
128 - child: Center(
129 - child: Text(
130 - text,
131 - style: TextStyle(
132 - color: Colors.black,
133 - fontSize: 12,
134 - fontWeight: FontWeight.w900,
135 - ),
136 - ),
137 - ),
138 - decoration: BoxDecoration(
139 - color: Colors.white,
140 - borderRadius: BorderRadius.circular(100),
141 - ),
142 - );
143 - }
144 -}
lib/src/screens/ionia/widgets/ionia_filter_modal.dart deleted
-132
@@ -1,132 +0,0 @@
1 -import 'package:cake_wallet/src/screens/ionia/widgets/rounded_checkbox.dart';
2 -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
3 -import 'package:cake_wallet/src/widgets/alert_background.dart';
4 -import 'package:cake_wallet/typography.dart';
5 -import 'package:cake_wallet/generated/i18n.dart';
6 -import 'package:cake_wallet/view_model/ionia/ionia_gift_cards_list_view_model.dart';
7 -import 'package:flutter/material.dart';
8 -import 'package:flutter_mobx/flutter_mobx.dart';
9 -import 'package:cake_wallet/palette.dart';
10 -import 'package:cake_wallet/themes/extensions/menu_theme.dart';
11 -
12 -class IoniaFilterModal extends StatelessWidget {
13 - IoniaFilterModal({required this.ioniaGiftCardsListViewModel}){
14 - ioniaGiftCardsListViewModel.resetIoniaCategories();
15 - }
16 -
17 - final IoniaGiftCardsListViewModel ioniaGiftCardsListViewModel;
18 -
19 - @override
20 - Widget build(BuildContext context) {
21 - final searchIcon = Padding(
22 - padding: EdgeInsets.all(10),
23 - child: Image.asset(
24 - 'assets/images/mini_search_icon.png',
25 - color: Theme.of(context).primaryColor,
26 - ),
27 - );
28 - return Scaffold(
29 - resizeToAvoidBottomInset: false,
30 - body: AlertBackground(
31 - child: Column(
32 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
33 - children: [
34 - SizedBox(height: 10),
35 - Container(
36 - padding: EdgeInsets.only(top: 24, bottom: 20),
37 - margin: EdgeInsets.all(24),
38 - decoration: BoxDecoration(
39 - color: Theme.of(context).colorScheme.background,
40 - borderRadius: BorderRadius.circular(30),
41 - ),
42 - child: Column(
43 - children: [
44 - SizedBox(
45 - height: 40,
46 - child: Padding(
47 - padding: const EdgeInsets.only(left: 24, right: 24),
48 - child: TextField(
49 - onChanged: ioniaGiftCardsListViewModel.onSearchFilter,
50 - style: textMedium(
51 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
52 - ),
53 - decoration: InputDecoration(
54 - filled: true,
55 - prefixIcon: searchIcon,
56 - hintText: S.of(context).search_category,
57 - contentPadding: EdgeInsets.only(bottom: 5),
58 - fillColor: Theme.of(context).extension<CakeMenuTheme>()!.dividerColor.withOpacity(0.5),
59 - border: OutlineInputBorder(
60 - borderSide: BorderSide.none,
61 - borderRadius: BorderRadius.circular(8),
62 - ),
63 - ),
64 - ),
65 - ),
66 - ),
67 - SizedBox(height: 10),
68 - Divider(thickness: 2),
69 - SizedBox(height: 24),
70 - Observer(builder: (_) {
71 - return ListView.builder(
72 - padding: EdgeInsets.zero,
73 - shrinkWrap: true,
74 - itemCount: ioniaGiftCardsListViewModel.ioniaCategories.length,
75 - itemBuilder: (_, index) {
76 - final category = ioniaGiftCardsListViewModel.ioniaCategories[index];
77 - return Padding(
78 - padding: const EdgeInsets.only(left: 24, right: 24, bottom: 24),
79 - child: InkWell(
80 - onTap: () => ioniaGiftCardsListViewModel.setSelectedFilter(category),
81 - child: Row(
82 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
83 - children: [
84 - Row(
85 - mainAxisSize: MainAxisSize.min,
86 - children: [
87 - Image.asset(
88 - category.iconPath,
89 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
90 - ),
91 - SizedBox(width: 10),
92 - Text(category.title,
93 - style: textSmall(
94 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
95 - ).copyWith(fontWeight: FontWeight.w500)),
96 - ],
97 - ),
98 - Observer(builder: (_) {
99 - final value = ioniaGiftCardsListViewModel.selectedIndices;
100 - return RoundedCheckbox(
101 - value: value.contains(category),
102 - );
103 - }),
104 - ],
105 - ),
106 - ),
107 - );
108 - },
109 - );
110 - }),
111 - ],
112 - ),
113 - ),
114 - InkWell(
115 - onTap: () => Navigator.pop(context),
116 - child: Container(
117 - margin: EdgeInsets.only(bottom: 40),
118 - child: CircleAvatar(
119 - child: Icon(
120 - Icons.close,
121 - color: Palette.darkBlueCraiola,
122 - ),
123 - backgroundColor: Colors.white,
124 - ),
125 - ),
126 - )
127 - ],
128 - ),
129 - ),
130 - );
131 - }
132 -}
lib/src/screens/send/widgets/confirm_sending_alert.dart
+84 -13
@@ -12,6 +12,7 @@ class ConfirmSendingAlert extends BaseAlertDialog {
12 {required this.alertTitle,
13 this.paymentId,
14 this.paymentIdValue,
15 + this.expirationTime,
16 required this.amount,
17 required this.amountValue,
18 required this.fiatAmountValue,
@@ -28,11 +29,13 @@ class ConfirmSendingAlert extends BaseAlertDialog {
29 this.alertLeftActionButtonTextColor,
30 this.alertRightActionButtonTextColor,
31 this.alertLeftActionButtonColor,
31 - this.alertRightActionButtonColor});
32 + this.alertRightActionButtonColor,
33 + this.onDispose});
34
35 final String alertTitle;
36 final String? paymentId;
37 final String? paymentIdValue;
38 + final String? expirationTime;
39 final String amount;
40 final String amountValue;
41 final String fiatAmountValue;
@@ -50,6 +53,7 @@ class ConfirmSendingAlert extends BaseAlertDialog {
53 final Color? alertRightActionButtonTextColor;
54 final Color? alertLeftActionButtonColor;
55 final Color? alertRightActionButtonColor;
56 + final Function? onDispose;
57
58 @override
59 String get titleText => alertTitle;
@@ -88,6 +92,7 @@ class ConfirmSendingAlert extends BaseAlertDialog {
92 Widget content(BuildContext context) => ConfirmSendingAlertContent(
93 paymentId: paymentId,
94 paymentIdValue: paymentIdValue,
95 + expirationTime: expirationTime,
96 amount: amount,
97 amountValue: amountValue,
98 fiatAmountValue: fiatAmountValue,
@@ -95,13 +100,15 @@ class ConfirmSendingAlert extends BaseAlertDialog {
100 feeRate: feeRate,
101 feeValue: feeValue,
102 feeFiatAmount: feeFiatAmount,
98 - outputs: outputs);
103 + outputs: outputs,
104 + onDispose: onDispose);
105 }
106
107 class ConfirmSendingAlertContent extends StatefulWidget {
108 ConfirmSendingAlertContent(
109 {this.paymentId,
110 this.paymentIdValue,
111 + this.expirationTime,
112 required this.amount,
113 required this.amountValue,
114 required this.fiatAmountValue,
@@ -109,10 +116,12 @@ class ConfirmSendingAlertContent extends StatefulWidget {
116 this.feeRate,
117 required this.feeValue,
118 required this.feeFiatAmount,
112 - required this.outputs});
119 + required this.outputs,
120 + required this.onDispose}) {}
121
122 final String? paymentId;
123 final String? paymentIdValue;
124 + final String? expirationTime;
125 final String amount;
126 final String amountValue;
127 final String fiatAmountValue;
@@ -121,11 +130,13 @@ class ConfirmSendingAlertContent extends StatefulWidget {
130 final String feeValue;
131 final String feeFiatAmount;
132 final List<Output> outputs;
133 + final Function? onDispose;
134
135 @override
136 ConfirmSendingAlertContentState createState() => ConfirmSendingAlertContentState(
137 paymentId: paymentId,
138 paymentIdValue: paymentIdValue,
139 + expirationTime: expirationTime,
140 amount: amount,
141 amountValue: amountValue,
142 fiatAmountValue: fiatAmountValue,
@@ -133,13 +144,15 @@ class ConfirmSendingAlertContent extends StatefulWidget {
144 feeRate: feeRate,
145 feeValue: feeValue,
146 feeFiatAmount: feeFiatAmount,
136 - outputs: outputs);
147 + outputs: outputs,
148 + onDispose: onDispose);
149 }
150
151 class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent> {
152 ConfirmSendingAlertContentState(
153 {this.paymentId,
154 this.paymentIdValue,
155 + this.expirationTime,
156 required this.amount,
157 required this.amountValue,
158 required this.fiatAmountValue,
@@ -147,7 +160,8 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
160 this.feeRate,
161 required this.feeValue,
162 required this.feeFiatAmount,
150 - required this.outputs})
163 + required this.outputs,
164 + this.onDispose})
165 : recipientTitle = '' {
166 recipientTitle = outputs.length > 1
167 ? S.current.transaction_details_recipient_address
@@ -156,6 +170,7 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
170
171 final String? paymentId;
172 final String? paymentIdValue;
173 + final String? expirationTime;
174 final String amount;
175 final String amountValue;
176 final String fiatAmountValue;
@@ -164,6 +179,7 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
179 final String feeValue;
180 final String feeFiatAmount;
181 final List<Output> outputs;
182 + final Function? onDispose;
183
184 final double backgroundHeight = 160;
185 final double thumbHeight = 72;
@@ -172,6 +188,12 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
188 String recipientTitle;
189 bool showScrollbar = false;
190
191 + @override
192 + void dispose() {
193 + if (onDispose != null) onDispose!();
194 + super.dispose();
195 + }
196 +
197 @override
198 Widget build(BuildContext context) {
199 controller.addListener(() {
@@ -217,14 +239,18 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
239 Column(
240 crossAxisAlignment: CrossAxisAlignment.end,
241 children: [
220 - Text(
221 - paymentIdValue!,
222 - style: TextStyle(
223 - fontSize: 18,
224 - fontWeight: FontWeight.w600,
225 - fontFamily: 'Lato',
226 - color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
227 - decoration: TextDecoration.none,
242 + Container(
243 + width: 160,
244 + child: Text(
245 + paymentIdValue!,
246 + textAlign: TextAlign.right,
247 + style: TextStyle(
248 + fontSize: 16,
249 + fontWeight: FontWeight.w600,
250 + fontFamily: 'Lato',
251 + color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
252 + decoration: TextDecoration.none,
253 + ),
254 ),
255 ),
256 ],
@@ -232,6 +258,8 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
258 ],
259 ),
260 ),
261 + if (widget.expirationTime != null)
262 + ExpirationTimeWidget(expirationTime: widget.expirationTime!),
263 Row(
264 mainAxisSize: MainAxisSize.max,
265 mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -468,3 +496,46 @@ class ConfirmSendingAlertContentState extends State<ConfirmSendingAlertContent>
496 ]);
497 }
498 }
499 +
500 +class ExpirationTimeWidget extends StatelessWidget {
501 + const ExpirationTimeWidget({
502 + required this.expirationTime,
503 + });
504 +
505 + final String expirationTime;
506 +
507 + @override
508 + Widget build(BuildContext context) {
509 + return Padding(
510 + padding: EdgeInsets.only(bottom: 32),
511 + child: Row(
512 + mainAxisSize: MainAxisSize.max,
513 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
514 + crossAxisAlignment: CrossAxisAlignment.start,
515 + children: <Widget>[
516 + Text(
517 + S.current.offer_expires_in,
518 + style: TextStyle(
519 + fontSize: 16,
520 + fontWeight: FontWeight.normal,
521 + fontFamily: 'Lato',
522 + color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
523 + decoration: TextDecoration.none,
524 + ),
525 + ),
526 + Text(
527 + expirationTime,
528 + textAlign: TextAlign.right,
529 + style: TextStyle(
530 + fontSize: 16,
531 + fontWeight: FontWeight.w600,
532 + fontFamily: 'Lato',
533 + color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
534 + decoration: TextDecoration.none,
535 + ),
536 + )
537 + ],
538 + ),
539 + );
540 + }
541 +}
lib/src/widgets/number_text_fild_widget.dart new
+145
@@ -0,0 +1,145 @@
1 +import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
2 +import 'package:cake_wallet/typography.dart';
3 +import 'package:flutter/material.dart';
4 +import 'package:flutter/services.dart';
5 +
6 +class NumberTextField extends StatefulWidget {
7 + final TextEditingController? controller;
8 + final FocusNode? focusNode;
9 + final int min;
10 + final int max;
11 + final int step;
12 + final double arrowsWidth;
13 + final double arrowsHeight;
14 + final EdgeInsets contentPadding;
15 + final double borderWidth;
16 + final ValueChanged<int?>? onChanged;
17 +
18 + const NumberTextField({
19 + Key? key,
20 + this.controller,
21 + this.focusNode,
22 + this.min = 0,
23 + this.max = 999,
24 + this.step = 1,
25 + this.arrowsWidth = 24,
26 + this.arrowsHeight = kMinInteractiveDimension,
27 + this.contentPadding = const EdgeInsets.symmetric(horizontal: 8),
28 + this.borderWidth = 2,
29 + this.onChanged,
30 + }) : super(key: key);
31 +
32 + @override
33 + State<StatefulWidget> createState() => _NumberTextFieldState();
34 +}
35 +
36 +class _NumberTextFieldState extends State<NumberTextField> {
37 + late TextEditingController _controller;
38 + late FocusNode _focusNode;
39 + bool _canGoUp = false;
40 + bool _canGoDown = false;
41 +
42 + @override
43 + void initState() {
44 + super.initState();
45 + _controller = widget.controller ?? TextEditingController();
46 + _focusNode = widget.focusNode ?? FocusNode();
47 + _updateArrows(int.tryParse(_controller.text));
48 + }
49 +
50 + @override
51 + void didUpdateWidget(covariant NumberTextField oldWidget) {
52 + super.didUpdateWidget(oldWidget);
53 + _controller = widget.controller ?? _controller;
54 + _focusNode = widget.focusNode ?? _focusNode;
55 + _updateArrows(int.tryParse(_controller.text));
56 + }
57 +
58 + @override
59 + Widget build(BuildContext context) => TextField(
60 + style: textMediumSemiBold(color: Theme.of(context).extension<CakeTextTheme>()!.titleColor),
61 + enableInteractiveSelection: false,
62 + textAlign: TextAlign.center,
63 + textAlignVertical: TextAlignVertical.bottom,
64 + controller: _controller,
65 + focusNode: _focusNode,
66 + textInputAction: TextInputAction.done,
67 + keyboardType: TextInputType.number,
68 + maxLength: widget.max.toString().length + (widget.min.isNegative ? 1 : 0),
69 + decoration: InputDecoration(
70 + border: InputBorder.none,
71 + contentPadding: EdgeInsets.all(0),
72 + fillColor: Colors.transparent,
73 + counterText: '',
74 + isDense: true,
75 + filled: true,
76 + suffixIconConstraints: BoxConstraints(
77 + maxHeight: widget.arrowsHeight,
78 + maxWidth: widget.arrowsWidth + widget.contentPadding.right),
79 + prefixIconConstraints: BoxConstraints(
80 + maxHeight: widget.arrowsHeight,
81 + maxWidth: widget.arrowsWidth + widget.contentPadding.left),
82 + prefixIcon: Material(
83 + type: MaterialType.transparency,
84 + child: InkWell(
85 + child: Container(
86 + width: widget.arrowsWidth,
87 + alignment: Alignment.bottomCenter,
88 + child: Icon(Icons.arrow_left_outlined, size: widget.arrowsWidth)),
89 + onTap: _canGoDown ? () => _update(false) : null)),
90 + suffixIcon: Material(
91 + type: MaterialType.transparency,
92 + child: InkWell(
93 + child: Container(
94 + width: widget.arrowsWidth,
95 + alignment: Alignment.bottomCenter,
96 + child: Icon(Icons.arrow_right_outlined, size: widget.arrowsWidth)),
97 + onTap: _canGoUp ? () => _update(true) : null))),
98 + maxLines: 1,
99 + onChanged: (value) {
100 + final intValue = int.tryParse(value);
101 + widget.onChanged?.call(intValue);
102 + _updateArrows(intValue);
103 + },
104 + inputFormatters: [_NumberTextInputFormatter(widget.min, widget.max)]);
105 +
106 + void _update(bool up) {
107 + var intValue = int.tryParse(_controller.text);
108 + intValue == null ? intValue = widget.min : intValue += up ? widget.step : -widget.step;
109 + intValue = intValue.clamp(widget.min, widget.max); // Ensure intValue is within range
110 + _controller.text = intValue.toString();
111 +
112 + // Manually call the onChanged callback after updating the controller's text
113 + widget.onChanged?.call(intValue);
114 +
115 + _updateArrows(intValue);
116 + _focusNode.requestFocus();
117 + }
118 +
119 + void _updateArrows(int? value) {
120 + final canGoUp = value == null || value < widget.max;
121 + final canGoDown = value == null || value > widget.min;
122 + if (_canGoUp != canGoUp || _canGoDown != canGoDown)
123 + setState(() {
124 + _canGoUp = canGoUp;
125 + _canGoDown = canGoDown;
126 + });
127 + }
128 +}
129 +
130 +class _NumberTextInputFormatter extends TextInputFormatter {
131 + final int min;
132 + final int max;
133 +
134 + _NumberTextInputFormatter(this.min, this.max);
135 +
136 + @override
137 + TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
138 + if (const ['-', ''].contains(newValue.text)) return newValue;
139 + final intValue = int.tryParse(newValue.text);
140 + if (intValue == null) return oldValue;
141 + if (intValue < min) return newValue.copyWith(text: min.toString());
142 + if (intValue > max) return newValue.copyWith(text: max.toString());
143 + return newValue.copyWith(text: intValue.toString());
144 + }
145 +}
lib/view_model/cake_pay/cake_pay_account_view_model.dart new
+20
@@ -0,0 +1,20 @@
1 +import 'package:cake_wallet/cake_pay/cake_pay_service.dart';
2 +import 'package:mobx/mobx.dart';
3 +
4 +part 'cake_pay_account_view_model.g.dart';
5 +
6 +class CakePayAccountViewModel = CakePayAccountViewModelBase with _$CakePayAccountViewModel;
7 +
8 +abstract class CakePayAccountViewModelBase with Store {
9 + CakePayAccountViewModelBase({required this.cakePayService}) : email = '' {
10 + cakePayService.getUserEmail().then((email) => this.email = email ?? '');
11 + }
12 +
13 + final CakePayService cakePayService;
14 +
15 + @observable
16 + String email;
17 +
18 + @action
19 + Future<void> logout() async => cakePayService.logout(email);
20 +}
lib/view_model/cake_pay/cake_pay_auth_view_model.dart new
+51
@@ -0,0 +1,51 @@
1 +import 'package:cake_wallet/cake_pay/cake_pay_states.dart';
2 +import 'package:cake_wallet/cake_pay/cake_pay_service.dart';
3 +import 'package:mobx/mobx.dart';
4 +
5 +part 'cake_pay_auth_view_model.g.dart';
6 +
7 +class CakePayAuthViewModel = CakePayAuthViewModelBase with _$CakePayAuthViewModel;
8 +
9 +abstract class CakePayAuthViewModelBase with Store {
10 + CakePayAuthViewModelBase({required this.cakePayService})
11 + : userVerificationState = CakePayUserVerificationStateInitial(),
12 + otpState = CakePayOtpSendDisabled(),
13 + email = '',
14 + otp = '';
15 +
16 + final CakePayService cakePayService;
17 +
18 + @observable
19 + CakePayUserVerificationState userVerificationState;
20 +
21 + @observable
22 + CakePayOtpState otpState;
23 +
24 + @observable
25 + String email;
26 +
27 + @observable
28 + String otp;
29 +
30 + @action
31 + Future<void> verifyEmail(String code) async {
32 + try {
33 + otpState = CakePayOtpValidating();
34 + await cakePayService.verifyEmail(code);
35 + otpState = CakePayOtpSuccess();
36 + } catch (_) {
37 + otpState = CakePayOtpFailure(error: 'Invalid OTP. Try again');
38 + }
39 + }
40 +
41 + @action
42 + Future<void> logIn(String email) async {
43 + try {
44 + userVerificationState = CakePayUserVerificationStateLoading();
45 + await cakePayService.logIn(email);
46 + userVerificationState = CakePayUserVerificationStateSuccess();
47 + } catch (e) {
48 + userVerificationState = CakePayUserVerificationStateFailure(error: e.toString());
49 + }
50 + }
51 +}
lib/view_model/cake_pay/cake_pay_buy_card_view_model.dart new
+48
@@ -0,0 +1,48 @@
1 +import 'package:cake_wallet/cake_pay/cake_pay_card.dart';
2 +import 'package:cake_wallet/cake_pay/cake_pay_vendor.dart';
3 +import 'package:mobx/mobx.dart';
4 +
5 +part 'cake_pay_buy_card_view_model.g.dart';
6 +
7 +class CakePayBuyCardViewModel = CakePayBuyCardViewModelBase with _$CakePayBuyCardViewModel;
8 +
9 +abstract class CakePayBuyCardViewModelBase with Store {
10 + CakePayBuyCardViewModelBase({required this.vendor})
11 + : amount = vendor.card!.denominations.isNotEmpty
12 + ? double.parse(vendor.card!.denominations.first)
13 + : 0,
14 + quantity = 1,
15 + min = double.parse(vendor.card!.minValue ?? '0'),
16 + max = double.parse(vendor.card!.maxValue ?? '0'),
17 + card = vendor.card!;
18 +
19 + final CakePayVendor vendor;
20 + final CakePayCard card;
21 +
22 + final double min;
23 + final double max;
24 +
25 + bool get isDenominationSelected => card.denominations.isNotEmpty;
26 +
27 + @observable
28 + double amount;
29 +
30 + @observable
31 + int quantity;
32 +
33 + @computed
34 + bool get isEnablePurchase =>
35 + (amount >= min && amount <= max) || (isDenominationSelected && quantity > 0);
36 +
37 + @computed
38 + double get totalAmount => amount * quantity;
39 +
40 + @action
41 + void onQuantityChanged(int? input) => quantity = input ?? 1;
42 +
43 + @action
44 + void onAmountChanged(String input) {
45 + if (input.isEmpty) return;
46 + amount = double.parse(input.replaceAll(',', '.'));
47 + }
48 +}
lib/view_model/cake_pay/cake_pay_cards_list_view_model.dart new
+221
@@ -0,0 +1,221 @@
1 +import 'package:cake_wallet/cake_pay/cake_pay_service.dart';
2 +import 'package:cake_wallet/cake_pay/cake_pay_states.dart';
3 +import 'package:cake_wallet/cake_pay/cake_pay_vendor.dart';
4 +import 'package:cake_wallet/generated/i18n.dart';
5 +import 'package:cake_wallet/view_model/dashboard/dropdown_filter_item.dart';
6 +import 'package:cake_wallet/view_model/dashboard/filter_item.dart';
7 +import 'package:mobx/mobx.dart';
8 +
9 +part 'cake_pay_cards_list_view_model.g.dart';
10 +
11 +class CakePayCardsListViewModel = CakePayCardsListViewModelBase with _$CakePayCardsListViewModel;
12 +
13 +abstract class CakePayCardsListViewModelBase with Store {
14 + CakePayCardsListViewModelBase({
15 + required this.cakePayService,
16 + }) : cardState = CakePayCardsStateNoCards(),
17 + cakePayVendors = [],
18 + availableCountries = [],
19 + page = 1,
20 + selectedCountry = 'USA',
21 + displayPrepaidCards = true,
22 + displayGiftCards = true,
23 + displayDenominationsCards = true,
24 + displayCustomValueCards = true,
25 + scrollOffsetFromTop = 0.0,
26 + vendorsState = InitialCakePayVendorLoadingState(),
27 + createCardState = CakePayCreateCardState(),
28 + searchString = '',
29 + CakePayVendorList = <CakePayVendor>[] {
30 + initialization();
31 + }
32 +
33 + void initialization() async {
34 + await getCountries();
35 + selectedCountry = availableCountries.first;
36 + getVendors();
37 + }
38 +
39 + final CakePayService cakePayService;
40 +
41 + List<CakePayVendor> CakePayVendorList;
42 +
43 + Map<String, List<FilterItem>> get createFilterItems => {
44 + S.current.filter_by: [
45 + FilterItem(
46 + value: () => displayPrepaidCards,
47 + caption: S.current.prepaid_cards,
48 + onChanged: togglePrepaidCards),
49 + FilterItem(
50 + value: () => displayGiftCards,
51 + caption: S.current.gift_cards,
52 + onChanged: toggleGiftCards),
53 + ],
54 + S.current.value_type: [
55 + FilterItem(
56 + value: () => displayDenominationsCards,
57 + caption: S.current.denominations,
58 + onChanged: toggleDenominationsCards),
59 + FilterItem(
60 + value: () => displayCustomValueCards,
61 + caption: S.current.custom_value,
62 + onChanged: toggleCustomValueCards),
63 + ],
64 + S.current.countries: [
65 + DropdownFilterItem(
66 + items: availableCountries,
67 + caption: '',
68 + selectedItem: selectedCountry,
69 + onItemSelected: (String value) => setSelectedCountry(value),
70 + ),
71 + ]
72 + };
73 +
74 + String searchString;
75 +
76 + int page;
77 +
78 + late String _initialSelectedCountry;
79 +
80 + late bool _initialDisplayPrepaidCards;
81 +
82 + late bool _initialDisplayGiftCards;
83 +
84 + late bool _initialDisplayDenominationsCards;
85 +
86 + late bool _initialDisplayCustomValueCards;
87 +
88 + @observable
89 + double scrollOffsetFromTop;
90 +
91 + @observable
92 + CakePayCreateCardState createCardState;
93 +
94 + @observable
95 + CakePayCardsState cardState;
96 +
97 + @observable
98 + CakePayVendorState vendorsState;
99 +
100 + @observable
101 + bool hasMoreDataToFetch = true;
102 +
103 + @observable
104 + bool isLoadingNextPage = false;
105 +
106 + @observable
107 + List<CakePayVendor> cakePayVendors;
108 +
109 + @observable
110 + List<String> availableCountries;
111 +
112 + @observable
113 + bool displayPrepaidCards;
114 +
115 + @observable
116 + bool displayGiftCards;
117 +
118 + @observable
119 + bool displayDenominationsCards;
120 +
121 + @observable
122 + bool displayCustomValueCards;
123 +
124 + @observable
125 + String selectedCountry;
126 +
127 + bool get hasFiltersChanged =>
128 + selectedCountry != _initialSelectedCountry ||
129 + displayPrepaidCards != _initialDisplayPrepaidCards ||
130 + displayGiftCards != _initialDisplayGiftCards ||
131 + displayDenominationsCards != _initialDisplayDenominationsCards ||
132 + displayCustomValueCards != _initialDisplayCustomValueCards;
133 +
134 + Future<void> getCountries() async {
135 + availableCountries = await cakePayService.getCountries();
136 + }
137 +
138 + @action
139 + Future<void> getVendors({
140 + String? text,
141 + int? currentPage,
142 + }) async {
143 + vendorsState = CakePayVendorLoadingState();
144 + searchString = text ?? '';
145 + var newVendors = await cakePayService.getVendors(
146 + country: selectedCountry,
147 + page: currentPage ?? page,
148 + search: searchString,
149 + giftCards: displayGiftCards,
150 + prepaidCards: displayPrepaidCards,
151 + custom: displayCustomValueCards,
152 + onDemand: displayDenominationsCards);
153 +
154 + cakePayVendors = CakePayVendorList = newVendors;
155 +
156 + vendorsState = CakePayVendorLoadedState();
157 + }
158 +
159 + @action
160 + Future<void> fetchNextPage() async {
161 + if (vendorsState is CakePayVendorLoadingState || !hasMoreDataToFetch || isLoadingNextPage)
162 + return;
163 +
164 + isLoadingNextPage = true;
165 + page++;
166 + try {
167 + var newVendors = await cakePayService.getVendors(
168 + country: selectedCountry,
169 + page: page,
170 + search: searchString,
171 + giftCards: displayGiftCards,
172 + prepaidCards: displayPrepaidCards,
173 + custom: displayCustomValueCards,
174 + onDemand: displayDenominationsCards);
175 +
176 + cakePayVendors.addAll(newVendors);
177 + } catch (error) {
178 + if (error.toString().contains('detail":"Invalid page."')) {
179 + hasMoreDataToFetch = false;
180 + }
181 + } finally {
182 + isLoadingNextPage = false;
183 + }
184 + }
185 +
186 + Future<bool> isCakePayUserAuthenticated() async {
187 + return await cakePayService.isLogged();
188 + }
189 +
190 + void resetLoadingNextPageState() {
191 + hasMoreDataToFetch = true;
192 + page = 1;
193 + }
194 +
195 + void storeInitialFilterStates() {
196 + _initialSelectedCountry = selectedCountry;
197 + _initialDisplayPrepaidCards = displayPrepaidCards;
198 + _initialDisplayGiftCards = displayGiftCards;
199 + _initialDisplayDenominationsCards = displayDenominationsCards;
200 + _initialDisplayCustomValueCards = displayCustomValueCards;
201 + }
202 +
203 + @action
204 + void setSelectedCountry(String country) => selectedCountry = country;
205 +
206 + @action
207 + void togglePrepaidCards() => displayPrepaidCards = !displayPrepaidCards;
208 +
209 + @action
210 + void toggleGiftCards() => displayGiftCards = !displayGiftCards;
211 +
212 + @action
213 + void toggleDenominationsCards() => displayDenominationsCards = !displayDenominationsCards;
214 +
215 + @action
216 + void toggleCustomValueCards() => displayCustomValueCards = !displayCustomValueCards;
217 +
218 + void setScrollOffsetFromTop(double scrollOffset) {
219 + scrollOffsetFromTop = scrollOffset;
220 + }
221 +}
lib/view_model/cake_pay/cake_pay_purchase_view_model.dart new
+162
@@ -0,0 +1,162 @@
1 +import 'dart:async';
2 +
3 +import 'package:cake_wallet/cake_pay/cake_pay_card.dart';
4 +import 'package:cake_wallet/cake_pay/cake_pay_order.dart';
5 +import 'package:cake_wallet/cake_pay/cake_pay_payment_credantials.dart';
6 +import 'package:cake_wallet/cake_pay/cake_pay_service.dart';
7 +import 'package:cake_wallet/core/execution_state.dart';
8 +import 'package:cake_wallet/view_model/send/send_view_model.dart';
9 +import 'package:cw_core/wallet_type.dart';
10 +import 'package:mobx/mobx.dart';
11 +
12 +part 'cake_pay_purchase_view_model.g.dart';
13 +
14 +class CakePayPurchaseViewModel = CakePayPurchaseViewModelBase with _$CakePayPurchaseViewModel;
15 +
16 +abstract class CakePayPurchaseViewModelBase with Store {
17 + CakePayPurchaseViewModelBase({
18 + required this.cakePayService,
19 + required this.paymentCredential,
20 + required this.card,
21 + required this.sendViewModel,
22 + }) : walletType = sendViewModel.walletType;
23 +
24 + final WalletType walletType;
25 +
26 + final PaymentCredential paymentCredential;
27 +
28 + final CakePayCard card;
29 +
30 + final SendViewModel sendViewModel;
31 +
32 + final CakePayService cakePayService;
33 +
34 + CakePayOrder? order;
35 +
36 + Timer? _timer;
37 +
38 + DateTime? expirationTime;
39 +
40 + Duration? remainingTime;
41 +
42 + String? get userName => paymentCredential.userName;
43 +
44 + double get amount => paymentCredential.amount;
45 +
46 + int get quantity => paymentCredential.quantity;
47 +
48 + double get totalAmount => paymentCredential.totalAmount;
49 +
50 + String get fiatCurrency => paymentCredential.fiatCurrency;
51 +
52 + CryptoPaymentData? get cryptoPaymentData {
53 + if (order == null) return null;
54 +
55 + if (WalletType.monero == walletType) {
56 + return order!.paymentData.xmr;
57 + }
58 +
59 + if (WalletType.bitcoin == walletType) {
60 + final paymentUrls = order!.paymentData.btc.paymentUrls!.bip21;
61 +
62 + final uri = Uri.parse(paymentUrls!);
63 +
64 + final address = uri.path;
65 + final price = uri.queryParameters['amount'];
66 +
67 + return CryptoPaymentData(
68 + address: address,
69 + price: price ?? '0',
70 + );
71 + }
72 +
73 + return null;
74 + }
75 +
76 + @observable
77 + bool isOrderExpired = false;
78 +
79 + @observable
80 + String formattedRemainingTime = '';
81 +
82 + @action
83 + Future<void> createOrder() async {
84 + if (walletType != WalletType.bitcoin && walletType != WalletType.monero) {
85 + sendViewModel.state = FailureState('Unsupported wallet type, please use Bitcoin or Monero.');
86 + }
87 + try {
88 + order = await cakePayService.createOrder(
89 + cardId: card.id,
90 + price: paymentCredential.amount.toString(),
91 + quantity: paymentCredential.quantity);
92 + await confirmSending();
93 + expirationTime = order!.paymentData.expirationTime;
94 + updateRemainingTime();
95 + _startExpirationTimer();
96 + } catch (e) {
97 + sendViewModel.state = FailureState(
98 + sendViewModel.translateErrorMessage(e, walletType, sendViewModel.wallet.currency));
99 + }
100 + }
101 +
102 + @action
103 + Future<void> confirmSending() async {
104 + final cryptoPaymentData = this.cryptoPaymentData;
105 + try {
106 + if (order == null || cryptoPaymentData == null) return;
107 +
108 + sendViewModel.clearOutputs();
109 + final output = sendViewModel.outputs.first;
110 + output.address = cryptoPaymentData.address;
111 + output.setCryptoAmount(cryptoPaymentData.price);
112 +
113 + await sendViewModel.createTransaction();
114 + } catch (e) {
115 + throw e;
116 + }
117 + }
118 +
119 + @action
120 + void updateRemainingTime() {
121 + if (expirationTime == null) {
122 + formattedRemainingTime = '';
123 + return;
124 + }
125 +
126 + remainingTime = expirationTime!.difference(DateTime.now());
127 +
128 + isOrderExpired = remainingTime!.isNegative;
129 +
130 + if (isOrderExpired) {
131 + disposeExpirationTimer();
132 + sendViewModel.state = FailureState('Order has expired.');
133 + } else {
134 + formattedRemainingTime = formatDuration(remainingTime!);
135 + }
136 + }
137 +
138 + void _startExpirationTimer() {
139 + _timer?.cancel();
140 + _timer = Timer.periodic(Duration(seconds: 1), (_) {
141 + updateRemainingTime();
142 + });
143 + }
144 +
145 + String formatDuration(Duration duration) {
146 + final hours = duration.inHours;
147 + final minutes = duration.inMinutes.remainder(60);
148 + final seconds = duration.inSeconds.remainder(60);
149 + return '${hours.toString().padLeft(2, '0')}:${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}';
150 + }
151 +
152 + void disposeExpirationTimer() {
153 + _timer?.cancel();
154 + remainingTime = null;
155 + formattedRemainingTime = '';
156 + expirationTime = null;
157 + }
158 +
159 + void dispose() {
160 + disposeExpirationTimer();
161 + }
162 +}
lib/view_model/dashboard/cake_features_view_model.dart
+4 -4
@@ -1,4 +1,4 @@
1 -import 'package:cake_wallet/ionia/ionia_service.dart';
1 +import 'package:cake_wallet/cake_pay/cake_pay_service.dart';
2 import 'package:mobx/mobx.dart';
3
4 part 'cake_features_view_model.g.dart';
@@ -6,11 +6,11 @@ part 'cake_features_view_model.g.dart';
6 class CakeFeaturesViewModel = CakeFeaturesViewModelBase with _$CakeFeaturesViewModel;
7
8 abstract class CakeFeaturesViewModelBase with Store {
9 - final IoniaService _ioniaService;
9 + final CakePayService _cakePayService;
10
11 - CakeFeaturesViewModelBase(this._ioniaService);
11 + CakeFeaturesViewModelBase(this._cakePayService);
12
13 Future<bool> isIoniaUserAuthenticated() async {
14 - return await _ioniaService.isLogined();
14 + return await _cakePayService.isLogged();
15 }
16 }
lib/view_model/dashboard/dropdown_filter_item.dart new
+19
@@ -0,0 +1,19 @@
1 +import 'package:cake_wallet/view_model/dashboard/filter_item.dart';
2 +
3 +class DropdownFilterItem extends FilterItem {
4 + DropdownFilterItem({
5 + required this.items,
6 + required this.caption,
7 + required this.selectedItem,
8 + required this.onItemSelected,
9 + }) : super(
10 + value: () => false,
11 + caption: caption,
12 + onChanged: (_) {},
13 + );
14 +
15 + final List<String> items;
16 + final String caption;
17 + final String selectedItem;
18 + final Function(String) onItemSelected;
19 +}
lib/view_model/dashboard/dropdown_filter_item_widget.dart new
+68
@@ -0,0 +1,68 @@
1 +import 'package:auto_size_text/auto_size_text.dart';
2 +import 'package:cake_wallet/themes/extensions/picker_theme.dart';
3 +import 'package:flutter/material.dart';
4 +
5 +class DropdownFilterList extends StatefulWidget {
6 + DropdownFilterList({
7 + Key? key,
8 + required this.items,
9 + this.itemPrefix,
10 + this.textStyle,
11 + required this.caption,
12 + required this.selectedItem,
13 + required this.onItemSelected,
14 + }) : super(key: key);
15 +
16 + final List<String> items;
17 + final String? itemPrefix;
18 + final TextStyle? textStyle;
19 + final String caption;
20 + final String selectedItem;
21 + final Function(String) onItemSelected;
22 +
23 + @override
24 + _DropdownFilterListState createState() => _DropdownFilterListState();
25 +}
26 +
27 +class _DropdownFilterListState extends State<DropdownFilterList> {
28 + String? selectedValue;
29 +
30 + @override
31 + void initState() {
32 + super.initState();
33 + selectedValue = widget.selectedItem;
34 + }
35 +
36 + @override
37 + Widget build(BuildContext context) {
38 + return DropdownButtonHideUnderline(
39 + child: Container(
40 + child: DropdownButton<String>(
41 + isExpanded: true,
42 + icon: Container(
43 + child: Column(
44 + mainAxisAlignment: MainAxisAlignment.end,
45 + children: [
46 + Icon(Icons.arrow_drop_down, color: Theme.of(context).extension<PickerTheme>()!.searchIconColor),
47 + ],
48 + ),
49 + ),
50 + dropdownColor: Theme.of(context).extension<PickerTheme>()!.searchBackgroundFillColor,
51 + borderRadius: BorderRadius.circular(10),
52 + items: widget.items
53 + .map((item) => DropdownMenuItem<String>(
54 + alignment: Alignment.bottomCenter,
55 + value: item,
56 + child: AutoSizeText('${widget.itemPrefix ?? ''} $item', style: widget.textStyle),
57 + ))
58 + .toList(),
59 + value: selectedValue,
60 + onChanged: (newValue) {
61 + setState(() => selectedValue = newValue);
62 + widget.onItemSelected(newValue!);
63 + },
64 + ),
65 + ),
66 + );
67 + }
68 +}
lib/view_model/ionia/ionia_account_view_model.dart deleted
-50
@@ -1,50 +0,0 @@
1 -import 'package:cake_wallet/ionia/ionia_create_state.dart';
2 -import 'package:cake_wallet/ionia/ionia_service.dart';
3 -import 'package:mobx/mobx.dart';
4 -import 'package:cake_wallet/ionia/ionia_gift_card.dart';
5 -
6 -part 'ionia_account_view_model.g.dart';
7 -
8 -class IoniaAccountViewModel = IoniaAccountViewModelBase with _$IoniaAccountViewModel;
9 -
10 -abstract class IoniaAccountViewModelBase with Store {
11 - IoniaAccountViewModelBase({required this.ioniaService})
12 - : email = '',
13 - giftCards = [],
14 - merchantState = InitialIoniaMerchantLoadingState() {
15 - ioniaService.getUserEmail().then((email) => this.email = email);
16 - updateUserGiftCards();
17 - }
18 -
19 - final IoniaService ioniaService;
20 -
21 - @observable
22 - String email;
23 -
24 - @observable
25 - List<IoniaGiftCard> giftCards;
26 -
27 - @observable
28 - IoniaMerchantState merchantState;
29 -
30 - @computed
31 - int get countOfMerch => giftCards.where((giftCard) => !giftCard.isEmpty).length;
32 -
33 - @computed
34 - List<IoniaGiftCard> get activeMechs => giftCards.where((giftCard) => !giftCard.isEmpty).toList();
35 -
36 - @computed
37 - List<IoniaGiftCard> get redeemedMerchs => giftCards.where((giftCard) => giftCard.isEmpty).toList();
38 -
39 - @action
40 - void logout() {
41 - ioniaService.logout();
42 - }
43 -
44 - @action
45 - Future<void> updateUserGiftCards() async {
46 - merchantState = IoniaLoadingMerchantState();
47 - giftCards = await ioniaService.getCurrentUserGiftCardSummaries();
48 - merchantState = IoniaLoadedMerchantState();
49 - }
50 -}
lib/view_model/ionia/ionia_auth_view_model.dart deleted
-69
@@ -1,69 +0,0 @@
1 -import 'package:cake_wallet/ionia/ionia_create_state.dart';
2 -import 'package:cake_wallet/ionia/ionia_service.dart';
3 -import 'package:mobx/mobx.dart';
4 -
5 -part 'ionia_auth_view_model.g.dart';
6 -
7 -class IoniaAuthViewModel = IoniaAuthViewModelBase with _$IoniaAuthViewModel;
8 -
9 -abstract class IoniaAuthViewModelBase with Store {
10 -
11 - IoniaAuthViewModelBase({required this.ioniaService}):
12 - createUserState = IoniaInitialCreateState(),
13 - signInState = IoniaInitialCreateState(),
14 - otpState = IoniaOtpSendDisabled(),
15 - email = '',
16 - otp = '';
17 -
18 - final IoniaService ioniaService;
19 -
20 - @observable
21 - IoniaCreateAccountState createUserState;
22 -
23 - @observable
24 - IoniaCreateAccountState signInState;
25 -
26 - @observable
27 - IoniaOtpState otpState;
28 -
29 - @observable
30 - String email;
31 -
32 - @observable
33 - String otp;
34 -
35 - @action
36 - Future<void> verifyEmail(String code) async {
37 - try {
38 - otpState = IoniaOtpValidating();
39 - await ioniaService.verifyEmail(code);
40 - otpState = IoniaOtpSuccess();
41 - } catch (_) {
42 - otpState = IoniaOtpFailure(error: 'Invalid OTP. Try again');
43 - }
44 - }
45 -
46 - @action
47 - Future<void> createUser(String email) async {
48 - try {
49 - createUserState = IoniaCreateStateLoading();
50 - await ioniaService.createUser(email);
51 - createUserState = IoniaCreateStateSuccess();
52 - } catch (e) {
53 - createUserState = IoniaCreateStateFailure(error: e.toString());
54 - }
55 - }
56 -
57 -
58 - @action
59 - Future<void> signIn(String email) async {
60 - try {
61 - signInState = IoniaCreateStateLoading();
62 - await ioniaService.signIn(email);
63 - signInState = IoniaCreateStateSuccess();
64 - } catch (e) {
65 - signInState = IoniaCreateStateFailure(error: e.toString());
66 - }
67 - }
68 -
69 -}
\ No newline at end of file
lib/view_model/ionia/ionia_buy_card_view_model.dart deleted
-30
@@ -1,30 +0,0 @@
1 -import 'package:cake_wallet/ionia/ionia_merchant.dart';
2 -import 'package:mobx/mobx.dart';
3 -
4 -part 'ionia_buy_card_view_model.g.dart';
5 -
6 -class IoniaBuyCardViewModel = IoniaBuyCardViewModelBase with _$IoniaBuyCardViewModel;
7 -
8 -abstract class IoniaBuyCardViewModelBase with Store {
9 - IoniaBuyCardViewModelBase({required this.ioniaMerchant})
10 - : isEnablePurchase = false,
11 - amount = 0;
12 -
13 - final IoniaMerchant ioniaMerchant;
14 -
15 - @observable
16 - double amount;
17 -
18 - @observable
19 - bool isEnablePurchase;
20 -
21 - @action
22 - void onAmountChanged(String input) {
23 - if (input.isEmpty) return;
24 - amount = double.parse(input.replaceAll(',', '.'));
25 - final min = ioniaMerchant.minimumCardPurchase;
26 - final max = ioniaMerchant.maximumCardPurchase;
27 -
28 - isEnablePurchase = amount >= min && amount <= max;
29 - }
30 -}
lib/view_model/ionia/ionia_custom_redeem_view_model.dart deleted
-51
@@ -1,51 +0,0 @@
1 -import 'package:cake_wallet/core/execution_state.dart';
2 -import 'package:cake_wallet/ionia/ionia_gift_card.dart';
3 -import 'package:cake_wallet/ionia/ionia_service.dart';
4 -import 'package:mobx/mobx.dart';
5 -part 'ionia_custom_redeem_view_model.g.dart';
6 -
7 -class IoniaCustomRedeemViewModel = IoniaCustomRedeemViewModelBase with _$IoniaCustomRedeemViewModel;
8 -
9 -abstract class IoniaCustomRedeemViewModelBase with Store {
10 - IoniaCustomRedeemViewModelBase({
11 - required this.giftCard,
12 - required this.ioniaService,
13 - }) : amount = 0,
14 - redeemState = InitialExecutionState();
15 -
16 - final IoniaGiftCard giftCard;
17 -
18 - final IoniaService ioniaService;
19 -
20 - @observable
21 - ExecutionState redeemState;
22 -
23 - @observable
24 - double amount;
25 -
26 - @computed
27 - double get remaining =>
28 - amount <= giftCard.remainingAmount ? giftCard.remainingAmount - amount : 0;
29 -
30 - @computed
31 - String get formattedRemaining => remaining.toStringAsFixed(2);
32 -
33 - @computed
34 - bool get disableRedeem => amount > giftCard.remainingAmount;
35 -
36 - @action
37 - void updateAmount(String text) {
38 - amount = double.tryParse(text.replaceAll(',', '.')) ?? 0;
39 - }
40 -
41 - @action
42 - Future<void> addCustomRedeem() async {
43 - try {
44 - redeemState = IsExecutingState();
45 - await ioniaService.redeem(giftCardId: giftCard.id, amount: amount);
46 - redeemState = ExecutedSuccessfullyState();
47 - } catch (e) {
48 - redeemState = FailureState(e.toString());
49 - }
50 - }
51 -}
lib/view_model/ionia/ionia_custom_tip_view_model.dart deleted
-34
@@ -1,34 +0,0 @@
1 -import 'package:cake_wallet/ionia/ionia_merchant.dart';
2 -import 'package:cake_wallet/ionia/ionia_tip.dart';
3 -import 'package:mobx/mobx.dart';
4 -
5 -part 'ionia_custom_tip_view_model.g.dart';
6 -
7 -class IoniaCustomTipViewModel = IoniaCustomTipViewModelBase with _$IoniaCustomTipViewModel;
8 -
9 -abstract class IoniaCustomTipViewModelBase with Store {
10 - IoniaCustomTipViewModelBase({
11 - required this.amount,
12 - required this.tip,
13 - required this.ioniaMerchant})
14 - : customTip = tip,
15 - percentage = 0;
16 -
17 - final IoniaMerchant ioniaMerchant;
18 - final double amount;
19 - final IoniaTip tip;
20 -
21 - @observable
22 - IoniaTip customTip;
23 -
24 - @observable
25 - double percentage;
26 -
27 - @action
28 - void onTipChanged(String value){
29 -
30 - final _amount = value.isEmpty ? 0 : double.parse(value.replaceAll(',', '.'));
31 - percentage = _amount/amount * 100;
32 - customTip = IoniaTip(percentage: percentage, originalAmount: amount);
33 - }
34 -}
\ No newline at end of file
lib/view_model/ionia/ionia_gift_card_details_view_model.dart deleted
-54
@@ -1,54 +0,0 @@
1 -import 'package:cake_wallet/core/execution_state.dart';
2 -import 'package:cake_wallet/ionia/ionia_service.dart';
3 -import 'package:cake_wallet/ionia/ionia_gift_card.dart';
4 -import 'package:mobx/mobx.dart';
5 -import 'package:device_display_brightness/device_display_brightness.dart';
6 -
7 -part 'ionia_gift_card_details_view_model.g.dart';
8 -
9 -class IoniaGiftCardDetailsViewModel = IoniaGiftCardDetailsViewModelBase
10 - with _$IoniaGiftCardDetailsViewModel;
11 -
12 -abstract class IoniaGiftCardDetailsViewModelBase with Store {
13 - IoniaGiftCardDetailsViewModelBase({required this.ioniaService, required this.giftCard})
14 - : redeemState = InitialExecutionState(),
15 - remainingAmount = giftCard.remainingAmount,
16 - brightness = 0;
17 -
18 - final IoniaService ioniaService;
19 -
20 - double brightness;
21 -
22 - @observable
23 - IoniaGiftCard giftCard;
24 -
25 - @observable
26 - double remainingAmount;
27 -
28 - @observable
29 - ExecutionState redeemState;
30 -
31 - @action
32 - Future<void> redeem() async {
33 - giftCard.remainingAmount = remainingAmount;
34 - try {
35 - redeemState = IsExecutingState();
36 - await ioniaService.redeem(giftCardId: giftCard.id, amount: giftCard.remainingAmount);
37 - giftCard = await ioniaService.getGiftCard(id: giftCard.id);
38 - redeemState = ExecutedSuccessfullyState();
39 - } catch (e) {
40 - redeemState = FailureState(e.toString());
41 - }
42 - }
43 -
44 - @action
45 - Future<void> refeshCard() async {
46 - giftCard = await ioniaService.getGiftCard(id: giftCard.id);
47 - remainingAmount = giftCard.remainingAmount;
48 - }
49 -
50 - void increaseBrightness() async {
51 - brightness = await DeviceDisplayBrightness.getBrightness();
52 - await DeviceDisplayBrightness.setBrightness(1.0);
53 - }
54 -}
lib/view_model/ionia/ionia_gift_cards_list_view_model.dart deleted
-139
@@ -1,139 +0,0 @@
1 -import 'package:cake_wallet/ionia/ionia_category.dart';
2 -import 'package:cake_wallet/ionia/ionia_service.dart';
3 -import 'package:cake_wallet/ionia/ionia_create_state.dart';
4 -import 'package:cake_wallet/ionia/ionia_merchant.dart';
5 -import 'package:mobx/mobx.dart';
6 -part 'ionia_gift_cards_list_view_model.g.dart';
7 -
8 -class IoniaGiftCardsListViewModel = IoniaGiftCardsListViewModelBase with _$IoniaGiftCardsListViewModel;
9 -
10 -abstract class IoniaGiftCardsListViewModelBase with Store {
11 - IoniaGiftCardsListViewModelBase({
12 - required this.ioniaService,
13 - }) :
14 - cardState = IoniaNoCardState(),
15 - ioniaMerchants = [],
16 - ioniaCategories = IoniaCategory.allCategories,
17 - selectedIndices = ObservableList<IoniaCategory>.of([IoniaCategory.all]),
18 - scrollOffsetFromTop = 0.0,
19 - merchantState = InitialIoniaMerchantLoadingState(),
20 - createCardState = IoniaCreateCardState(),
21 - searchString = '',
22 - ioniaMerchantList = <IoniaMerchant>[] {
23 - }
24 -
25 - final IoniaService ioniaService;
26 -
27 - List<IoniaMerchant> ioniaMerchantList;
28 -
29 - String searchString;
30 -
31 - @observable
32 - double scrollOffsetFromTop;
33 -
34 - @observable
35 - IoniaCreateCardState createCardState;
36 -
37 - @observable
38 - IoniaFetchCardState cardState;
39 -
40 - @observable
41 - IoniaMerchantState merchantState;
42 -
43 - @observable
44 - List<IoniaMerchant> ioniaMerchants;
45 -
46 - @observable
47 - List<IoniaCategory> ioniaCategories;
48 -
49 - @observable
50 - ObservableList<IoniaCategory> selectedIndices;
51 -
52 - @action
53 - Future<void> createCard() async {
54 - try {
55 - createCardState = IoniaCreateCardLoading();
56 - await ioniaService.createCard();
57 - createCardState = IoniaCreateCardSuccess();
58 - } catch (e) {
59 - createCardState = IoniaCreateCardFailure(error: e.toString());
60 - }
61 - }
62 -
63 - @action
64 - void searchMerchant(String text) {
65 - if (text.isEmpty) {
66 - ioniaMerchants = ioniaMerchantList;
67 - return;
68 - }
69 - searchString = text;
70 - ioniaService.getMerchantsByFilter(search: searchString).then((value) {
71 - ioniaMerchants = value;
72 - });
73 - }
74 -
75 - Future<void> _getCard() async {
76 - cardState = IoniaFetchingCard();
77 - try {
78 - final card = await ioniaService.getCard();
79 -
80 - cardState = IoniaCardSuccess(card: card);
81 - } catch (_) {
82 - cardState = IoniaFetchCardFailure();
83 - }
84 - }
85 -
86 -
87 - void getMerchants() {
88 - merchantState = IoniaLoadingMerchantState();
89 - ioniaService.getMerchantsByFilter(categories: selectedIndices).then((value) {
90 - value.sort((a, b) => a.legalName.toLowerCase().compareTo(b.legalName.toLowerCase()));
91 - ioniaMerchants = ioniaMerchantList = value;
92 - merchantState = IoniaLoadedMerchantState();
93 - });
94 -
95 - }
96 -
97 - @action
98 - void setSelectedFilter(IoniaCategory category) {
99 - if (category == IoniaCategory.all) {
100 - selectedIndices.clear();
101 - selectedIndices.add(category);
102 - return;
103 - }
104 -
105 - if (category != IoniaCategory.all) {
106 - selectedIndices.remove(IoniaCategory.all);
107 - }
108 -
109 - if (selectedIndices.contains(category)) {
110 - selectedIndices.remove(category);
111 -
112 - if (selectedIndices.isEmpty) {
113 - selectedIndices.add(IoniaCategory.all);
114 - }
115 - return;
116 - }
117 - selectedIndices.add(category);
118 - }
119 -
120 - @action
121 - void onSearchFilter(String text) {
122 - if (text.isEmpty) {
123 - ioniaCategories = IoniaCategory.allCategories;
124 - } else {
125 - ioniaCategories = IoniaCategory.allCategories
126 - .where((e) => e.title.toLowerCase().contains(text.toLowerCase()),)
127 - .toList();
128 - }
129 - }
130 -
131 - @action
132 - void resetIoniaCategories() {
133 - ioniaCategories = IoniaCategory.allCategories;
134 - }
135 -
136 - void setScrollOffsetFromTop(double scrollOffset) {
137 - scrollOffsetFromTop = scrollOffset;
138 - }
139 -}
lib/view_model/ionia/ionia_payment_status_view_model.dart deleted
-62
@@ -1,62 +0,0 @@
1 -import 'dart:async';
2 -import 'package:cake_wallet/anypay/any_pay_chain.dart';
3 -import 'package:mobx/mobx.dart';
4 -import 'package:flutter/foundation.dart';
5 -import 'package:cake_wallet/ionia/ionia_service.dart';
6 -import 'package:cake_wallet/ionia/ionia_gift_card.dart';
7 -import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart';
8 -import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart';
9 -
10 -part 'ionia_payment_status_view_model.g.dart';
11 -
12 -class IoniaPaymentStatusViewModel = IoniaPaymentStatusViewModelBase with _$IoniaPaymentStatusViewModel;
13 -
14 -abstract class IoniaPaymentStatusViewModelBase with Store {
15 - IoniaPaymentStatusViewModelBase(
16 - this.ioniaService, {
17 - required this.paymentInfo,
18 - required this.committedInfo})
19 - : error = '' {
20 - _timer = Timer.periodic(updateTime, (timer) async {
21 - await updatePaymentStatus();
22 -
23 - if (giftCard != null) {
24 - timer?.cancel();
25 - }
26 - });
27 - }
28 -
29 - static const updateTime = Duration(seconds: 3);
30 -
31 - final IoniaService ioniaService;
32 - final IoniaAnyPayPaymentInfo paymentInfo;
33 - final AnyPayPaymentCommittedInfo committedInfo;
34 -
35 - @observable
36 - IoniaGiftCard? giftCard;
37 -
38 - @observable
39 - String error;
40 -
41 - Timer? get timer => _timer;
42 -
43 - bool get payingByBitcoin => paymentInfo.anyPayPayment.chain == AnyPayChain.btc;
44 -
45 - Timer? _timer;
46 -
47 - @action
48 - Future<void> updatePaymentStatus() async {
49 - try {
50 - final giftCardId = await ioniaService.getPaymentStatus(
51 - orderId: paymentInfo.ioniaOrder.id,
52 - paymentId: paymentInfo.ioniaOrder.paymentId);
53 -
54 - if (giftCardId != null) {
55 - giftCard = await ioniaService.getGiftCard(id: giftCardId);
56 - }
57 -
58 - } catch (e) {
59 - error = e.toString();
60 - }
61 - }
62 -}
lib/view_model/ionia/ionia_purchase_merch_view_model.dart deleted
-104
@@ -1,104 +0,0 @@
1 -import 'package:flutter/foundation.dart';
2 -import 'package:mobx/mobx.dart';
3 -import 'package:cake_wallet/anypay/any_pay_payment.dart';
4 -import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart';
5 -import 'package:cake_wallet/core/execution_state.dart';
6 -import 'package:cake_wallet/ionia/ionia_anypay.dart';
7 -import 'package:cake_wallet/ionia/ionia_merchant.dart';
8 -import 'package:cake_wallet/ionia/ionia_tip.dart';
9 -import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart';
10 -import 'package:cake_wallet/view_model/send/send_view_model.dart';
11 -
12 -part 'ionia_purchase_merch_view_model.g.dart';
13 -
14 -class IoniaMerchPurchaseViewModel = IoniaMerchPurchaseViewModelBase with _$IoniaMerchPurchaseViewModel;
15 -
16 -abstract class IoniaMerchPurchaseViewModelBase with Store {
17 - IoniaMerchPurchaseViewModelBase({
18 - required this.ioniaAnyPayService,
19 - required this.amount,
20 - required this.ioniaMerchant,
21 - required this.sendViewModel,
22 - }) : tipAmount = 0.0,
23 - percentage = 0.0,
24 - invoiceCreationState = InitialExecutionState(),
25 - invoiceCommittingState = InitialExecutionState(),
26 - tips = <IoniaTip>[
27 - IoniaTip(percentage: 0, originalAmount: amount),
28 - IoniaTip(percentage: 15, originalAmount: amount),
29 - IoniaTip(percentage: 18, originalAmount: amount),
30 - IoniaTip(percentage: 20, originalAmount: amount),
31 - IoniaTip(percentage: 0, originalAmount: amount, isCustom: true),
32 - ] {
33 - selectedTip = tips.first;
34 - }
35 -
36 - final double amount;
37 -
38 - List<IoniaTip> tips;
39 -
40 - @observable
41 - IoniaTip? selectedTip;
42 -
43 - final IoniaMerchant ioniaMerchant;
44 -
45 - final SendViewModel sendViewModel;
46 -
47 - final IoniaAnyPay ioniaAnyPayService;
48 -
49 - IoniaAnyPayPaymentInfo? paymentInfo;
50 -
51 - AnyPayPayment? get invoice => paymentInfo?.anyPayPayment;
52 -
53 - AnyPayPaymentCommittedInfo? committedInfo;
54 -
55 - @observable
56 - ExecutionState invoiceCreationState;
57 -
58 - @observable
59 - ExecutionState invoiceCommittingState;
60 -
61 - @observable
62 - double percentage;
63 -
64 - @computed
65 - double get giftCardAmount => double.parse((amount + tipAmount).toStringAsFixed(2));
66 -
67 - @computed
68 - double get billAmount => double.parse((giftCardAmount * (1 - (ioniaMerchant.discount / 100))).toStringAsFixed(2));
69 -
70 - @observable
71 - double tipAmount;
72 -
73 - @action
74 - void addTip(IoniaTip tip) {
75 - tipAmount = tip.additionalAmount;
76 - selectedTip = tip;
77 - }
78 -
79 - @action
80 - Future<void> createInvoice() async {
81 - try {
82 - invoiceCreationState = IsExecutingState();
83 - paymentInfo = await ioniaAnyPayService.purchase(merchId: ioniaMerchant.id.toString(), amount: giftCardAmount);
84 - invoiceCreationState = ExecutedSuccessfullyState();
85 - } catch (e) {
86 - invoiceCreationState = FailureState(e.toString());
87 - }
88 - }
89 -
90 - @action
91 - Future<void> commitPaymentInvoice() async {
92 - try {
93 - if (invoice == null) {
94 - throw Exception('Invoice is created. Invoince is null');
95 - }
96 -
97 - invoiceCommittingState = IsExecutingState();
98 - committedInfo = await ioniaAnyPayService.commitInvoice(invoice!);
99 - invoiceCommittingState = ExecutedSuccessfullyState(payload: committedInfo!);
100 - } catch (e) {
101 - invoiceCommittingState = FailureState(e.toString());
102 - }
103 - }
104 -}
res/values/strings_ar.arb
+13 -2
@@ -87,6 +87,7 @@
87 "buy": "اشتري",
88 "buy_alert_content": ".ﺎﻬﻴﻟﺇ ﻞﻳﺪﺒﺘﻟﺍ ﻭﺃ Monero ﻭﺃ Litecoin ﻭﺃ Ethereum ﻭﺃ Bitcoin ﺔﻈﻔﺤﻣ ءﺎﺸﻧﺇ ﻰﺟﺮﻳ .",
89 "buy_bitcoin": "شراء Bitcoin",
90 + "buy_now": "اشتري الآن",
91 "buy_provider_unavailable": "مزود حاليا غير متوفر.",
92 "buy_with": "اشتر بواسطة",
93 "by_cake_pay": "عن طريق Cake Pay",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "موضوع الكعكة الظلام",
96 "cake_pay_account_note": "قم بالتسجيل باستخدام عنوان بريد إلكتروني فقط لمشاهدة البطاقات وشرائها. حتى أن بعضها متوفر بسعر مخفض!",
97 "cake_pay_learn_more": "شراء واسترداد بطاقات الهدايا على الفور في التطبيق!\nاسحب من اليسار إلى اليمين لمعرفة المزيد.",
97 - "cake_pay_subtitle": "شراء بطاقات هدايا مخفضة السعر (الولايات المتحدة فقط)",
98 - "cake_pay_title": "بطاقات هدايا Cake Pay",
98 + "cake_pay_subtitle": "شراء بطاقات مسبقة الدفع وبطاقات الهدايا في جميع أنحاء العالم",
99 "cake_pay_web_cards_subtitle": "اشتري بطاقات مدفوعة مسبقا وبطاقات هدايا في جميع أنحاء العالم",
100 "cake_pay_web_cards_title": "بطاقات Cake Pay Web",
101 "cake_wallet": "Cake Wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "تغيير المحفظة الحالية",
124 "choose_account": "اختر حساب",
125 "choose_address": "\n\nالرجاء اختيار عنوان:",
126 + "choose_card_value": "اختر قيمة بطاقة",
127 "choose_derivation": "اختر اشتقاق المحفظة",
128 "choose_from_available_options": "اختر من بين الخيارات المتاحة:",
129 "choose_one": "اختر واحدة",
@@ -166,6 +167,7 @@
167 "copy_address": "نسخ العنوان",
168 "copy_id": "نسخ معرف العملية",
169 "copyWalletConnectLink": "ﺎﻨﻫ ﻪﻘﺼﻟﺍﻭ dApp ﻦﻣ WalletConnect ﻂﺑﺍﺭ ﺦﺴﻧﺍ",
170 + "countries": "بلدان",
171 "create_account": "إنشاء حساب",
172 "create_backup": "انشئ نسخة احتياطية",
173 "create_donation_link": "إنشاء رابط التبرع",
@@ -178,6 +180,7 @@
180 "custom": "مخصصة",
181 "custom_drag": "مخصص (عقد وسحب)",
182 "custom_redeem_amount": "مبلغ الاسترداد مخصص",
183 + "custom_value": "القيمة الجمركية",
184 "dark_theme": "داكن",
185 "debit_card": "بطاقة ائتمان",
186 "debit_card_terms": "يخضع تخزين واستخدام رقم بطاقة الدفع الخاصة بك (وبيانات الاعتماد المقابلة لرقم بطاقة الدفع الخاصة بك) في هذه المحفظة الرقمية لشروط وأحكام اتفاقية حامل البطاقة المعمول بها مع جهة إصدار بطاقة الدفع ، كما هو معمول به من وقت لآخر.",
@@ -190,6 +193,7 @@
193 "delete_wallet": "حذف المحفظة",
194 "delete_wallet_confirm_message": "هل أنت متأكد أنك تريد حذف محفظة ${wallet_name}؟",
195 "deleteConnectionConfirmationPrompt": "ـﺑ ﻝﺎﺼﺗﻻﺍ ﻑﺬﺣ ﺪﻳﺮﺗ ﻚﻧﺃ ﺪﻛﺄﺘﻣ ﺖﻧﺃ ﻞﻫ",
196 + "denominations": "الطوائف",
197 "descending": "النزول",
198 "description": "ﻒﺻﻭ",
199 "destination_tag": "علامة الوجهة:",
@@ -277,6 +281,7 @@
281 "expired": "منتهي الصلاحية",
282 "expires": "تنتهي",
283 "expiresOn": "ﻲﻓ ﻪﺘﻴﺣﻼﺻ ﻲﻬﺘﻨﺗ",
284 + "expiry_and_validity": "انتهاء الصلاحية والصلاحية",
285 "export_backup": "تصدير نسخة احتياطية",
286 "extra_id": "معرف إضافي:",
287 "extracted_address_content": "سوف ترسل الأموال إلى\n${recipient_name}",
@@ -384,6 +389,7 @@
389 "new_template": "قالب جديد",
390 "new_wallet": "إنشاء محفظة جديدة",
391 "newConnection": "ﺪﻳﺪﺟ ﻝﺎﺼﺗﺍ",
392 + "no_cards_found": "لم يتم العثور على بطاقات",
393 "no_id_needed": "لا حاجة لID!",
394 "no_id_required": "لا ID مطلوب. اشحن وانفق في أي مكان",
395 "no_relay_on_domain": ".ﻡﺍﺪﺨﺘﺳﻼﻟ ﻊﺑﺎﺘﺘﻟﺍ ﺭﺎﻴﺘﺧﺍ ءﺎﺟﺮﻟﺍ .ﺡﺎﺘﻣ ﺮﻴﻏ ﻞﻴﺣﺮﺘﻟﺍ ﻥﺃ ﻭﺃ ﻡﺪﺨﺘﺴﻤﻟﺍ ﻝﺎﺠﻤﻟ ﻞﻴﺣﺮﺗ ﺪ",
@@ -452,6 +458,7 @@
458 "pre_seed_button_text": "انا أفهم. أرني سييد الخاص بي",
459 "pre_seed_description": "في الصفحة التالية ستشاهد سلسلة من الكلمات ${words}. هذه هي سييد الفريدة والخاصة بك وهي الطريقة الوحيدة لاسترداد محفظتك في حالة فقدها أو عطلها. تقع على عاتقك مسؤولية تدوينها وتخزينها في مكان آمن خارج تطبيق Cake Wallet.",
460 "pre_seed_title": "مهم",
461 + "prepaid_cards": "البطاقات المدفوعة مسبقا",
462 "prevent_screenshots": "منع لقطات الشاشة وتسجيل الشاشة",
463 "privacy": "خصوصية",
464 "privacy_policy": "سياسة الخصوصية",
@@ -467,6 +474,7 @@
474 "purple_dark_theme": "موضوع الظلام الأرجواني",
475 "qr_fullscreen": "انقر لفتح ال QR بملء الشاشة",
476 "qr_payment_amount": "يحتوي هذا ال QR على مبلغ الدفع. هل تريد تغير المبلغ فوق القيمة الحالية؟",
477 + "quantity": "كمية",
478 "question_to_disable_2fa": "هل أنت متأكد أنك تريد تعطيل Cake 2FA؟ لن تكون هناك حاجة إلى رمز 2FA للوصول إلى المحفظة ووظائف معينة.",
479 "receivable_balance": "التوازن القادم",
480 "receive": "استلام",
@@ -708,6 +716,7 @@
716 "tokenID": "ﻒﻳﺮﻌﺗ ﺔﻗﺎﻄﺑ",
717 "tor_connection": "ﺭﻮﺗ ﻝﺎﺼﺗﺍ",
718 "tor_only": "Tor فقط",
719 + "total": "المجموع",
720 "total_saving": "إجمالي المدخرات",
721 "totp_2fa_failure": "شفرة خاطئة. يرجى تجربة رمز مختلف أو إنشاء مفتاح سري جديد. استخدم تطبيق 2FA متوافقًا يدعم الرموز المكونة من 8 أرقام و SHA512.",
722 "totp_2fa_success": "نجاح! تم تمكين Cake 2FA لهذه المحفظة. تذكر حفظ بذرة ذاكري في حالة فقد الوصول إلى المحفظة.",
@@ -798,6 +807,8 @@
807 "use_ssl": "استخدم SSL",
808 "use_suggested": "استخدام المقترح",
809 "use_testnet": "استخدم testnet",
810 + "value": "قيمة",
811 + "value_type": "نوع القيمة",
812 "variable_pair_not_supported": "هذا الزوج المتغير غير مدعوم في التبادلات المحددة",
813 "verification": "تَحَقّق",
814 "verify_with_2fa": "تحقق مع Cake 2FA",
res/values/strings_bg.arb
+14 -3
@@ -87,6 +87,7 @@
87 "buy": "Купуване",
88 "buy_alert_content": "В момента поддържаме само закупуването на Bitcoin, Ethereum, Litecoin и Monero. Моля, създайте или превключете към своя портфейл Bitcoin, Ethereum, Litecoin или Monero.",
89 "buy_bitcoin": "Купуване на Bitcoin",
90 + "buy_now": "Купи сега",
91 "buy_provider_unavailable": "Понастоящем доставчик не е наличен.",
92 "buy_with": "Купуване чрез",
93 "by_cake_pay": "от Cake Pay",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "Торта тъмна тема",
96 "cake_pay_account_note": "Регистрайте се само с един имейл, за да виждате и купувате карти. За някои има дори и отстъпка!",
97 "cake_pay_learn_more": "Купете и използвайте гифткарти директно в приложението!\nПлъзнете отляво надясно, за да научите още.",
97 - "cake_pay_subtitle": "Купете гифткарти на намалени цени (само за САЩ)",
98 - "cake_pay_title": "Cake Pay Gift Карти",
98 + "cake_pay_subtitle": "Купете предплатени карти и карти за подаръци в световен мащаб",
99 "cake_pay_web_cards_subtitle": "Купете световно признати предплатени и гифт карти",
100 "cake_pay_web_cards_title": "Cake Pay Онлайн Карти",
101 "cake_wallet": "Cake Wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "Смяна на сегашния портфейл",
124 "choose_account": "Избиране на профил",
125 "choose_address": "\n\nМоля, изберете адреса:",
126 + "choose_card_value": "Изберете стойност на картата",
127 "choose_derivation": "Изберете производно на портфейла",
128 "choose_from_available_options": "Изберете от следните опции:",
129 "choose_one": "Изберете едно",
@@ -166,6 +167,7 @@
167 "copy_address": "Copy Address",
168 "copy_id": "Копиране на ID",
169 "copyWalletConnectLink": "Копирайте връзката WalletConnect от dApp и я поставете тук",
170 + "countries": "Държави",
171 "create_account": "Създаване на профил",
172 "create_backup": "Създаване на резервно копие",
173 "create_donation_link": "Създайте връзка за дарение",
@@ -178,6 +180,7 @@
180 "custom": "персонализирано",
181 "custom_drag": "Персонализиране (задръжте и плъзнете)",
182 "custom_redeem_amount": "Персонализирана сума за използване",
183 + "custom_value": "Персонализирана стойност",
184 "dark_theme": "Тъмно",
185 "debit_card": "Дебитна карта",
186 "debit_card_terms": "Съхранението и използването на данните от вашата платежна карта в този дигитален портфейл подлежат на условията на съответното съгласие за картодържец от издателя на картата.",
@@ -190,6 +193,7 @@
193 "delete_wallet": "Изтриване на портфейл",
194 "delete_wallet_confirm_message": "Сигурни ли сте, че искате да изтриете протфейла ${wallet_name}?",
195 "deleteConnectionConfirmationPrompt": "Сигурни ли сте, че искате да изтриете връзката към",
196 + "denominations": "Деноминации",
197 "descending": "Низходящ",
198 "description": "Описание",
199 "destination_tag": "Destination tag:",
@@ -277,6 +281,7 @@
281 "expired": "Изтекло",
282 "expires": "Изтича",
283 "expiresOn": "Изтича на",
284 + "expiry_and_validity": "Изтичане и валидност",
285 "export_backup": "Експортиране на резервно копие",
286 "extra_id": "Допълнително ID:",
287 "extracted_address_content": "Ще изпратите средства на \n${recipient_name}",
@@ -308,7 +313,7 @@
313 "gift_card_is_generated": "Gift Card бе създадена",
314 "gift_card_number": "Номер на Gift Card",
315 "gift_card_redeemed_note": "Използваните гифткарти ще се покажат тук",
311 - "gift_cards": "Gift Карти",
316 + "gift_cards": "Карти за подаръци",
317 "gift_cards_unavailable": "В момента гифткарти могат да бъдат закупени само с Monero, Bitcoin и Litecoin",
318 "got_it": "Готово",
319 "gross_balance": "Брутен баланс",
@@ -384,6 +389,7 @@
389 "new_template": "Нов шаблон",
390 "new_wallet": "Нов портфейл",
391 "newConnection": "Нова връзка",
392 + "no_cards_found": "Не са намерени карти",
393 "no_id_needed": "Без нужда от документ за самоличност!",
394 "no_id_required": "Без нужда от документ за самоличност. Използвайте навсякъде",
395 "no_relay_on_domain": "Няма реле за домейна на потребителя или релето не е налично. Моля, изберете реле, което да използвате.",
@@ -452,6 +458,7 @@
458 "pre_seed_button_text": "Разбирам. Покажи seed",
459 "pre_seed_description": "На следващата страница ще видите поредица от ${words} думи. Това е вашият таен личен seed и е единственият начин да възстановите портфейла си. Отговорността за съхранението му на сигурно място извън приложението на Cake Wallet е изцяло ВАША.",
460 "pre_seed_title": "ВАЖНО",
461 + "prepaid_cards": "Предплатени карти",
462 "prevent_screenshots": "Предотвратете екранни снимки и запис на екрана",
463 "privacy": "Поверителност",
464 "privacy_policy": "Политика за поверителността",
@@ -467,6 +474,7 @@
474 "purple_dark_theme": "Лилава тъмна тема",
475 "qr_fullscreen": "Натиснете, за да отворите QR кода на цял екран",
476 "qr_payment_amount": "Този QR код съдържа сума за плащане. Искате ли да промените стойността?",
477 + "quantity": "Количество",
478 "question_to_disable_2fa": "Сигурни ли сте, че искате да деактивирате Cake 2FA? Вече няма да е необходим 2FA код за достъп до портфейла и определени функции.",
479 "receivable_balance": "Баланс за вземания",
480 "receive": "Получи",
@@ -708,6 +716,7 @@
716 "tokenID": "документ за самоличност",
717 "tor_connection": "Tor връзка",
718 "tor_only": "Само чрез Tor",
719 + "total": "Обща сума",
720 "total_saving": "Общо спестявания",
721 "totp_2fa_failure": "Грешен код. Моля, опитайте с различен код или генерирайте нов таен ключ. Използвайте съвместимо 2FA приложение, което поддържа 8-цифрени кодове и SHA512.",
722 "totp_2fa_success": "Успех! Cake 2FA е активиран за този портфейл. Не забравяйте да запазите мнемоничното начало, в случай че загубите достъп до портфейла.",
@@ -798,6 +807,8 @@
807 "use_ssl": "Използване на SSL",
808 "use_suggested": "Използване на предложеното",
809 "use_testnet": "Използвайте TestNet",
810 + "value": "Стойност",
811 + "value_type": "Тип стойност",
812 "variable_pair_not_supported": "Този variable pair не се поддържа от избраната борса",
813 "verification": "Потвърждаване",
814 "verify_with_2fa": "Проверете с Cake 2FA",
res/values/strings_cs.arb
+13 -2
@@ -87,6 +87,7 @@
87 "buy": "Koupit",
88 "buy_alert_content": "V současné době podporujeme pouze nákup bitcoinů, etherea, litecoinů a monero. Vytvořte nebo přepněte na svou peněženku bitcoinů, etherea, litecoinů nebo monero.",
89 "buy_bitcoin": "Nakoupit Bitcoin",
90 + "buy_now": "Kup nyní",
91 "buy_provider_unavailable": "Poskytovatel aktuálně nedostupný.",
92 "buy_with": "Nakoupit pomocí",
93 "by_cake_pay": "od Cake Pay",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "Dort tmavé téma",
96 "cake_pay_account_note": "Přihlaste se svou e-mailovou adresou pro zobrazení a nákup karet. Některé jsou dostupné ve slevě!",
97 "cake_pay_learn_more": "Okamžitý nákup a uplatnění dárkových karet v aplikaci!\nPřejeďte prstem zleva doprava pro další informace.",
97 - "cake_pay_subtitle": "Kupte si zlevněné dárkové karty (pouze USA)",
98 - "cake_pay_title": "Cake Pay dárkové karty",
98 + "cake_pay_subtitle": "Kupte si celosvětové předplacené karty a dárkové karty",
99 "cake_pay_web_cards_subtitle": "Kupte si celosvětové předplacené a dárkové karty",
100 "cake_pay_web_cards_title": "Cake Pay webové karty",
101 "cake_wallet": "Cake Wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "Přepnout peněženku",
124 "choose_account": "Zvolte částku",
125 "choose_address": "\n\nProsím vyberte adresu:",
126 + "choose_card_value": "Vyberte hodnotu karty",
127 "choose_derivation": "Vyberte derivaci peněženky",
128 "choose_from_available_options": "Zvolte si z dostupných možností:",
129 "choose_one": "Zvolte si",
@@ -166,6 +167,7 @@
167 "copy_address": "Zkopírovat adresu",
168 "copy_id": "Kopírovat ID",
169 "copyWalletConnectLink": "Zkopírujte odkaz WalletConnect z dApp a vložte jej sem",
170 + "countries": "Země",
171 "create_account": "Vytvořit účet",
172 "create_backup": "Vytvořit zálohu",
173 "create_donation_link": "Vytvořit odkaz na darování",
@@ -178,6 +180,7 @@
180 "custom": "vlastní",
181 "custom_drag": "Custom (Hold and Drag)",
182 "custom_redeem_amount": "Vlastní částka pro uplatnění",
183 + "custom_value": "Vlastní hodnota",
184 "dark_theme": "Tmavý",
185 "debit_card": "Debetní karta",
186 "debit_card_terms": "Uložení a použití vašeho čísla platební karty (a přihlašovací údaje k vašemu číslu karty) v této digitální peněžence se řídí Obchodními podmínkami smlouvy příslušného držitele karty s vydavatelem karty (v jejich nejaktuálnější verzi).",
@@ -190,6 +193,7 @@
193 "delete_wallet": "Smazat peněženku",
194 "delete_wallet_confirm_message": "Opravdu chcete smazat ${wallet_name} peněženku?",
195 "deleteConnectionConfirmationPrompt": "Jste si jisti, že chcete smazat připojení k?",
196 + "denominations": "Označení",
197 "descending": "Klesající",
198 "description": "Popis",
199 "destination_tag": "Destination Tag:",
@@ -277,6 +281,7 @@
281 "expired": "Vypršelo",
282 "expires": "Vyprší",
283 "expiresOn": "Vyprší dne",
284 + "expiry_and_validity": "Vypršení a platnost",
285 "export_backup": "Exportovat zálohu",
286 "extra_id": "Extra ID:",
287 "extracted_address_content": "Prostředky budete posílat na\n${recipient_name}",
@@ -384,6 +389,7 @@
389 "new_template": "Nová šablona",
390 "new_wallet": "Nová peněženka",
391 "newConnection": "Nové připojení",
392 + "no_cards_found": "Žádné karty nenalezeny",
393 "no_id_needed": "Žádné ID není potřeba!",
394 "no_id_required": "Žádní ID není potřeba. Dobijte si a utrácejte kdekoliv",
395 "no_relay_on_domain": "Pro doménu uživatele neexistuje přenos nebo je přenos nedostupný. Vyberte relé, které chcete použít.",
@@ -452,6 +458,7 @@
458 "pre_seed_button_text": "Rozumím. Ukaž mi můj seed.",
459 "pre_seed_description": "Na následující stránce uvidíte sérii ${words} slov. Je to váš tzv. seed a je to JEDINÁ možnost, jak můžete později obnovit svou peněženku v případě ztráty nebo poruchy. Je VAŠÍ zodpovědností zapsat si ho a uložit si ho na bezpečném místě mimo aplikaci Cake Wallet.",
460 "pre_seed_title": "DŮLEŽITÉ",
461 + "prepaid_cards": "Předplacené karty",
462 "prevent_screenshots": "Zabránit vytváření snímků obrazovky a nahrávání obrazovky",
463 "privacy": "Soukromí",
464 "privacy_policy": "Zásady ochrany soukromí",
@@ -467,6 +474,7 @@
474 "purple_dark_theme": "Fialové temné téma",
475 "qr_fullscreen": "Poklepáním otevřete QR kód na celé obrazovce",
476 "qr_payment_amount": "Tento QR kód obsahuje i částku. Chcete přepsat současnou hodnotu?",
477 + "quantity": "Množství",
478 "question_to_disable_2fa": "Opravdu chcete deaktivovat Cake 2FA? Pro přístup k peněžence a některým funkcím již nebude potřeba kód 2FA.",
479 "receivable_balance": "Zůstatek pohledávek",
480 "receive": "Přijmout",
@@ -708,6 +716,7 @@
716 "tokenID": "ID",
717 "tor_connection": "Připojení Tor",
718 "tor_only": "Pouze Tor",
719 + "total": "Celkový",
720 "total_saving": "Celkem ušetřeno",
721 "totp_2fa_failure": "Nesprávný kód. Zkuste prosím jiný kód nebo vygenerujte nový tajný klíč. Použijte kompatibilní aplikaci 2FA, která podporuje 8místné kódy a SHA512.",
722 "totp_2fa_success": "Úspěch! Pro tuto peněženku povolen Cake 2FA. Nezapomeňte si uložit mnemotechnický klíč pro případ, že ztratíte přístup k peněžence.",
@@ -798,6 +807,8 @@
807 "use_ssl": "Použít SSL",
808 "use_suggested": "Použít doporučený",
809 "use_testnet": "Použijte testNet",
810 + "value": "Hodnota",
811 + "value_type": "Typ hodnoty",
812 "variable_pair_not_supported": "Tento pár s tržním kurzem není ve zvolené směnárně podporován",
813 "verification": "Ověření",
814 "verify_with_2fa": "Ověřte pomocí Cake 2FA",
res/values/strings_de.arb
+14 -3
@@ -87,6 +87,7 @@
87 "buy": "Kaufen",
88 "buy_alert_content": "Derzeit unterstützen wir nur den Kauf von Bitcoin, Ethereum, Litecoin und Monero. Bitte erstellen Sie Ihr Bitcoin-, Ethereum-, Litecoin- oder Monero-Wallet oder wechseln Sie zu diesem.",
89 "buy_bitcoin": "Bitcoin kaufen",
90 + "buy_now": "Kaufe jetzt",
91 "buy_provider_unavailable": "Anbieter derzeit nicht verfügbar.",
92 "buy_with": "Kaufen mit",
93 "by_cake_pay": "von Cake Pay",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "Cake Dark Thema",
96 "cake_pay_account_note": "Melden Sie sich nur mit einer E-Mail-Adresse an, um Karten anzuzeigen und zu kaufen. Einige sind sogar mit Rabatt erhältlich!",
97 "cake_pay_learn_more": "Kaufen und lösen Sie Geschenkkarten sofort in der App ein!\nWischen Sie von links nach rechts, um mehr zu erfahren.",
97 - "cake_pay_subtitle": "Kaufen Sie ermäßigte Geschenkkarten (nur USA)",
98 - "cake_pay_title": "Cake Pay-Geschenkkarten",
98 + "cake_pay_subtitle": "Kaufen Sie weltweite Prepaid -Karten und Geschenkkarten",
99 "cake_pay_web_cards_subtitle": "Kaufen Sie weltweit Prepaid-Karten und Geschenkkarten",
100 "cake_pay_web_cards_title": "Cake Pay-Webkarten",
101 "cake_wallet": "Cake Wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "Aktuelle Wallet ändern",
124 "choose_account": "Konto auswählen",
125 "choose_address": "\n\nBitte wählen Sie die Adresse:",
126 + "choose_card_value": "Wählen Sie einen Kartenwert",
127 "choose_derivation": "Wählen Sie Wallet-Ableitung",
128 "choose_from_available_options": "Wähle aus verfügbaren Optionen:",
129 "choose_one": "Wähle ein",
@@ -166,6 +167,7 @@
167 "copy_address": "Adresse kopieren",
168 "copy_id": "ID kopieren",
169 "copyWalletConnectLink": "Kopieren Sie den WalletConnect-Link von dApp und fügen Sie ihn hier ein",
170 + "countries": "Länder",
171 "create_account": "Konto erstellen",
172 "create_backup": "Backup erstellen",
173 "create_donation_link": "Spendenlink erstellen",
@@ -178,6 +180,7 @@
180 "custom": "benutzerdefiniert",
181 "custom_drag": "Custom (Hold and Drag)",
182 "custom_redeem_amount": "Benutzerdefinierter Einlösungsbetrag",
183 + "custom_value": "Benutzerdefinierten Wert",
184 "dark_theme": "Dunkel",
185 "debit_card": "Debitkarte",
186 "debit_card_terms": "Die Speicherung und Nutzung Ihrer Zahlungskartennummer (und Ihrer Zahlungskartennummer entsprechenden Anmeldeinformationen) in dieser digitalen Geldbörse unterliegt den Allgemeinen Geschäftsbedingungen des geltenden Karteninhabervertrags mit dem Zahlungskartenaussteller, gültig ab von Zeit zu Zeit.",
@@ -190,6 +193,7 @@
193 "delete_wallet": "Wallet löschen",
194 "delete_wallet_confirm_message": "Sind Sie sicher, dass Sie das ${wallet_name} Wallet löschen möchten?",
195 "deleteConnectionConfirmationPrompt": "Sind Sie sicher, dass Sie die Verbindung zu löschen möchten?",
196 + "denominations": "Konfessionen",
197 "descending": "Absteigend",
198 "description": "Beschreibung",
199 "destination_tag": "Ziel-Tag:",
@@ -277,6 +281,7 @@
281 "expired": "Abgelaufen",
282 "expires": "Läuft ab",
283 "expiresOn": "Läuft aus am",
284 + "expiry_and_validity": "Ablauf und Gültigkeit",
285 "export_backup": "Sicherung exportieren",
286 "extra_id": "Extra ID:",
287 "extracted_address_content": "Sie senden Geld an\n${recipient_name}",
@@ -384,6 +389,7 @@
389 "new_template": "neue Vorlage",
390 "new_wallet": "Neue Wallet",
391 "newConnection": "Neue Verbindung",
392 + "no_cards_found": "Keine Karten gefunden",
393 "no_id_needed": "Keine ID erforderlich!",
394 "no_id_required": "Keine ID erforderlich. Upgraden und überall ausgeben",
395 "no_relay_on_domain": "Es gibt kein Relay für die Domäne des Benutzers oder das Relay ist nicht verfügbar. Bitte wählen Sie ein zu verwendendes Relais aus.",
@@ -442,8 +448,8 @@
448 "placeholder_transactions": "Ihre Transaktionen werden hier angezeigt",
449 "please_fill_totp": "Bitte geben Sie den 8-stelligen Code ein, der auf Ihrem anderen Gerät vorhanden ist",
450 "please_make_selection": "Bitte treffen Sie unten eine Auswahl zum Erstellen oder Wiederherstellen Ihrer Wallet.",
445 - "please_reference_document": "Bitte verweisen Sie auf die folgenden Dokumente, um weitere Informationen zu erhalten.",
451 "Please_reference_document": "Weitere Informationen finden Sie in den Dokumenten unten.",
452 + "please_reference_document": "Bitte verweisen Sie auf die folgenden Dokumente, um weitere Informationen zu erhalten.",
453 "please_select": "Bitte auswählen:",
454 "please_select_backup_file": "Bitte wählen Sie die Sicherungsdatei und geben Sie das Sicherungskennwort ein.",
455 "please_try_to_connect_to_another_node": "Bitte versuchen Sie, sich mit einem anderen Knoten zu verbinden",
@@ -453,6 +459,7 @@
459 "pre_seed_button_text": "Verstanden. Zeig mir meinen Seed",
460 "pre_seed_description": "Auf der nächsten Seite sehen Sie eine Reihe von ${words} Wörtern. Dies ist Ihr einzigartiger und privater Seed und der EINZIGE Weg, um Ihre Wallet im Falle eines Verlusts oder einer Fehlfunktion wiederherzustellen. Es liegt in IHRER Verantwortung, ihn aufzuschreiben und an einem sicheren Ort außerhalb der Cake Wallet-App aufzubewahren.",
461 "pre_seed_title": "WICHTIG",
462 + "prepaid_cards": "Karten mit Guthaben",
463 "prevent_screenshots": "Verhindern Sie Screenshots und Bildschirmaufzeichnungen",
464 "privacy": "Datenschutz",
465 "privacy_policy": "Datenschutzrichtlinie",
@@ -468,6 +475,7 @@
475 "purple_dark_theme": "Lila dunkle Thema",
476 "qr_fullscreen": "Tippen Sie hier, um den QR-Code im Vollbildmodus zu öffnen",
477 "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?",
478 + "quantity": "Menge",
479 "question_to_disable_2fa": "Sind Sie sicher, dass Sie Cake 2FA deaktivieren möchten? Für den Zugriff auf die Wallet und bestimmte Funktionen wird kein 2FA-Code mehr benötigt.",
480 "receivable_balance": "Forderungsbilanz",
481 "receive": "Empfangen",
@@ -709,6 +717,7 @@
717 "tokenID": "AUSWEIS",
718 "tor_connection": "Tor-Verbindung",
719 "tor_only": "Nur Tor",
720 + "total": "Gesamt",
721 "total_saving": "Gesamteinsparungen",
722 "totp_2fa_failure": "Falscher Code. Bitte versuchen Sie es mit einem anderen Code oder generieren Sie einen neuen geheimen Schlüssel. Verwenden Sie eine kompatible 2FA-App, die 8-stellige Codes und SHA512 unterstützt.",
723 "totp_2fa_success": "Erfolg! Cake 2FA für dieses Wallet aktiviert. Denken Sie daran, Ihren mnemonischen Seed zu speichern, falls Sie den Zugriff auf die Wallet verlieren.",
@@ -800,6 +809,8 @@
809 "use_ssl": "SSL verwenden",
810 "use_suggested": "Vorgeschlagen verwenden",
811 "use_testnet": "TESTNET verwenden",
812 + "value": "Wert",
813 + "value_type": "Werttyp",
814 "variable_pair_not_supported": "Dieses Variablenpaar wird von den ausgewählten Börsen nicht unterstützt",
815 "verification": "Verifizierung",
816 "verify_with_2fa": "Verifizieren Sie mit Cake 2FA",
res/values/strings_en.arb
+13 -2
@@ -87,6 +87,7 @@
87 "buy": "Buy",
88 "buy_alert_content": "Currently we only support the purchase of Bitcoin, Ethereum, Litecoin, and Monero. Please create or switch to your Bitcoin, Ethereum, Litecoin, or Monero wallet.",
89 "buy_bitcoin": "Buy Bitcoin",
90 + "buy_now": "Buy Now",
91 "buy_provider_unavailable": "Provider currently unavailable.",
92 "buy_with": "Buy with",
93 "by_cake_pay": "by Cake Pay",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "Cake Dark Theme",
96 "cake_pay_account_note": "Sign up with just an email address to see and purchase cards. Some are even available at a discount!",
97 "cake_pay_learn_more": "Instantly purchase and redeem gift cards in the app!\nSwipe left to right to learn more.",
97 - "cake_pay_subtitle": "Buy discounted gift cards (USA only)",
98 - "cake_pay_title": "Cake Pay Gift Cards",
98 + "cake_pay_subtitle": "Buy worldwide prepaid cards and gift cards",
99 "cake_pay_web_cards_subtitle": "Buy worldwide prepaid cards and gift cards",
100 "cake_pay_web_cards_title": "Cake Pay Web Cards",
101 "cake_wallet": "Cake Wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "Change current wallet",
124 "choose_account": "Choose account",
125 "choose_address": "\n\nPlease choose the address:",
126 + "choose_card_value": "Choose a card value",
127 "choose_derivation": "Choose Wallet Derivation",
128 "choose_from_available_options": "Choose from the available options:",
129 "choose_one": "Choose one",
@@ -166,6 +167,7 @@
167 "copy_address": "Copy Address",
168 "copy_id": "Copy ID",
169 "copyWalletConnectLink": "Copy the WalletConnect link from dApp and paste here",
170 + "countries": "Countries",
171 "create_account": "Create Account",
172 "create_backup": "Create backup",
173 "create_donation_link": "Create donation link",
@@ -178,6 +180,7 @@
180 "custom": "Custom",
181 "custom_drag": "Custom (Hold and Drag)",
182 "custom_redeem_amount": "Custom Redeem Amount",
183 + "custom_value": "Custom Value",
184 "dark_theme": "Dark",
185 "debit_card": "Debit Card",
186 "debit_card_terms": "The storage and usage of your payment card number (and credentials corresponding to your payment card number) in this digital wallet are subject to the Terms and Conditions of the applicable cardholder agreement with the payment card issuer, as in effect from time to time.",
@@ -190,6 +193,7 @@
193 "delete_wallet": "Delete wallet",
194 "delete_wallet_confirm_message": "Are you sure that you want to delete ${wallet_name} wallet?",
195 "deleteConnectionConfirmationPrompt": "Are you sure that you want to delete the connection to",
196 + "denominations": "Denominations",
197 "descending": "Descending",
198 "description": "Description",
199 "destination_tag": "Destination tag:",
@@ -277,6 +281,7 @@
281 "expired": "Expired",
282 "expires": "Expires",
283 "expiresOn": "Expires on",
284 + "expiry_and_validity": "Expiry and Validity",
285 "export_backup": "Export backup",
286 "extra_id": "Extra ID:",
287 "extracted_address_content": "You will be sending funds to\n${recipient_name}",
@@ -384,6 +389,7 @@
389 "new_template": "New Template",
390 "new_wallet": "New Wallet",
391 "newConnection": "New Connection",
392 + "no_cards_found": "No cards found",
393 "no_id_needed": "No ID needed!",
394 "no_id_required": "No ID required. Top up and spend anywhere",
395 "no_relay_on_domain": "There isn't a relay for user's domain or the relay is unavailable. Please choose a relay to use.",
@@ -452,6 +458,7 @@
458 "pre_seed_button_text": "I understand. Show me my seed",
459 "pre_seed_description": "On the next page you will see a series of ${words} words. This is your unique and private seed and it is the ONLY way to recover your wallet in case of loss or malfunction. It is YOUR responsibility to write it down and store it in a safe place outside of the Cake Wallet app.",
460 "pre_seed_title": "IMPORTANT",
461 + "prepaid_cards": "Prepaid Cards",
462 "prevent_screenshots": "Prevent screenshots and screen recording",
463 "privacy": "Privacy",
464 "privacy_policy": "Privacy Policy",
@@ -467,6 +474,7 @@
474 "purple_dark_theme": "Purple Dark Theme",
475 "qr_fullscreen": "Tap to open full screen QR code",
476 "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?",
477 + "quantity": "Quantity",
478 "question_to_disable_2fa": "Are you sure that you want to disable Cake 2FA? A 2FA code will no longer be needed to access the wallet and certain functions.",
479 "receivable_balance": "Receivable Balance",
480 "receive": "Receive",
@@ -708,6 +716,7 @@
716 "tokenID": "ID",
717 "tor_connection": "Tor connection",
718 "tor_only": "Tor only",
719 + "total": "Total",
720 "total_saving": "Total Savings",
721 "totp_2fa_failure": "Incorrect code. Please try a different code or generate a new secret key. Use a compatible 2FA app that supports 8-digit codes and SHA512.",
722 "totp_2fa_success": "Success! Cake 2FA enabled for this wallet. Remember to save your mnemonic seed in case you lose wallet access.",
@@ -798,6 +807,8 @@
807 "use_ssl": "Use SSL",
808 "use_suggested": "Use Suggested",
809 "use_testnet": "Use Testnet",
810 + "value": "Value",
811 + "value_type": "Value Type",
812 "variable_pair_not_supported": "This variable pair is not supported with the selected exchanges",
813 "verification": "Verification",
814 "verify_with_2fa": "Verify with Cake 2FA",
res/values/strings_es.arb
+13 -2
@@ -87,6 +87,7 @@
87 "buy": "Comprar",
88 "buy_alert_content": "Actualmente solo admitimos la compra de Bitcoin, Ethereum, Litecoin y Monero. Cree o cambie a su billetera Bitcoin, Ethereum, Litecoin o Monero.",
89 "buy_bitcoin": "Comprar Bitcoin",
90 + "buy_now": "Comprar ahora",
91 "buy_provider_unavailable": "Proveedor actualmente no disponible.",
92 "buy_with": "Compra con",
93 "by_cake_pay": "por Cake Pay",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "Tema oscuro del pastel",
96 "cake_pay_account_note": "Regístrese con solo una dirección de correo electrónico para ver y comprar tarjetas. ¡Algunas incluso están disponibles con descuento!",
97 "cake_pay_learn_more": "¡Compre y canjee tarjetas de regalo al instante en la aplicación!\nDeslice el dedo de izquierda a derecha para obtener más información.",
97 - "cake_pay_subtitle": "Compre tarjetas de regalo con descuento (solo EE. UU.)",
98 - "cake_pay_title": "Tarjetas de regalo Cake Pay",
98 + "cake_pay_subtitle": "Compre tarjetas prepagas y tarjetas de regalo en todo el mundo",
99 "cake_pay_web_cards_subtitle": "Compre tarjetas de prepago y tarjetas de regalo en todo el mundo",
100 "cake_pay_web_cards_title": "Tarjetas Web Cake Pay",
101 "cake_wallet": "Cake Wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "Cambiar billetera actual",
124 "choose_account": "Elegir cuenta",
125 "choose_address": "\n\nPor favor elija la dirección:",
126 + "choose_card_value": "Elija un valor de tarjeta",
127 "choose_derivation": "Elija la derivación de la billetera",
128 "choose_from_available_options": "Elija entre las opciones disponibles:",
129 "choose_one": "Elige uno",
@@ -166,6 +167,7 @@
167 "copy_address": "Copiar dirección ",
168 "copy_id": "Copiar ID",
169 "copyWalletConnectLink": "Copie el enlace de WalletConnect de dApp y péguelo aquí",
170 + "countries": "Países",
171 "create_account": "Crear Cuenta",
172 "create_backup": "Crear copia de seguridad",
173 "create_donation_link": "Crear enlace de donación",
@@ -178,6 +180,7 @@
180 "custom": "Costumbre",
181 "custom_drag": "Custom (mantenía y arrastre)",
182 "custom_redeem_amount": "Cantidad de canje personalizada",
183 + "custom_value": "Valor personalizado",
184 "dark_theme": "Oscura",
185 "debit_card": "Tarjeta de Débito",
186 "debit_card_terms": "El almacenamiento y el uso de su número de tarjeta de pago (y las credenciales correspondientes a su número de tarjeta de pago) en esta billetera digital están sujetos a los Términos y condiciones del acuerdo del titular de la tarjeta aplicable con el emisor de la tarjeta de pago, en vigor desde tiempo al tiempo.",
@@ -190,6 +193,7 @@
193 "delete_wallet": "Eliminar billetera",
194 "delete_wallet_confirm_message": "¿Está seguro de que desea eliminar la billetera ${wallet_name}?",
195 "deleteConnectionConfirmationPrompt": "¿Está seguro de que desea eliminar la conexión a",
196 + "denominations": "Denominaciones",
197 "descending": "Descendente",
198 "description": "Descripción",
199 "destination_tag": "Etiqueta de destino:",
@@ -277,6 +281,7 @@
281 "expired": "Muerto",
282 "expires": "Caduca",
283 "expiresOn": "Expira el",
284 + "expiry_and_validity": "Vencimiento y validez",
285 "export_backup": "Exportar copia de seguridad",
286 "extra_id": "ID adicional:",
287 "extracted_address_content": "Enviará fondos a\n${recipient_name}",
@@ -384,6 +389,7 @@
389 "new_template": "Nueva plantilla",
390 "new_wallet": "Nueva billetera",
391 "newConnection": "Nueva conexión",
392 + "no_cards_found": "No se encuentran cartas",
393 "no_id_needed": "¡No se necesita identificación!",
394 "no_id_required": "No se requiere identificación. Recargue y gaste en cualquier lugar",
395 "no_relay_on_domain": "No hay una retransmisión para el dominio del usuario o la retransmisión no está disponible. Elija un relé para usar.",
@@ -453,6 +459,7 @@
459 "pre_seed_button_text": "Entiendo. Muéstrame mi semilla",
460 "pre_seed_description": "En la página siguiente verá una serie de ${words} palabras. Esta es su semilla única y privada y es la ÚNICA forma de recuperar su billetera en caso de pérdida o mal funcionamiento. Es SU responsabilidad escribirlo y guardarlo en un lugar seguro fuera de la aplicación Cake Wallet.",
461 "pre_seed_title": "IMPORTANTE",
462 + "prepaid_cards": "Tajetas prepagadas",
463 "prevent_screenshots": "Evitar capturas de pantalla y grabación de pantalla",
464 "privacy": "Privacidad",
465 "privacy_policy": "Política de privacidad",
@@ -468,6 +475,7 @@
475 "purple_dark_theme": "Tema morado oscuro",
476 "qr_fullscreen": "Toque para abrir el código QR en pantalla completa",
477 "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?",
478 + "quantity": "Cantidad",
479 "question_to_disable_2fa": "¿Está seguro de que desea deshabilitar Cake 2FA? Ya no se necesitará un código 2FA para acceder a la billetera y a ciertas funciones.",
480 "receivable_balance": "Saldo de cuentas por cobrar",
481 "receive": "Recibir",
@@ -709,6 +717,7 @@
717 "tokenID": "IDENTIFICACIÓN",
718 "tor_connection": "conexión tor",
719 "tor_only": "solo Tor",
720 + "total": "Total",
721 "total_saving": "Ahorro Total",
722 "totp_2fa_failure": "Código incorrecto. Intente con un código diferente o genere una nueva clave secreta. Use una aplicación 2FA compatible que admita códigos de 8 dígitos y SHA512.",
723 "totp_2fa_success": "¡Éxito! Cake 2FA habilitado para esta billetera. Recuerde guardar su semilla mnemotécnica en caso de que pierda el acceso a la billetera.",
@@ -799,6 +808,8 @@
808 "use_ssl": "Utilice SSL",
809 "use_suggested": "Usar sugerido",
810 "use_testnet": "Use TestNet",
811 + "value": "Valor",
812 + "value_type": "Tipo de valor",
813 "variable_pair_not_supported": "Este par de variables no es compatible con los intercambios seleccionados",
814 "verification": "Verificación",
815 "verify_with_2fa": "Verificar con Cake 2FA",
res/values/strings_fr.arb
+14 -3
@@ -87,6 +87,7 @@
87 "buy": "Acheter",
88 "buy_alert_content": "Actuellement, nous ne prenons en charge que l'achat de Bitcoin, Ethereum, Litecoin et Monero. Veuillez créer ou basculer vers votre portefeuille Bitcoin, Ethereum, Litecoin ou Monero.",
89 "buy_bitcoin": "Acheter du Bitcoin",
90 + "buy_now": "Acheter maintenant",
91 "buy_provider_unavailable": "Fournisseur actuellement indisponible.",
92 "buy_with": "Acheter avec",
93 "by_cake_pay": "par Cake Pay",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "Thème sombre du gâteau",
96 "cake_pay_account_note": "Inscrivez-vous avec juste une adresse e-mail pour voir et acheter des cartes. Certaines sont même disponibles à prix réduit !",
97 "cake_pay_learn_more": "Achetez et utilisez instantanément des cartes-cadeaux dans l'application !\nBalayer de gauche à droite pour en savoir plus.",
97 - "cake_pay_subtitle": "Achetez des cartes-cadeaux à prix réduit (États-Unis uniquement)",
98 - "cake_pay_title": "Cartes cadeaux Cake Pay",
98 + "cake_pay_subtitle": "Achetez des cartes et des cartes-cadeaux prépayées mondiales",
99 "cake_pay_web_cards_subtitle": "Achetez des cartes prépayées et des cartes-cadeaux dans le monde entier",
100 "cake_pay_web_cards_title": "Cartes Web Cake Pay",
101 "cake_wallet": "Cake Wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "Changer le portefeuille (wallet) actuel",
124 "choose_account": "Choisir le compte",
125 "choose_address": "\n\nMerci de choisir l'adresse :",
126 + "choose_card_value": "Choisissez une valeur de carte",
127 "choose_derivation": "Choisissez le chemin de dérivation du portefeuille",
128 "choose_from_available_options": "Choisissez parmi les options disponibles :",
129 "choose_one": "Choisissez-en un",
@@ -166,6 +167,7 @@
167 "copy_address": "Copier l'Adresse",
168 "copy_id": "Copier l'ID",
169 "copyWalletConnectLink": "Copiez le lien WalletConnect depuis l'application décentralisée (dApp) et collez-le ici",
170 + "countries": "Des pays",
171 "create_account": "Créer un compte",
172 "create_backup": "Créer une sauvegarde",
173 "create_donation_link": "Créer un lien de don",
@@ -178,6 +180,7 @@
180 "custom": "personnalisé",
181 "custom_drag": "Custom (maintenir et traîner)",
182 "custom_redeem_amount": "Montant d'échange personnalisé",
183 + "custom_value": "Valeur personnalisée",
184 "dark_theme": "Sombre",
185 "debit_card": "Carte de débit",
186 "debit_card_terms": "Le stockage et l'utilisation de votre numéro de carte de paiement (et des informations d'identification correspondant à votre numéro de carte de paiement) dans ce portefeuille (wallet) numérique peuvent être soumis aux conditions générales de l'accord du titulaire de carte parfois en vigueur avec l'émetteur de la carte de paiement.",
@@ -190,6 +193,7 @@
193 "delete_wallet": "Supprimer le portefeuille (wallet)",
194 "delete_wallet_confirm_message": "Êtes-vous sûr de vouloir supprimer le portefeuille (wallet) ${wallet_name}?",
195 "deleteConnectionConfirmationPrompt": "Êtes-vous sûr de vouloir supprimer la connexion à",
196 + "denominations": "Dénominations",
197 "descending": "Descendant",
198 "description": "Description",
199 "destination_tag": "Tag de destination :",
@@ -277,6 +281,7 @@
281 "expired": "Expirée",
282 "expires": "Expire",
283 "expiresOn": "Expire le",
284 + "expiry_and_validity": "Expiration et validité",
285 "export_backup": "Exporter la sauvegarde",
286 "extra_id": "ID supplémentaire :",
287 "extracted_address_content": "Vous allez envoyer des fonds à\n${recipient_name}",
@@ -308,7 +313,7 @@
313 "gift_card_is_generated": "La carte-cadeau est générée",
314 "gift_card_number": "Numéro de carte cadeau",
315 "gift_card_redeemed_note": "Les cartes-cadeaux que vous avez utilisées apparaîtront ici",
311 - "gift_cards": "Cartes-Cadeaux",
316 + "gift_cards": "Cartes cadeaux",
317 "gift_cards_unavailable": "Les cartes-cadeaux ne sont disponibles à l'achat que via Monero, Bitcoin et Litecoin pour le moment",
318 "got_it": "Compris",
319 "gross_balance": "Solde brut",
@@ -384,6 +389,7 @@
389 "new_template": "Nouveau Modèle",
390 "new_wallet": "Nouveau Portefeuille (Wallet)",
391 "newConnection": "Nouvelle connexion",
392 + "no_cards_found": "Pas de cartes trouvées",
393 "no_id_needed": "Aucune pièce d'identité nécessaire !",
394 "no_id_required": "Aucune pièce d'identité requise. Rechargez et dépensez n'importe où",
395 "no_relay_on_domain": "Il n'existe pas de relais pour le domaine de l'utilisateur ou le relais n'est pas disponible. Veuillez choisir un relais à utiliser.",
@@ -452,6 +458,7 @@
458 "pre_seed_button_text": "J'ai compris. Montrez moi ma phrase secrète (seed)",
459 "pre_seed_description": "Sur la page suivante vous allez voir une série de ${words} mots. Ils constituent votre phrase secrète (seed) unique et privée et sont le SEUL moyen de restaurer votre portefeuille (wallet) en cas de perte ou de dysfonctionnement. Il est de VOTRE responsabilité d'écrire cette série de mots et de la stocker dans un lieu sûr en dehors de l'application Cake Wallet.",
460 "pre_seed_title": "IMPORTANT",
461 + "prepaid_cards": "Cartes prépayées",
462 "prevent_screenshots": "Empêcher les captures d'écran et l'enregistrement d'écran",
463 "privacy": "Confidentialité",
464 "privacy_policy": "Politique de confidentialité",
@@ -467,6 +474,7 @@
474 "purple_dark_theme": "THÈME PURPLE DARK",
475 "qr_fullscreen": "Appuyez pour ouvrir le QR code en mode plein écran",
476 "qr_payment_amount": "Ce QR code contient un montant de paiement. Voulez-vous remplacer la valeur actuelle ?",
477 + "quantity": "Quantité",
478 "question_to_disable_2fa": "Êtes-vous sûr de vouloir désactiver Cake 2FA ? Un code 2FA ne sera plus nécessaire pour accéder au portefeuille (wallet) et à certaines fonctions.",
479 "receivable_balance": "Solde de créances",
480 "receive": "Recevoir",
@@ -708,6 +716,7 @@
716 "tokenID": "IDENTIFIANT",
717 "tor_connection": "Connexion Tor",
718 "tor_only": "Tor uniquement",
719 + "total": "Total",
720 "total_saving": "Économies totales",
721 "totp_2fa_failure": "Code incorrect. Veuillez essayer un code différent ou générer un nouveau secret TOTP. Utilisez une application 2FA compatible qui prend en charge les codes à 8 chiffres et SHA512.",
722 "totp_2fa_success": "Succès! Cake 2FA est activé pour ce portefeuille. N'oubliez pas de sauvegarder votre phrase secrète (seed) au cas où vous perdriez l'accès au portefeuille (wallet).",
@@ -798,6 +807,8 @@
807 "use_ssl": "Utiliser SSL",
808 "use_suggested": "Suivre la suggestion",
809 "use_testnet": "Utiliser TestNet",
810 + "value": "Valeur",
811 + "value_type": "Type de valeur",
812 "variable_pair_not_supported": "Cette paire variable n'est pas prise en charge avec les échanges sélectionnés",
813 "verification": "Vérification",
814 "verify_with_2fa": "Vérifier avec Cake 2FA",
res/values/strings_ha.arb
+13 -2
@@ -87,6 +87,7 @@
87 "buy": "Sayi",
88 "buy_alert_content": "A halin yanzu muna tallafawa kawai siyan Bitcoin, Ethereum, Litecoin, da Monero. Da fatan za a ƙirƙiri ko canza zuwa Bitcoin, Ethereum, Litecoin, ko Monero walat.",
89 "buy_bitcoin": "Sayi Bitcoin",
90 + "buy_now": "Saya yanzu",
91 "buy_provider_unavailable": "Mai ba da kyauta a halin yanzu babu.",
92 "buy_with": "Saya da",
93 "by_cake_pay": "da Cake Pay",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "Cake Dark Jigo",
96 "cake_pay_account_note": "Yi rajista tare da adireshin imel kawai don gani da siyan katunan. Wasu ma suna samuwa a rangwame!",
97 "cake_pay_learn_more": "Nan take siya ku kwaso katunan kyaututtuka a cikin app!\nTake hagu zuwa dama don ƙarin koyo.",
97 - "cake_pay_subtitle": "Sayi katunan kyauta masu rahusa (Amurka kawai)",
98 - "cake_pay_title": "Cake Pay Gift Cards",
98 + "cake_pay_subtitle": "Sayi katunan shirye-shiryen duniya da katunan kyauta",
99 "cake_pay_web_cards_subtitle": "Sayi katunan da aka riga aka biya na duniya da katunan kyauta",
100 "cake_pay_web_cards_title": "Cake Pay Web Cards",
101 "cake_wallet": "Cake Wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "Canja walat yanzu",
124 "choose_account": "Zaɓi asusu",
125 "choose_address": "\n\n Da fatan za a zaɓi adireshin:",
126 + "choose_card_value": "Zabi darajar katin",
127 "choose_derivation": "Zaɓi walatawa",
128 "choose_from_available_options": "Zaɓi daga zaɓuɓɓukan da ake da su:",
129 "choose_one": "Zaɓi ɗaya",
@@ -166,6 +167,7 @@
167 "copy_address": "Kwafi Adireshin",
168 "copy_id": "Kwafi ID",
169 "copyWalletConnectLink": "Kwafi hanyar haɗin WalletConnect daga dApp kuma liƙa a nan",
170 + "countries": "Kasashe",
171 "create_account": "Kirkira ajiya",
172 "create_backup": "Ƙirƙiri madadin",
173 "create_donation_link": "Sanya hanyar sadaka",
@@ -178,6 +180,7 @@
180 "custom": "al'ada",
181 "custom_drag": "Al'ada (riƙe da ja)",
182 "custom_redeem_amount": "Adadin Fansa na Musamman",
183 + "custom_value": "Darajar al'ada",
184 "dark_theme": "Duhu",
185 "debit_card": "Katin Zare kudi",
186 "debit_card_terms": "Adana da amfani da lambar katin kuɗin ku (da takaddun shaida masu dacewa da lambar katin kuɗin ku) a cikin wannan walat ɗin dijital suna ƙarƙashin Sharuɗɗa da Sharuɗɗa na yarjejeniya mai amfani da katin tare da mai fitar da katin biyan kuɗi, kamar yadda yake aiki daga lokaci zuwa lokaci.",
@@ -190,6 +193,7 @@
193 "delete_wallet": "Share walat",
194 "delete_wallet_confirm_message": "Shin kun tabbata cewa kuna son share jakar ${wallet_name}?",
195 "deleteConnectionConfirmationPrompt": "Shin kun tabbata cewa kuna son share haɗin zuwa",
196 + "denominations": "Denominations",
197 "descending": "Saukowa",
198 "description": "Bayani",
199 "destination_tag": "Tambarin makoma:",
@@ -277,6 +281,7 @@
281 "expired": "Karewa",
282 "expires": "Ya ƙare",
283 "expiresOn": "Yana ƙarewa",
284 + "expiry_and_validity": "Karewa da inganci",
285 "export_backup": "Ajiyayyen fitarwa",
286 "extra_id": "Karin ID:",
287 "extracted_address_content": "Za ku aika da kudade zuwa\n${recipient_name}",
@@ -384,6 +389,7 @@
389 "new_template": "Sabon Samfura",
390 "new_wallet": "Sabuwar Wallet",
391 "newConnection": "Sabuwar Haɗi",
392 + "no_cards_found": "Babu katunan da aka samo",
393 "no_id_needed": "Babu ID da ake buƙata!",
394 "no_id_required": "Babu ID da ake buƙata. Yi da kuma ciyar a ko'ina",
395 "no_relay_on_domain": "Babu gudun ba da sanda ga yankin mai amfani ko kuma ba a samu ba. Da fatan za a zaɓi gudun ba da sanda don amfani.",
@@ -454,6 +460,7 @@
460 "pre_seed_button_text": "Ina fahimta. Nuna mini seed din nawa",
461 "pre_seed_description": "A kan shafin nan za ku ga wata ƙungiya na ${words} kalmomi. Wannan shine tsarin daban-daban ku kuma na sirri kuma shine hanya ɗaya kadai don mai da purse dinku a cikin yanayin rasa ko rashin aiki. Yana da damar da kuke a cikin tabbatar da kuyi rubuta shi kuma kuyi ajiye shi a wuri na aminci wanda ya wuce wurin app na Cake Wallet.",
462 "pre_seed_title": "MUHIMMANCI",
463 + "prepaid_cards": "Katunan shirye-shirye",
464 "prevent_screenshots": "Fada lambobi da jarrabobi na kayan lambobi",
465 "privacy": "Keɓantawa",
466 "privacy_policy": "takardar kebantawa",
@@ -469,6 +476,7 @@
476 "purple_dark_theme": "M duhu jigo",
477 "qr_fullscreen": "Matsa don buɗe lambar QR na cikakken allo",
478 "qr_payment_amount": "Wannan QR code yana da adadin kuɗi. Kuna so ku overwrite wannan adadi?",
479 + "quantity": "Yawa",
480 "question_to_disable_2fa": "Ka tabbata cewa kana son kashe cake 2fa? Ba za a sake buƙatar lambar 2FA ba don samun damar yin walat da takamaiman ayyuka.",
481 "receivable_balance": "Daidaituwa da daidaituwa",
482 "receive": "Samu",
@@ -710,6 +718,7 @@
718 "tokenID": "ID",
719 "tor_connection": "Tor haɗin gwiwa",
720 "tor_only": "Tor kawai",
721 + "total": "Duka",
722 "total_saving": "Jimlar Adana",
723 "totp_2fa_failure": "Ba daidai ba. Da fatan za a gwada wata lamba ta daban ko samar da sabon maɓallin asirin. Yi amfani da aikace-aikacen da ya dace 2FA wanda ke tallafawa lambobin lambobi 8 da Sha512.",
724 "totp_2fa_success": "Nasara! Cake 2FA ya dogara da wannan waljin. Ka tuna domin adana zuriyar mnemmonic naka idan ka rasa damar walat.",
@@ -800,6 +809,8 @@
809 "use_ssl": "Yi amfani da SSL",
810 "use_suggested": "Amfani da Shawarwari",
811 "use_testnet": "Amfani da gwaji",
812 + "value": "Daraja",
813 + "value_type": "Nau'in darajar",
814 "variable_pair_not_supported": "Ba a samun goyan bayan wannan m biyu tare da zaɓaɓɓun musayar",
815 "verification": "tabbatar",
816 "verify_with_2fa": "Tabbatar da Cake 2FA",
res/values/strings_hi.arb
+13 -2
@@ -87,6 +87,7 @@
87 "buy": "खरीदें",
88 "buy_alert_content": "वर्तमान में हम केवल बिटकॉइन, एथेरियम, लाइटकॉइन और मोनेरो की खरीद का समर्थन करते हैं। कृपया अपना बिटकॉइन, एथेरियम, लाइटकॉइन, या मोनेरो वॉलेट बनाएं या उस पर स्विच करें।",
89 "buy_bitcoin": "बिटकॉइन खरीदें",
90 + "buy_now": "अभी खरीदें",
91 "buy_provider_unavailable": "वर्तमान में प्रदाता अनुपलब्ध है।",
92 "buy_with": "के साथ खरीदें",
93 "by_cake_pay": "केकपे द्वारा",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "केक डार्क थीम",
96 "cake_pay_account_note": "कार्ड देखने और खरीदने के लिए केवल एक ईमेल पते के साथ साइन अप करें। कुछ छूट पर भी उपलब्ध हैं!",
97 "cake_pay_learn_more": "ऐप में उपहार कार्ड तुरंत खरीदें और रिडीम करें!\nअधिक जानने के लिए बाएं से दाएं स्वाइप करें।",
97 - "cake_pay_subtitle": "रियायती उपहार कार्ड खरीदें (केवल यूएसए)",
98 - "cake_pay_title": "केक पे गिफ्ट कार्ड्स",
98 + "cake_pay_subtitle": "दुनिया भर में प्रीपेड कार्ड और उपहार कार्ड खरीदें",
99 "cake_pay_web_cards_subtitle": "दुनिया भर में प्रीपेड कार्ड और गिफ्ट कार्ड खरीदें",
100 "cake_pay_web_cards_title": "केक भुगतान वेब कार्ड",
101 "cake_wallet": "Cake Wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "वर्तमान बटुआ बदलें",
124 "choose_account": "खाता चुनें",
125 "choose_address": "\n\nकृपया पता चुनें:",
126 + "choose_card_value": "एक कार्ड मूल्य चुनें",
127 "choose_derivation": "वॉलेट व्युत्पत्ति चुनें",
128 "choose_from_available_options": "उपलब्ध विकल्पों में से चुनें:",
129 "choose_one": "एक का चयन",
@@ -166,6 +167,7 @@
167 "copy_address": "पता कॉपी करें",
168 "copy_id": "प्रतिलिपि ID",
169 "copyWalletConnectLink": "dApp से वॉलेटकनेक्ट लिंक को कॉपी करें और यहां पेस्ट करें",
170 + "countries": "देशों",
171 "create_account": "खाता बनाएं",
172 "create_backup": "बैकअप बनाएँ",
173 "create_donation_link": "दान लिंक बनाएं",
@@ -178,6 +180,7 @@
180 "custom": "कस्टम",
181 "custom_drag": "कस्टम (पकड़ और खींचें)",
182 "custom_redeem_amount": "कस्टम रिडीम राशि",
183 + "custom_value": "कस्टम मूल्य",
184 "dark_theme": "अंधेरा",
185 "debit_card": "डेबिट कार्ड",
186 "debit_card_terms": "इस डिजिटल वॉलेट में आपके भुगतान कार्ड नंबर (और आपके भुगतान कार्ड नंबर से संबंधित क्रेडेंशियल) का भंडारण और उपयोग भुगतान कार्ड जारीकर्ता के साथ लागू कार्डधारक समझौते के नियमों और शर्तों के अधीन है, जैसा कि प्रभावी है समय - समय पर।",
@@ -190,6 +193,7 @@
193 "delete_wallet": "वॉलेट हटाएं",
194 "delete_wallet_confirm_message": "क्या आप वाकई ${wallet_name} वॉलेट हटाना चाहते हैं?",
195 "deleteConnectionConfirmationPrompt": "क्या आप वाकई कनेक्शन हटाना चाहते हैं?",
196 + "denominations": "मूल्यवर्ग",
197 "descending": "अवरोही",
198 "description": "विवरण",
199 "destination_tag": "गंतव्य टैग:",
@@ -277,6 +281,7 @@
281 "expired": "समय सीमा समाप्त",
282 "expires": "समाप्त हो जाता है",
283 "expiresOn": "पर समय सीमा समाप्त",
284 + "expiry_and_validity": "समाप्ति और वैधता",
285 "export_backup": "निर्यात बैकअप",
286 "extra_id": "अतिरिक्त आईडी:",
287 "extracted_address_content": "आपको धनराशि भेजी जाएगी\n${recipient_name}",
@@ -384,6 +389,7 @@
389 "new_template": "नया टेम्पलेट",
390 "new_wallet": "नया बटुआ",
391 "newConnection": "नया कनेक्शन",
392 + "no_cards_found": "कोई कार्ड नहीं मिला",
393 "no_id_needed": "कोई आईडी नहीं चाहिए!",
394 "no_id_required": "कोई आईडी आवश्यक नहीं है। टॉप अप करें और कहीं भी खर्च करें",
395 "no_relay_on_domain": "उपयोगकर्ता के डोमेन के लिए कोई रिले नहीं है या रिले अनुपलब्ध है। कृपया उपयोग करने के लिए एक रिले चुनें।",
@@ -453,6 +459,7 @@
459 "pre_seed_button_text": "मै समझता हुँ। मुझे अपना बीज दिखाओ",
460 "pre_seed_description": "अगले पेज पर आपको ${words} शब्दों की एक श्रृंखला दिखाई देगी। यह आपका अद्वितीय और निजी बीज है और नुकसान या खराबी के मामले में अपने बटुए को पुनर्प्राप्त करने का एकमात्र तरीका है। यह आपकी जिम्मेदारी है कि इसे नीचे लिखें और इसे Cake Wallet ऐप के बाहर सुरक्षित स्थान पर संग्रहीत करें।",
461 "pre_seed_title": "महत्वपूर्ण",
462 + "prepaid_cards": "पूर्वदत्त कार्ड",
463 "prevent_screenshots": "स्क्रीनशॉट और स्क्रीन रिकॉर्डिंग रोकें",
464 "privacy": "गोपनीयता",
465 "privacy_policy": "गोपनीयता नीति",
@@ -468,6 +475,7 @@
475 "purple_dark_theme": "पर्पल डार्क थीम",
476 "qr_fullscreen": "फ़ुल स्क्रीन क्यूआर कोड खोलने के लिए टैप करें",
477 "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?",
478 + "quantity": "मात्रा",
479 "question_to_disable_2fa": "क्या आप सुनिश्चित हैं कि आप Cake 2FA को अक्षम करना चाहते हैं? वॉलेट और कुछ कार्यों तक पहुँचने के लिए अब 2FA कोड की आवश्यकता नहीं होगी।",
480 "ready_have_account": "क्या आपके पास पहले से ही एक खाता है?",
481 "receivable_balance": "प्राप्य शेष",
@@ -710,6 +718,7 @@
718 "tokenID": "पहचान",
719 "tor_connection": "टोर कनेक्शन",
720 "tor_only": "Tor केवल",
721 + "total": "कुल",
722 "total_saving": "कुल बचत",
723 "totp_2fa_failure": "गलत कोड़। कृपया एक अलग कोड का प्रयास करें या एक नई गुप्त कुंजी उत्पन्न करें। 8-अंकीय कोड और SHA512 का समर्थन करने वाले संगत 2FA ऐप का उपयोग करें।",
724 "totp_2fa_success": "सफलता! इस वॉलेट के लिए Cake 2FA सक्षम है। यदि आप वॉलेट एक्सेस खो देते हैं तो अपने स्मरक बीज को सहेजना याद रखें।",
@@ -800,6 +809,8 @@
809 "use_ssl": "उपयोग SSL",
810 "use_suggested": "सुझाए गए का प्रयोग करें",
811 "use_testnet": "टेस्टनेट का उपयोग करें",
812 + "value": "कीमत",
813 + "value_type": "मान प्रकार",
814 "variable_pair_not_supported": "यह परिवर्तनीय जोड़ी चयनित एक्सचेंजों के साथ समर्थित नहीं है",
815 "verification": "सत्यापन",
816 "verify_with_2fa": "केक 2FA के साथ सत्यापित करें",
res/values/strings_hr.arb
+14 -3
@@ -87,6 +87,7 @@
87 "buy": "Kupi",
88 "buy_alert_content": "Trenutno podržavamo samo kupnju Bitcoina, Ethereuma, Litecoina i Monera. Izradite ili prijeđite na svoj Bitcoin, Ethereum, Litecoin ili Monero novčanik.",
89 "buy_bitcoin": "Kupite Bitcoin",
90 + "buy_now": "Kupi sada",
91 "buy_provider_unavailable": "Davatelj trenutno nije dostupan.",
92 "buy_with": "Kupite s",
93 "by_cake_pay": "od Cake Paya",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "TOKA DARKA TEMA",
96 "cake_pay_account_note": "Prijavite se samo s adresom e-pošte da biste vidjeli i kupili kartice. Neke su čak dostupne uz popust!",
97 "cake_pay_learn_more": "Azonnal vásárolhat és válthat be ajándékutalványokat az alkalmazásban!\nTovábbi információért csúsztassa balról jobbra az ujját.",
97 - "cake_pay_subtitle": "Kupite darovne kartice s popustom (samo SAD)",
98 - "cake_pay_title": "Cake Pay poklon kartice",
98 + "cake_pay_subtitle": "Kupite svjetske unaprijed plaćene kartice i poklon kartice",
99 "cake_pay_web_cards_subtitle": "Kupujte prepaid kartice i poklon kartice diljem svijeta",
100 "cake_pay_web_cards_title": "Cake Pay Web kartice",
101 "cake_wallet": "Cake Wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "Izmijeni trenutni novčanik",
124 "choose_account": "Odaberi račun",
125 "choose_address": "\n\nOdaberite adresu:",
126 + "choose_card_value": "Odaberite vrijednost kartice",
127 "choose_derivation": "Odaberite izvedbu novčanika",
128 "choose_from_available_options": "Odaberite neku od dostupnih opcija:",
129 "choose_one": "Izaberi jedan",
@@ -166,6 +167,7 @@
167 "copy_address": "Kopiraj adresu",
168 "copy_id": "Kopirati ID",
169 "copyWalletConnectLink": "Kopirajte vezu WalletConnect iz dApp-a i zalijepite je ovdje",
170 + "countries": "Zemalja",
171 "create_account": "Stvori račun",
172 "create_backup": "Stvori sigurnosnu kopiju",
173 "create_donation_link": "Izradi poveznicu za donaciju",
@@ -178,6 +180,7 @@
180 "custom": "prilagođeno",
181 "custom_drag": "Prilagođeni (držite i povucite)",
182 "custom_redeem_amount": "Prilagođeni iznos otkupa",
183 + "custom_value": "Prilagođena vrijednost",
184 "dark_theme": "Tamna",
185 "debit_card": "Debitna kartica",
186 "debit_card_terms": "Pohranjivanje i korištenje broja vaše platne kartice (i vjerodajnica koje odgovaraju broju vaše platne kartice) u ovom digitalnom novčaniku podliježu Uvjetima i odredbama važećeg ugovora vlasnika kartice s izdavateljem platne kartice, koji su na snazi ​​od S vremena na vrijeme.",
@@ -190,6 +193,7 @@
193 "delete_wallet": "Izbriši novčanik",
194 "delete_wallet_confirm_message": "Jeste li sigurni da želite izbrisati ${wallet_name} novčanik?",
195 "deleteConnectionConfirmationPrompt": "Jeste li sigurni da želite izbrisati vezu s",
196 + "denominations": "Denominacije",
197 "descending": "Silazni",
198 "description": "Opis",
199 "destination_tag": "Odredišna oznaka:",
@@ -277,6 +281,7 @@
281 "expired": "Isteklo",
282 "expires": "Ističe",
283 "expiresOn": "Istječe",
284 + "expiry_and_validity": "Istek i valjanost",
285 "export_backup": "Izvezi sigurnosnu kopiju",
286 "extra_id": "Dodatni ID:",
287 "extracted_address_content": "Poslat ćete sredstva primatelju\n${recipient_name}",
@@ -308,7 +313,7 @@
313 "gift_card_is_generated": "Poklon kartica je generirana",
314 "gift_card_number": "Broj darovne kartice",
315 "gift_card_redeemed_note": "Poklon kartice koje ste iskoristili pojavit će se ovdje",
311 - "gift_cards": "Ajándékkártya",
316 + "gift_cards": "Darovne kartice",
317 "gift_cards_unavailable": "Poklon kartice trenutno su dostupne za kupnju samo putem Monera, Bitcoina i Litecoina",
318 "got_it": "U redu",
319 "gross_balance": "Bruto bilanca",
@@ -384,6 +389,7 @@
389 "new_template": "novi predložak",
390 "new_wallet": "Novi novčanik",
391 "newConnection": "Nova veza",
392 + "no_cards_found": "Nisu pronađene kartice",
393 "no_id_needed": "Nije potreban ID!",
394 "no_id_required": "Nije potreban ID. Nadopunite i potrošite bilo gdje",
395 "no_relay_on_domain": "Ne postoji relej za korisničku domenu ili je relej nedostupan. Odaberite relej za korištenje.",
@@ -452,6 +458,7 @@
458 "pre_seed_button_text": "Razumijem. Prikaži mi moj pristupni izraz",
459 "pre_seed_description": "Na sljedećoj ćete stranici vidjeti niz ${words} riječi. Radi se o Vašem jedinstvenom i tajnom pristupnom izrazu koji je ujedno i JEDINI način na koji možete oporaviti svoj novčanik u slučaju gubitka ili kvara. VAŠA je odgovornost zapisati ga te pohraniti na sigurno mjesto izvan Cake Wallet aplikacije.",
460 "pre_seed_title": "VAŽNO",
461 + "prepaid_cards": "Unaprijed plaćene kartice",
462 "prevent_screenshots": "Spriječite snimke zaslona i snimanje zaslona",
463 "privacy": "Privatnost",
464 "privacy_policy": "Pravila privatnosti",
@@ -467,6 +474,7 @@
474 "purple_dark_theme": "Ljubičasta tamna tema",
475 "qr_fullscreen": "Dodirnite za otvaranje QR koda preko cijelog zaslona",
476 "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?",
477 + "quantity": "Količina",
478 "question_to_disable_2fa": "Jeste li sigurni da želite onemogućiti Cake 2FA? 2FA kod više neće biti potreban za pristup novčaniku i određenim funkcijama.",
479 "receivable_balance": "Stanje potraživanja",
480 "receive": "Primi",
@@ -708,6 +716,7 @@
716 "tokenID": "iskaznica",
717 "tor_connection": "Tor veza",
718 "tor_only": "Samo Tor",
719 + "total": "Ukupno",
720 "total_saving": "Ukupna ušteda",
721 "totp_2fa_failure": "Neispravan kod. Pokušajte s drugim kodom ili generirajte novi tajni ključ. Koristite kompatibilnu 2FA aplikaciju koja podržava 8-znamenkasti kod i SHA512.",
722 "totp_2fa_success": "Uspjeh! Cake 2FA omogućen za ovaj novčanik. Ne zaboravite spremiti svoje mnemoničko sjeme u slučaju da izgubite pristup novčaniku.",
@@ -798,6 +807,8 @@
807 "use_ssl": "Koristi SSL",
808 "use_suggested": "Koristite predloženo",
809 "use_testnet": "Koristite TestNet",
810 + "value": "Vrijednost",
811 + "value_type": "Tipa vrijednosti",
812 "variable_pair_not_supported": "Ovaj par varijabli nije podržan s odabranim burzama",
813 "verification": "Potvrda",
814 "verify_with_2fa": "Provjerite s Cake 2FA",
res/values/strings_id.arb
+14 -3
@@ -87,6 +87,7 @@
87 "buy": "Beli",
88 "buy_alert_content": "Saat ini kami hanya mendukung pembelian Bitcoin, Ethereum, Litecoin, dan Monero. Harap buat atau alihkan ke dompet Bitcoin, Ethereum, Litecoin, atau Monero Anda.",
89 "buy_bitcoin": "Beli Bitcoin",
90 + "buy_now": "Beli sekarang",
91 "buy_provider_unavailable": "Penyedia saat ini tidak tersedia.",
92 "buy_with": "Beli dengan",
93 "by_cake_pay": "oleh Cake Pay",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "Tema Kue Gelap",
96 "cake_pay_account_note": "Daftar hanya dengan alamat email untuk melihat dan membeli kartu. Beberapa di antaranya bahkan tersedia dengan diskon!",
97 "cake_pay_learn_more": "Beli dan tukar kartu hadiah secara instan di aplikasi!\nGeser ke kanan untuk informasi lebih lanjut.",
97 - "cake_pay_subtitle": "Beli kartu hadiah dengan harga diskon (hanya USA)",
98 - "cake_pay_title": "Kartu Hadiah Cake Pay",
98 + "cake_pay_subtitle": "Beli kartu prabayar di seluruh dunia dan kartu hadiah",
99 "cake_pay_web_cards_subtitle": "Beli kartu prabayar dan kartu hadiah secara global",
100 "cake_pay_web_cards_title": "Kartu Web Cake Pay",
101 "cake_wallet": "Cake Wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "Ganti dompet saat ini",
124 "choose_account": "Pilih akun",
125 "choose_address": "\n\nSilakan pilih alamat:",
126 + "choose_card_value": "Pilih nilai kartu",
127 "choose_derivation": "Pilih dompet dompet",
128 "choose_from_available_options": "Pilih dari pilihan yang tersedia:",
129 "choose_one": "Pilih satu",
@@ -166,6 +167,7 @@
167 "copy_address": "Salin Alamat",
168 "copy_id": "Salin ID",
169 "copyWalletConnectLink": "Salin tautan WalletConnect dari dApp dan tempel di sini",
170 + "countries": "Negara",
171 "create_account": "Buat Akun",
172 "create_backup": "Buat cadangan",
173 "create_donation_link": "Buat tautan donasi",
@@ -178,6 +180,7 @@
180 "custom": "kustom",
181 "custom_drag": "Khusus (tahan dan seret)",
182 "custom_redeem_amount": "Jumlah Tukar Kustom",
183 + "custom_value": "Nilai khusus",
184 "dark_theme": "Gelap",
185 "debit_card": "Kartu Debit",
186 "debit_card_terms": "Penyimpanan dan penggunaan nomor kartu pembayaran Anda (dan kredensial yang sesuai dengan nomor kartu pembayaran Anda) dalam dompet digital ini tertakluk pada Syarat dan Ketentuan persetujuan pemegang kartu yang berlaku dengan penerbit kartu pembayaran, seperti yang berlaku dari waktu ke waktu.",
@@ -190,6 +193,7 @@
193 "delete_wallet": "Hapus dompet",
194 "delete_wallet_confirm_message": "Apakah Anda yakin ingin menghapus dompet ${wallet_name}?",
195 "deleteConnectionConfirmationPrompt": "Apakah Anda yakin ingin menghapus koneksi ke",
196 + "denominations": "Denominasi",
197 "descending": "Menurun",
198 "description": "Keterangan",
199 "destination_tag": "Tag tujuan:",
@@ -277,6 +281,7 @@
281 "expired": "Kedaluwarsa",
282 "expires": "Kadaluarsa",
283 "expiresOn": "Kadaluarsa pada",
284 + "expiry_and_validity": "Kedaluwarsa dan validitas",
285 "export_backup": "Ekspor cadangan",
286 "extra_id": "ID tambahan:",
287 "extracted_address_content": "Anda akan mengirim dana ke\n${recipient_name}",
@@ -308,7 +313,7 @@
313 "gift_card_is_generated": "Kartu Hadiah telah dibuat",
314 "gift_card_number": "Nomor Kartu Hadiah",
315 "gift_card_redeemed_note": "Kartu hadiah yang sudah Anda tukar akan muncul di sini",
311 - "gift_cards": "Kartu Hadiah",
316 + "gift_cards": "Kartu hadiah",
317 "gift_cards_unavailable": "Kartu hadiah hanya tersedia untuk dibeli dengan Monero, Bitcoin, dan Litecoin saat ini",
318 "got_it": "Sudah paham",
319 "gross_balance": "Saldo Kotor",
@@ -384,6 +389,7 @@
389 "new_template": "Template Baru",
390 "new_wallet": "Dompet Baru",
391 "newConnection": "Koneksi Baru",
392 + "no_cards_found": "Tidak ada kartu yang ditemukan",
393 "no_id_needed": "Tidak perlu ID!",
394 "no_id_required": "Tidak perlu ID. Isi ulang dan belanja di mana saja",
395 "no_relay_on_domain": "Tidak ada relai untuk domain pengguna atau relai tidak tersedia. Silakan pilih relai yang akan digunakan.",
@@ -454,6 +460,7 @@
460 "pre_seed_button_text": "Saya mengerti. Tampilkan seed saya",
461 "pre_seed_description": "Di halaman berikutnya Anda akan melihat serangkaian kata ${words}. Ini adalah seed unik dan pribadi Anda dan itu SATU-SATUNYA cara untuk mengembalikan dompet Anda jika hilang atau rusak. Ini adalah TANGGUNG JAWAB Anda untuk menuliskannya dan menyimpan di tempat yang aman di luar aplikasi Cake Wallet.",
462 "pre_seed_title": "PENTING",
463 + "prepaid_cards": "Kartu prabayar",
464 "prevent_screenshots": "Cegah tangkapan layar dan perekaman layar",
465 "privacy": "Privasi",
466 "privacy_policy": "Kebijakan Privasi",
@@ -469,6 +476,7 @@
476 "purple_dark_theme": "Tema gelap ungu",
477 "qr_fullscreen": "Tap untuk membuka layar QR code penuh",
478 "qr_payment_amount": "QR code ini berisi jumlah pembayaran. Apakah Anda ingin menimpa nilai saat ini?",
479 + "quantity": "Kuantitas",
480 "question_to_disable_2fa": "Apakah Anda yakin ingin menonaktifkan Cake 2FA? Kode 2FA tidak lagi diperlukan untuk mengakses dompet dan fungsi tertentu.",
481 "receivable_balance": "Saldo piutang",
482 "receive": "Menerima",
@@ -711,6 +719,7 @@
719 "tokenID": "PENGENAL",
720 "tor_connection": "koneksi Tor",
721 "tor_only": "Hanya Tor",
722 + "total": "Total",
723 "total_saving": "Total Pembayaran",
724 "totp_2fa_failure": "Kode salah. Silakan coba kode lain atau buat kunci rahasia baru. Gunakan aplikasi 2FA yang kompatibel yang mendukung kode 8 digit dan SHA512.",
725 "totp_2fa_success": "Kesuksesan! Cake 2FA diaktifkan untuk dompet ini. Ingatlah untuk menyimpan benih mnemonik Anda jika Anda kehilangan akses dompet.",
@@ -801,6 +810,8 @@
810 "use_ssl": "Gunakan SSL",
811 "use_suggested": "Gunakan yang Disarankan",
812 "use_testnet": "Gunakan TestNet",
813 + "value": "Nilai",
814 + "value_type": "Jenis Nilai",
815 "variable_pair_not_supported": "Pasangan variabel ini tidak didukung dengan bursa yang dipilih",
816 "verification": "Verifikasi",
817 "verify_with_2fa": "Verifikasi dengan Cake 2FA",
res/values/strings_it.arb
+13 -2
@@ -87,6 +87,7 @@
87 "buy": "Comprare",
88 "buy_alert_content": "Attualmente supportiamo solo l'acquisto di Bitcoin, Ethereum, Litecoin e Monero. Crea o passa al tuo portafoglio Bitcoin, Ethereum, Litecoin o Monero.",
89 "buy_bitcoin": "Acquista Bitcoin",
90 + "buy_now": "Acquista ora",
91 "buy_provider_unavailable": "Provider attualmente non disponibile.",
92 "buy_with": "Acquista con",
93 "by_cake_pay": "da Cake Pay",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "Tema oscuro della torta",
96 "cake_pay_account_note": "Iscriviti con solo un indirizzo email per vedere e acquistare le carte. Alcune sono anche disponibili con uno sconto!",
97 "cake_pay_learn_more": "Acquista e riscatta istantaneamente carte regalo nell'app!\nScorri da sinistra a destra per saperne di più.",
97 - "cake_pay_subtitle": "Acquista buoni regalo scontati (solo USA)",
98 - "cake_pay_title": "Carte regalo Cake Pay",
98 + "cake_pay_subtitle": "Acquista carte prepagate in tutto il mondo e carte regalo",
99 "cake_pay_web_cards_subtitle": "Acquista carte prepagate e carte regalo in tutto il mondo",
100 "cake_pay_web_cards_title": "Carte Web Cake Pay",
101 "cake_wallet": "Cake Wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "Cambia portafoglio attuale",
124 "choose_account": "Scegli account",
125 "choose_address": "\n\nSi prega di scegliere l'indirizzo:",
126 + "choose_card_value": "Scegli un valore della carta",
127 "choose_derivation": "Scegli la derivazione del portafoglio",
128 "choose_from_available_options": "Scegli tra le opzioni disponibili:",
129 "choose_one": "Scegline uno",
@@ -167,6 +168,7 @@
168 "copy_address": "Copia Indirizzo",
169 "copy_id": "Copia ID",
170 "copyWalletConnectLink": "Copia il collegamento WalletConnect dalla dApp e incollalo qui",
171 + "countries": "Paesi",
172 "create_account": "Crea account",
173 "create_backup": "Crea backup",
174 "create_donation_link": "Crea un link per la donazione",
@@ -179,6 +181,7 @@
181 "custom": "personalizzato",
182 "custom_drag": "Custom (Hold and Drag)",
183 "custom_redeem_amount": "Importo di riscatto personalizzato",
184 + "custom_value": "Valore personalizzato",
185 "dark_theme": "Scuro",
186 "debit_card": "Carta di debito",
187 "debit_card_terms": "L'archiviazione e l'utilizzo del numero della carta di pagamento (e delle credenziali corrispondenti al numero della carta di pagamento) in questo portafoglio digitale sono soggetti ai Termini e condizioni del contratto applicabile con il titolare della carta con l'emittente della carta di pagamento, come in vigore da tempo al tempo.",
@@ -191,6 +194,7 @@
194 "delete_wallet": "Elimina portafoglio",
195 "delete_wallet_confirm_message": "Sei sicuro di voler eliminare il portafoglio ${wallet_name}?",
196 "deleteConnectionConfirmationPrompt": "Sei sicuro di voler eliminare la connessione a",
197 + "denominations": "Denominazioni",
198 "descending": "Discendente",
199 "description": "Descrizione",
200 "destination_tag": "Tag destinazione:",
@@ -278,6 +282,7 @@
282 "expired": "Scaduta",
283 "expires": "Scade",
284 "expiresOn": "Scade il",
285 + "expiry_and_validity": "Scadenza e validità",
286 "export_backup": "Esporta backup",
287 "extra_id": "Extra ID:",
288 "extracted_address_content": "Invierai i tuoi fondi a\n${recipient_name}",
@@ -385,6 +390,7 @@
390 "new_template": "Nuovo modello",
391 "new_wallet": "Nuovo Portafoglio",
392 "newConnection": "Nuova connessione",
393 + "no_cards_found": "Nessuna carta trovata",
394 "no_id_needed": "Nessun ID necessario!",
395 "no_id_required": "Nessun ID richiesto. Ricarica e spendi ovunque",
396 "no_relay_on_domain": "Non esiste un inoltro per il dominio dell'utente oppure l'inoltro non è disponibile. Scegli un relè da utilizzare.",
@@ -454,6 +460,7 @@
460 "pre_seed_button_text": "Ho capito. Mostrami il seme",
461 "pre_seed_description": "Nella pagina seguente ti sarà mostrata una serie di parole ${words}. Questo è il tuo seme unico e privato ed è l'UNICO modo per recuperare il tuo portafoglio in caso di perdita o malfunzionamento. E' TUA responsabilità trascriverlo e conservarlo in un posto sicuro fuori dall'app Cake Wallet.",
462 "pre_seed_title": "IMPORTANTE",
463 + "prepaid_cards": "Carte prepagata",
464 "prevent_screenshots": "Impedisci screenshot e registrazione dello schermo",
465 "privacy": "Privacy",
466 "privacy_policy": "Informativa sulla privacy",
@@ -469,6 +476,7 @@
476 "purple_dark_theme": "Tema oscuro viola",
477 "qr_fullscreen": "Tocca per aprire il codice QR a schermo intero",
478 "qr_payment_amount": "Questo codice QR contiene l'ammontare del pagamento. Vuoi sovrascrivere il varlore attuale?",
479 + "quantity": "Quantità",
480 "question_to_disable_2fa": "Sei sicuro di voler disabilitare Cake 2FA? Non sarà più necessario un codice 2FA per accedere al portafoglio e ad alcune funzioni.",
481 "receivable_balance": "Bilanciamento creditizio",
482 "receive": "Ricevi",
@@ -710,6 +718,7 @@
718 "tokenID": "ID",
719 "tor_connection": "Connessione Tor",
720 "tor_only": "Solo Tor",
721 + "total": "Totale",
722 "total_saving": "Risparmio totale",
723 "totp_2fa_failure": "Codice non corretto. Prova un codice diverso o genera una nuova chiave segreta. Utilizza un'app 2FA compatibile che supporti codici a 8 cifre e SHA512.",
724 "totp_2fa_success": "Successo! Cake 2FA abilitato per questo portafoglio. Ricordati di salvare il tuo seme mnemonico nel caso in cui perdi l'accesso al portafoglio.",
@@ -800,6 +809,8 @@
809 "use_ssl": "Usa SSL",
810 "use_suggested": "Usa suggerito",
811 "use_testnet": "Usa TestNet",
812 + "value": "Valore",
813 + "value_type": "Tipo di valore",
814 "variable_pair_not_supported": "Questa coppia di variabili non è supportata con gli scambi selezionati",
815 "verification": "Verifica",
816 "verify_with_2fa": "Verifica con Cake 2FA",
res/values/strings_ja.arb
+13 -2
@@ -87,6 +87,7 @@
87 "buy": "購入",
88 "buy_alert_content": "現在、ビットコイン、イーサリアム、ライトコイン、モネロの購入のみをサポートしています。ビットコイン、イーサリアム、ライトコイン、またはモネロのウォレットを作成するか、これらのウォレットに切り替えてください。",
89 "buy_bitcoin": "ビットコインを購入する",
90 + "buy_now": "今すぐ購入",
91 "buy_provider_unavailable": "現在、プロバイダーは利用できません。",
92 "buy_with": "で購入",
93 "by_cake_pay": "by Cake Pay",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "ケーキ暗いテーマ",
96 "cake_pay_account_note": "メールアドレスだけでサインアップして、カードを表示して購入できます。割引価格で利用できるカードもあります!",
97 "cake_pay_learn_more": "アプリですぐにギフトカードを購入して引き換えましょう!\n左から右にスワイプして詳細をご覧ください。",
97 - "cake_pay_subtitle": "割引ギフトカードを購入する (米国のみ)",
98 - "cake_pay_title": "ケーキペイギフトカード",
98 + "cake_pay_subtitle": "世界中のプリペイドカードとギフトカードを購入します",
99 "cake_pay_web_cards_subtitle": "世界中のプリペイド カードとギフト カードを購入する",
100 "cake_pay_web_cards_title": "Cake Pay ウェブカード",
101 "cake_wallet": "Cake Wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "現在のウォレットを変更する",
124 "choose_account": "アカウントを選択",
125 "choose_address": "\n\n住所を選択してください:",
126 + "choose_card_value": "カード値を選択します",
127 "choose_derivation": "ウォレット派生を選択します",
128 "choose_from_available_options": "利用可能なオプションから選択してください:",
129 "choose_one": "1 つ選択してください",
@@ -166,6 +167,7 @@
167 "copy_address": "住所をコピー",
168 "copy_id": "IDをコピー",
169 "copyWalletConnectLink": "dApp から WalletConnect リンクをコピーし、ここに貼り付けます",
170 + "countries": "国",
171 "create_account": "アカウントの作成",
172 "create_backup": "バックアップを作成",
173 "create_donation_link": "寄付リンクを作成",
@@ -178,6 +180,7 @@
180 "custom": "カスタム",
181 "custom_drag": "カスタム(ホールドとドラッグ)",
182 "custom_redeem_amount": "カスタム交換金額",
183 + "custom_value": "カスタム値",
184 "dark_theme": "闇",
185 "debit_card": "デビットカード",
186 "debit_card_terms": "このデジタルウォレットでの支払いカード番号(および支払いカード番号に対応する資格情報)の保存と使用には、支払いカード発行者との該当するカード所有者契約の利用規約が適用されます。時々。",
@@ -190,6 +193,7 @@
193 "delete_wallet": "ウォレットを削除",
194 "delete_wallet_confirm_message": "${wallet_name} ウォレットを削除してもよろしいですか?",
195 "deleteConnectionConfirmationPrompt": "への接続を削除してもよろしいですか?",
196 + "denominations": "宗派",
197 "descending": "下降",
198 "description": "説明",
199 "destination_tag": "宛先タグ:",
@@ -277,6 +281,7 @@
281 "expired": "期限切れ",
282 "expires": "Expires",
283 "expiresOn": "有効期限は次のとおりです",
284 + "expiry_and_validity": "有効期限と有効性",
285 "export_backup": "バックアップのエクスポート",
286 "extra_id": "追加ID:",
287 "extracted_address_content": "に送金します\n${recipient_name}",
@@ -385,6 +390,7 @@
390 "new_template": "新しいテンプレート",
391 "new_wallet": "新しいウォレット",
392 "newConnection": "新しい接続",
393 + "no_cards_found": "カードは見つかりません",
394 "no_id_needed": "IDは必要ありません!",
395 "no_id_required": "IDは必要ありません。どこにでも補充して使用できます",
396 "no_relay_on_domain": "ユーザーのドメインのリレーが存在しないか、リレーが使用できません。使用するリレーを選択してください。",
@@ -453,6 +459,7 @@
459 "pre_seed_button_text": "わかります。 種を見せて",
460 "pre_seed_description": "次のページでは、一連の${words}語が表示されます。 これはあなたのユニークでプライベートなシードであり、紛失や誤動作が発生した場合にウォレットを回復する唯一の方法です。 それを書き留めて、Cake Wallet アプリの外の安全な場所に保管するのはあなたの責任です。",
461 "pre_seed_title": "重要",
462 + "prepaid_cards": "プリペイドカード",
463 "prevent_screenshots": "スクリーンショットと画面録画を防止する",
464 "privacy": "プライバシー",
465 "privacy_policy": "プライバシーポリシー",
@@ -468,6 +475,7 @@
475 "purple_dark_theme": "紫色の暗いテーマ",
476 "qr_fullscreen": "タップして全画面QRコードを開く",
477 "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?",
478 + "quantity": "量",
479 "question_to_disable_2fa": "Cake 2FA を無効にしてもよろしいですか?ウォレットと特定の機能にアクセスするために 2FA コードは必要なくなります。",
480 "receivable_balance": "売掛金残高",
481 "receive": "受け取る",
@@ -709,6 +717,7 @@
717 "tokenID": "ID",
718 "tor_connection": "Tor接続",
719 "tor_only": "Torのみ",
720 + "total": "合計",
721 "total_saving": "合計節約額",
722 "totp_2fa_failure": "コードが正しくありません。 別のコードを試すか、新しい秘密鍵を生成してください。 8 桁のコードと SHA512 をサポートする互換性のある 2FA アプリを使用してください。",
723 "totp_2fa_success": "成功!このウォレットでは Cake 2FA が有効になっています。ウォレットへのアクセスを失った場合に備えて、ニーモニック シードを忘れずに保存してください。",
@@ -799,6 +808,8 @@
808 "use_ssl": "SSLを使用する",
809 "use_suggested": "推奨を使用",
810 "use_testnet": "テストネットを使用します",
811 + "value": "価値",
812 + "value_type": "値タイプ",
813 "variable_pair_not_supported": "この変数ペアは、選択した取引所ではサポートされていません",
814 "verification": "検証",
815 "verify_with_2fa": "Cake 2FA で検証する",
res/values/strings_ko.arb
+13 -2
@@ -87,6 +87,7 @@
87 "buy": "구입",
88 "buy_alert_content": "현재 Bitcoin, Ethereum, Litecoin 및 Monero 구매만 지원합니다. Bitcoin, Ethereum, Litecoin 또는 Monero 지갑을 생성하거나 전환하십시오.",
89 "buy_bitcoin": "비트 코인 구매",
90 + "buy_now": "지금 구매하십시오",
91 "buy_provider_unavailable": "제공자는 현재 사용할 수 없습니다.",
92 "buy_with": "구매",
93 "by_cake_pay": "Cake Pay로",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "케이크 다크 테마",
96 "cake_pay_account_note": "이메일 주소로 가입하면 카드를 보고 구매할 수 있습니다. 일부는 할인된 가격으로 사용 가능합니다!",
97 "cake_pay_learn_more": "앱에서 즉시 기프트 카드를 구매하고 사용하세요!\n자세히 알아보려면 왼쪽에서 오른쪽으로 스와이프하세요.",
97 - "cake_pay_subtitle": "할인된 기프트 카드 구매(미국만 해당)",
98 - "cake_pay_title": "케이크 페이 기프트 카드",
98 + "cake_pay_subtitle": "전세계 선불 카드와 기프트 카드를 구입하십시오",
99 "cake_pay_web_cards_subtitle": "전 세계 선불 카드 및 기프트 카드 구매",
100 "cake_pay_web_cards_title": "케이크페이 웹카드",
101 "cake_wallet": "Cake Wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "현재 지갑 변경",
124 "choose_account": "계정을 선택하십시오",
125 "choose_address": "\n\n주소를 선택하십시오:",
126 + "choose_card_value": "카드 값을 선택하십시오",
127 "choose_derivation": "지갑 파생을 선택하십시오",
128 "choose_from_available_options": "사용 가능한 옵션에서 선택:",
129 "choose_one": "하나 선택",
@@ -166,6 +167,7 @@
167 "copy_address": "주소 복사",
168 "copy_id": "부 ID",
169 "copyWalletConnectLink": "dApp에서 WalletConnect 링크를 복사하여 여기에 붙여넣으세요.",
170 + "countries": "국가",
171 "create_account": "계정 만들기",
172 "create_backup": "백업 생성",
173 "create_donation_link": "기부 링크 만들기",
@@ -178,6 +180,7 @@
180 "custom": "커스텀",
181 "custom_drag": "사용자 정의 (홀드 앤 드래그)",
182 "custom_redeem_amount": "사용자 지정 상환 금액",
183 + "custom_value": "맞춤 가치",
184 "dark_theme": "어두운",
185 "debit_card": "직불 카드",
186 "debit_card_terms": "이 디지털 지갑에 있는 귀하의 지불 카드 번호(및 귀하의 지불 카드 번호에 해당하는 자격 증명)의 저장 및 사용은 부터 발효되는 지불 카드 발행자와의 해당 카드 소지자 계약의 이용 약관을 따릅니다. 수시로.",
@@ -190,6 +193,7 @@
193 "delete_wallet": "지갑 삭제",
194 "delete_wallet_confirm_message": "${wallet_name} 지갑을 삭제하시겠습니까?",
195 "deleteConnectionConfirmationPrompt": "다음 연결을 삭제하시겠습니까?",
196 + "denominations": "교파",
197 "descending": "내림차순",
198 "description": "설명",
199 "destination_tag": "목적지 태그:",
@@ -277,6 +281,7 @@
281 "expired": "만료",
282 "expires": "만료",
283 "expiresOn": "만료 날짜",
284 + "expiry_and_validity": "만료와 타당성",
285 "export_backup": "백업 내보내기",
286 "extra_id": "추가 ID:",
287 "extracted_address_content": "당신은에 자금을 보낼 것입니다\n${recipient_name}",
@@ -384,6 +389,7 @@
389 "new_template": "새 템플릿",
390 "new_wallet": "새 월렛",
391 "newConnection": "새로운 연결",
392 + "no_cards_found": "카드를 찾지 못했습니다",
393 "no_id_needed": "ID가 필요하지 않습니다!",
394 "no_id_required": "신분증이 필요하지 않습니다. 충전하고 어디에서나 사용하세요",
395 "no_relay_on_domain": "사용자 도메인에 릴레이가 없거나 릴레이를 사용할 수 없습니다. 사용할 릴레이를 선택해주세요.",
@@ -453,6 +459,7 @@
459 "pre_seed_button_text": "이해 했어요. 내 씨앗을 보여줘",
460 "pre_seed_description": "다음 페이지에서 ${words} 개의 단어를 볼 수 있습니다. 이것은 귀하의 고유하고 개인적인 시드이며 분실 또는 오작동시 지갑을 복구하는 유일한 방법입니다. 기록해두고 Cake Wallet 앱 외부의 안전한 장소에 보관하는 것은 귀하의 책임입니다.",
461 "pre_seed_title": "중대한",
462 + "prepaid_cards": "선불 카드",
463 "prevent_screenshots": "스크린샷 및 화면 녹화 방지",
464 "privacy": "프라이버시",
465 "privacy_policy": "개인 정보 보호 정책",
@@ -468,6 +475,7 @@
475 "purple_dark_theme": "보라색 어두운 테마",
476 "qr_fullscreen": "전체 화면 QR 코드를 열려면 탭하세요.",
477 "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?",
478 + "quantity": "수량",
479 "question_to_disable_2fa": "Cake 2FA를 비활성화하시겠습니까? 지갑 및 특정 기능에 액세스하는 데 더 이상 2FA 코드가 필요하지 않습니다.",
480 "receivable_balance": "채권 잔액",
481 "receive": "받다",
@@ -709,6 +717,7 @@
717 "tokenID": "ID",
718 "tor_connection": "토르 연결",
719 "tor_only": "Tor 뿐",
720 + "total": "총",
721 "total_saving": "총 절감액",
722 "totp_2fa_failure": "잘못된 코드입니다. 다른 코드를 시도하거나 새 비밀 키를 생성하십시오. 8자리 코드와 SHA512를 지원하는 호환되는 2FA 앱을 사용하세요.",
723 "totp_2fa_success": "성공! 이 지갑에 케이크 2FA가 활성화되었습니다. 지갑 액세스 권한을 잃을 경우를 대비하여 니모닉 시드를 저장하는 것을 잊지 마십시오.",
@@ -799,6 +808,8 @@
808 "use_ssl": "SSL 사용",
809 "use_suggested": "추천 사용",
810 "use_testnet": "TestNet을 사용하십시오",
811 + "value": "값",
812 + "value_type": "가치 유형",
813 "variable_pair_not_supported": "이 변수 쌍은 선택한 교환에서 지원되지 않습니다.",
814 "verification": "검증",
815 "verify_with_2fa": "케이크 2FA로 확인",
res/values/strings_my.arb
+13 -2
@@ -87,6 +87,7 @@
87 "buy": "ဝယ်ပါ။",
88 "buy_alert_content": "လက်ရှိတွင် ကျွန်ုပ်တို့သည် Bitcoin၊ Ethereum၊ Litecoin နှင့် Monero တို့ကိုသာ ဝယ်ယူမှုကို ပံ့ပိုးပေးပါသည်။ သင်၏ Bitcoin၊ Ethereum၊ Litecoin သို့မဟုတ် Monero ပိုက်ဆံအိတ်ကို ဖန်တီးပါ သို့မဟုတ် ပြောင်းပါ။",
89 "buy_bitcoin": "Bitcoin ကိုဝယ်ပါ။",
90 + "buy_now": "အခုဝယ်ပါ",
91 "buy_provider_unavailable": "လက်ရှိတွင်လက်ရှိမရနိုင်ပါ။",
92 "buy_with": "အတူဝယ်ပါ။",
93 "by_cake_pay": "Cake Pay ဖြင့်",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "ကိတ်မုန့် Dark Theme",
96 "cake_pay_account_note": "ကတ်များကြည့်ရှုဝယ်ယူရန် အီးမေးလ်လိပ်စာတစ်ခုဖြင့် စာရင်းသွင်းပါ။ အချို့ကို လျှော့ဈေးဖြင့်ပင် ရနိုင်သည်။",
97 "cake_pay_learn_more": "အက်ပ်ရှိ လက်ဆောင်ကတ်များကို ချက်ချင်းဝယ်ယူပြီး ကူပွန်ဖြင့် လဲလှယ်ပါ။\nပိုမိုလေ့လာရန် ဘယ်မှညာသို့ ပွတ်ဆွဲပါ။",
97 - "cake_pay_subtitle": "လျှော့စျေးလက်ဆောင်ကတ်များဝယ်ပါ (USA သာ)",
98 - "cake_pay_title": "ကိတ်မုန့်လက်ဆောင်ကတ်များ",
98 + "cake_pay_subtitle": "Worldwide ကြိုတင်ငွေဖြည့်ကဒ်များနှင့်လက်ဆောင်ကဒ်များကို 0 ယ်ပါ",
99 "cake_pay_web_cards_subtitle": "ကမ္ဘာတစ်ဝှမ်း ကြိုတင်ငွေပေးကတ်များနှင့် လက်ဆောင်ကတ်များကို ဝယ်ယူပါ။",
100 "cake_pay_web_cards_title": "Cake Pay ဝဘ်ကတ်များ",
101 "cake_wallet": "Cake ပိုက်ဆံအိတ်",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "လက်ရှိပိုက်ဆံအိတ်ကို ပြောင်းပါ။",
124 "choose_account": "အကောင့်ကို ရွေးပါ။",
125 "choose_address": "\n\nလိပ်စာကို ရွေးပါ-",
126 + "choose_card_value": "ကဒ်တန်ဖိုးတစ်ခုရွေးပါ",
127 "choose_derivation": "ပိုက်ဆံအိတ်ကိုရွေးချယ်ပါ",
128 "choose_from_available_options": "ရနိုင်သောရွေးချယ်မှုများမှ ရွေးပါ-",
129 "choose_one": "တစ်ခုရွေးပါ။",
@@ -166,6 +167,7 @@
167 "copy_address": "လိပ်စာကို ကူးယူပါ။",
168 "copy_id": "ID ကူးယူပါ။",
169 "copyWalletConnectLink": "dApp မှ WalletConnect လင့်ခ်ကို ကူးယူပြီး ဤနေရာတွင် ကူးထည့်ပါ။",
170 + "countries": "နိုင်ငံများ",
171 "create_account": "အကောင့်ပြုလုပ်ပါ",
172 "create_backup": "အရန်သိမ်းခြင်းကို ဖန်တီးပါ။",
173 "create_donation_link": "လှူဒါန်းမှုလင့်ခ်ကို ဖန်တီးပါ။",
@@ -178,6 +180,7 @@
180 "custom": "စိတ်ကြိုက်",
181 "custom_drag": "စိတ်ကြိုက် (Drag)",
182 "custom_redeem_amount": "စိတ်ကြိုက်သုံးငွေပမာဏ",
183 + "custom_value": "စိတ်ကြိုက်တန်ဖိုး",
184 "dark_theme": "မှောငျမိုကျသော",
185 "debit_card": "ဒက်ဘစ်ကတ်",
186 "debit_card_terms": "ဤဒစ်ဂျစ်တယ်ပိုက်ဆံအိတ်ရှိ သင့်ငွေပေးချေမှုကတ်နံပါတ် (နှင့် သင့်ငွေပေးချေကတ်နံပါတ်နှင့် သက်ဆိုင်သောအထောက်အထားများ) ၏ သိုလှောင်မှုနှင့် အသုံးပြုမှုသည် အချိန်အခါနှင့်အမျှ သက်ရောက်မှုရှိသကဲ့သို့ ကတ်ကိုင်ဆောင်ထားသူ၏ သဘောတူညီချက်၏ စည်းကမ်းသတ်မှတ်ချက်များနှင့် ကိုက်ညီပါသည်။",
@@ -190,6 +193,7 @@
193 "delete_wallet": "ပိုက်ဆံအိတ်ကို ဖျက်ပါ။",
194 "delete_wallet_confirm_message": "${wallet_name} ပိုက်ဆံအိတ်ကို ဖျက်လိုသည်မှာ သေချာပါသလား။",
195 "deleteConnectionConfirmationPrompt": "ချိတ်ဆက်မှုကို ဖျက်လိုသည်မှာ သေချာပါသလား။",
196 + "denominations": "ဂိုဏ်းချုပ်ပစ္စည်းများ",
197 "descending": "ဆင်း",
198 "description": "ဖော်ပြချက်",
199 "destination_tag": "ခရီးဆုံးအမှတ်-",
@@ -277,6 +281,7 @@
281 "expired": "သက်တမ်းကုန်သွားပြီ",
282 "expires": "သက်တမ်းကုန်သည်။",
283 "expiresOn": "သက်တမ်းကုန်သည်။",
284 + "expiry_and_validity": "သက်တမ်းကုန်ဆုံးခြင်းနှင့်တရားဝင်မှု",
285 "export_backup": "အရန်ကူးထုတ်ရန်",
286 "extra_id": "အပို ID-",
287 "extracted_address_content": "သင်သည် \n${recipient_name} သို့ ရန်ပုံငွေများ ပေးပို့ပါမည်",
@@ -384,6 +389,7 @@
389 "new_template": "ပုံစံအသစ်",
390 "new_wallet": "ပိုက်ဆံအိတ်အသစ်",
391 "newConnection": "ချိတ်ဆက်မှုအသစ်",
392 + "no_cards_found": "ကဒ်များမရှိပါ",
393 "no_id_needed": "ID မလိုအပ်ပါ။",
394 "no_id_required": "ID မလိုအပ်ပါ။ ငွေဖြည့်ပြီး ဘယ်နေရာမဆို သုံးစွဲပါ။",
395 "no_relay_on_domain": "အသုံးပြုသူ၏ဒိုမိန်းအတွက် ထပ်ဆင့်လွှင့်ခြင်း မရှိပါ သို့မဟုတ် ထပ်ဆင့်လွှင့်ခြင်း မရနိုင်ပါ။ အသုံးပြုရန် relay ကိုရွေးချယ်ပါ။",
@@ -452,6 +458,7 @@
458 "pre_seed_button_text": "ကျွန်တော်နားလည်ပါတယ်။ ငါ့အမျိုးအနွယ်ကို ပြလော့",
459 "pre_seed_description": "နောက်စာမျက်နှာတွင် ${words} စကားလုံးများ အတွဲလိုက်ကို တွေ့ရပါမည်။ ၎င်းသည် သင်၏ထူးခြားပြီး သီးသန့်မျိုးစေ့ဖြစ်ပြီး ပျောက်ဆုံးခြင်း သို့မဟုတ် ချွတ်ယွင်းမှုရှိပါက သင့်ပိုက်ဆံအိတ်ကို ပြန်လည်ရယူရန် တစ်ခုတည်းသောနည်းလမ်းဖြစ်သည်။ ၎င်းကို Cake Wallet အက်ပ်၏အပြင်ဘက်တွင် လုံခြုံသောနေရာတွင် သိမ်းဆည်းရန်မှာ သင်၏တာဝန်ဖြစ်သည်။",
460 "pre_seed_title": "အရေးကြီးသည်။",
461 + "prepaid_cards": "ကြိုတင်ငွေဖြည့်ကဒ်များ",
462 "prevent_screenshots": "ဖန်သားပြင်ဓာတ်ပုံများနှင့် မျက်နှာပြင်ရိုက်ကူးခြင်းကို တားဆီးပါ။",
463 "privacy": "ကိုယ်ရေးကိုယ်တာ",
464 "privacy_policy": "ကိုယ်ရေးအချက်အလက်မူဝါဒ",
@@ -467,6 +474,7 @@
474 "purple_dark_theme": "ခရမ်းရောင် Drwing Theme",
475 "qr_fullscreen": "မျက်နှာပြင်အပြည့် QR ကုဒ်ကိုဖွင့်ရန် တို့ပါ။",
476 "qr_payment_amount": "ဤ QR ကုဒ်တွင် ငွေပေးချေမှုပမာဏတစ်ခုပါရှိသည်။ လက်ရှိတန်ဖိုးကို ထပ်ရေးလိုပါသလား။",
477 + "quantity": "အရေအတွက်",
478 "question_to_disable_2fa": "Cake 2FA ကို ပိတ်လိုသည်မှာ သေချာပါသလား။ ပိုက်ဆံအိတ်နှင့် အချို့သောလုပ်ဆောင်ချက်များကို အသုံးပြုရန်အတွက် 2FA ကုဒ်တစ်ခု မလိုအပ်တော့ပါ။",
479 "receivable_balance": "လက်ကျန်ငွေ",
480 "receive": "လက်ခံသည်။",
@@ -708,6 +716,7 @@
716 "tokenID": "အမှတ်သညာ",
717 "tor_connection": "Tor ချိတ်ဆက်မှု",
718 "tor_only": "Tor သာ",
719 + "total": "လုံးဝသော",
720 "total_saving": "စုစုပေါင်းစုဆောင်းငွေ",
721 "totp_2fa_failure": "ကုဒ်မမှန်ပါ။ ကျေးဇူးပြု၍ အခြားကုဒ်တစ်ခုကို စမ်းကြည့်ပါ သို့မဟုတ် လျှို့ဝှက်သော့အသစ်တစ်ခု ဖန်တီးပါ။ ဂဏန်း ၈ လုံးကုဒ်များနှင့် SHA512 ကို ပံ့ပိုးပေးသည့် တွဲဖက်အသုံးပြုနိုင်သော 2FA အက်ပ်ကို အသုံးပြုပါ။",
722 "totp_2fa_success": "အောင်မြင် ဤပိုက်ဆံအိတ်အတွက် ကိတ်မုန့် 2FA ကို ဖွင့်ထားသည်။ ပိုက်ဆံအိတ်ဝင်ရောက်ခွင့်ဆုံးရှုံးသွားသောအခါတွင် သင်၏ mnemonic မျိုးစေ့များကို သိမ်းဆည်းရန် မမေ့ပါနှင့်။",
@@ -798,6 +807,8 @@
807 "use_ssl": "SSL ကိုသုံးပါ။",
808 "use_suggested": "အကြံပြုထားသည်ကို အသုံးပြုပါ။",
809 "use_testnet": "testnet ကိုသုံးပါ",
810 + "value": "အဘိုး",
811 + "value_type": "Value အမျိုးအစား",
812 "variable_pair_not_supported": "ရွေးချယ်ထားသော ဖလှယ်မှုများဖြင့် ဤပြောင်းလဲနိုင်သောအတွဲကို ပံ့ပိုးမထားပါ။",
813 "verification": "စိစစ်ခြင်း။",
814 "verify_with_2fa": "Cake 2FA ဖြင့် စစ်ဆေးပါ။",
res/values/strings_nl.arb
+13 -2
@@ -87,6 +87,7 @@
87 "buy": "Kopen",
88 "buy_alert_content": "Momenteel ondersteunen we alleen de aankoop van Bitcoin, Ethereum, Litecoin en Monero. Maak of schakel over naar uw Bitcoin-, Ethereum-, Litecoin- of Monero-portemonnee.",
89 "buy_bitcoin": "Koop Bitcoin",
90 + "buy_now": "Koop nu",
91 "buy_provider_unavailable": "Provider momenteel niet beschikbaar.",
92 "buy_with": "Koop met",
93 "by_cake_pay": "door Cake Pay",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "Cake Dark Theme",
96 "cake_pay_account_note": "Meld u aan met alleen een e-mailadres om kaarten te bekijken en te kopen. Sommige zijn zelfs met korting verkrijgbaar!",
97 "cake_pay_learn_more": "Koop en wissel cadeaubonnen direct in de app in!\nSwipe van links naar rechts voor meer informatie.",
97 - "cake_pay_subtitle": "Koop cadeaubonnen met korting (alleen VS)",
98 - "cake_pay_title": "Cake Pay-cadeaubonnen",
98 + "cake_pay_subtitle": "Koop wereldwijde prepaid -kaarten en cadeaubonnen",
99 "cake_pay_web_cards_subtitle": "Koop wereldwijd prepaidkaarten en cadeaubonnen",
100 "cake_pay_web_cards_title": "Cake Pay-webkaarten",
101 "cake_wallet": "Cake Wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "Wijzig huidige portemonnee",
124 "choose_account": "Kies account",
125 "choose_address": "\n\nKies het adres:",
126 + "choose_card_value": "Kies een kaartwaarde",
127 "choose_derivation": "Kies portemonnee -afleiding",
128 "choose_from_available_options": "Kies uit de beschikbare opties:",
129 "choose_one": "Kies er een",
@@ -166,6 +167,7 @@
167 "copy_address": "Adres kopiëren",
168 "copy_id": "ID kopiëren",
169 "copyWalletConnectLink": "Kopieer de WalletConnect-link van dApp en plak deze hier",
170 + "countries": "Landen",
171 "create_account": "Account aanmaken",
172 "create_backup": "Maak een back-up",
173 "create_donation_link": "Maak een donatielink aan",
@@ -178,6 +180,7 @@
180 "custom": "aangepast",
181 "custom_drag": "Custom (vasthouden en slepen)",
182 "custom_redeem_amount": "Aangepast inwisselbedrag",
183 + "custom_value": "Aangepaste waarde",
184 "dark_theme": "Donker",
185 "debit_card": "Debetkaart",
186 "debit_card_terms": "De opslag en het gebruik van uw betaalkaartnummer (en inloggegevens die overeenkomen met uw betaalkaartnummer) in deze digitale portemonnee zijn onderworpen aan de Algemene voorwaarden van de toepasselijke kaarthouderovereenkomst met de uitgever van de betaalkaart, zoals van kracht vanaf tijd tot tijd.",
@@ -190,6 +193,7 @@
193 "delete_wallet": "Portemonnee verwijderen",
194 "delete_wallet_confirm_message": "Weet u zeker dat u de portemonnee van ${wallet_name} wilt verwijderen?",
195 "deleteConnectionConfirmationPrompt": "Weet u zeker dat u de verbinding met",
196 + "denominations": "Denominaties",
197 "descending": "Aflopend",
198 "description": "Beschrijving",
199 "destination_tag": "Bestemmingstag:",
@@ -277,6 +281,7 @@
281 "expired": "Verlopen",
282 "expires": "Verloopt",
283 "expiresOn": "Verloopt op",
284 + "expiry_and_validity": "Vervallen en geldigheid",
285 "export_backup": "Back-up exporteren",
286 "extra_id": "Extra ID:",
287 "extracted_address_content": "U stuurt geld naar\n${recipient_name}",
@@ -384,6 +389,7 @@
389 "new_template": "Nieuwe sjabloon",
390 "new_wallet": "Nieuwe portemonnee",
391 "newConnection": "Nieuwe verbinding",
392 + "no_cards_found": "Geen kaarten gevonden",
393 "no_id_needed": "Geen ID nodig!",
394 "no_id_required": "Geen ID vereist. Opwaarderen en overal uitgeven",
395 "no_relay_on_domain": "Er is geen relay voor het domein van de gebruiker of de relay is niet beschikbaar. Kies een relais dat u wilt gebruiken.",
@@ -452,6 +458,7 @@
458 "pre_seed_button_text": "Ik begrijp het. Laat me mijn zaad zien",
459 "pre_seed_description": "Op de volgende pagina ziet u een reeks van ${words} woorden. Dit is uw unieke en persoonlijke zaadje en het is de ENIGE manier om uw portemonnee te herstellen in geval van verlies of storing. Het is JOUW verantwoordelijkheid om het op te schrijven en op een veilige plaats op te slaan buiten de Cake Wallet app.",
460 "pre_seed_title": "BELANGRIJK",
461 + "prepaid_cards": "Prepaid-kaarten",
462 "prevent_screenshots": "Voorkom screenshots en schermopname",
463 "privacy": "Privacy",
464 "privacy_policy": "Privacybeleid",
@@ -467,6 +474,7 @@
474 "purple_dark_theme": "Paars donker thema",
475 "qr_fullscreen": "Tik om de QR-code op volledig scherm te openen",
476 "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?",
477 + "quantity": "Hoeveelheid",
478 "question_to_disable_2fa": "Weet je zeker dat je Cake 2FA wilt uitschakelen? Er is geen 2FA-code meer nodig om toegang te krijgen tot de portemonnee en bepaalde functies.",
479 "receivable_balance": "Het saldo",
480 "receive": "Krijgen",
@@ -708,6 +716,7 @@
716 "tokenID": "ID kaart",
717 "tor_connection": "Tor-verbinding",
718 "tor_only": "Alleen Tor",
719 + "total": "Totaal",
720 "total_saving": "Totale besparingen",
721 "totp_2fa_failure": "Foute code. Probeer een andere code of genereer een nieuwe geheime sleutel. Gebruik een compatibele 2FA-app die 8-cijferige codes en SHA512 ondersteunt.",
722 "totp_2fa_success": "Succes! Cake 2FA ingeschakeld voor deze portemonnee. Vergeet niet om uw geheugensteuntje op te slaan voor het geval u de toegang tot de portemonnee kwijtraakt.",
@@ -798,6 +807,8 @@
807 "use_ssl": "Gebruik SSL",
808 "use_suggested": "Gebruik aanbevolen",
809 "use_testnet": "Gebruik testnet",
810 + "value": "Waarde",
811 + "value_type": "Waarde type",
812 "variable_pair_not_supported": "Dit variabelenpaar wordt niet ondersteund met de geselecteerde uitwisselingen",
813 "verification": "Verificatie",
814 "verify_with_2fa": "Controleer met Cake 2FA",
res/values/strings_pl.arb
+13 -2
@@ -87,6 +87,7 @@
87 "buy": "Kup",
88 "buy_alert_content": "Obecnie obsługujemy tylko zakup Bitcoin, Ethereum, Litecoin i Monero. Utwórz lub przełącz się na swój portfel Bitcoin, Ethereum, Litecoin lub Monero.",
89 "buy_bitcoin": "Kup Bitcoin",
90 + "buy_now": "Kup Teraz",
91 "buy_provider_unavailable": "Dostawca obecnie niedostępny.",
92 "buy_with": "Kup za pomocą",
93 "by_cake_pay": "przez Cake Pay",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "Cake Dark Temat",
96 "cake_pay_account_note": "Zarejestruj się, używając tylko adresu e-mail, aby przeglądać i kupować karty. Niektóre są nawet dostępne ze zniżką!",
97 "cake_pay_learn_more": "Kupuj i wykorzystuj karty podarunkowe od razu w aplikacji!\nPrzesuń od lewej do prawej, aby dowiedzieć się więcej.",
97 - "cake_pay_subtitle": "Kup karty upominkowe ze zniżką (tylko USA)",
98 - "cake_pay_title": "Karty podarunkowe Cake Pay",
98 + "cake_pay_subtitle": "Kup na całym świecie karty przedpłacone i karty podarunkowe",
99 "cake_pay_web_cards_subtitle": "Kupuj na całym świecie karty przedpłacone i karty podarunkowe",
100 "cake_pay_web_cards_title": "Cake Pay Web Cards",
101 "cake_wallet": "Cake Wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "Zmień obecny portfel",
124 "choose_account": "Wybierz konto",
125 "choose_address": "\n\nWybierz adres:",
126 + "choose_card_value": "Wybierz wartość karty",
127 "choose_derivation": "Wybierz wyprowadzenie portfela",
128 "choose_from_available_options": "Wybierz z dostępnych opcji:",
129 "choose_one": "Wybierz jeden",
@@ -166,6 +167,7 @@
167 "copy_address": "Skopiuj adress",
168 "copy_id": "skopiuj ID",
169 "copyWalletConnectLink": "Skopiuj link do WalletConnect z dApp i wklej tutaj",
170 + "countries": "Kraje",
171 "create_account": "Utwórz konto",
172 "create_backup": "Utwórz kopię zapasową",
173 "create_donation_link": "Utwórz link do darowizny",
@@ -178,6 +180,7 @@
180 "custom": "niestandardowy",
181 "custom_drag": "Niestandardowe (trzymaj i przeciągnij)",
182 "custom_redeem_amount": "Niestandardowa kwota wykorzystania",
183 + "custom_value": "Wartość niestandardowa",
184 "dark_theme": "Ciemny",
185 "debit_card": "Karta debetowa",
186 "debit_card_terms": "Przechowywanie i używanie numeru karty płatniczej (oraz danych uwierzytelniających odpowiadających numerowi karty płatniczej) w tym portfelu cyfrowym podlega Warunkom odpowiedniej umowy posiadacza karty z wydawcą karty płatniczej, zgodnie z obowiązującym od od czasu do czasu.",
@@ -190,6 +193,7 @@
193 "delete_wallet": "Usuń portfel",
194 "delete_wallet_confirm_message": "Czy na pewno chcesz usunąć portfel ${wallet_name}?",
195 "deleteConnectionConfirmationPrompt": "Czy na pewno chcesz usunąć połączenie z",
196 + "denominations": "Wyznaczenia",
197 "descending": "Schodzenie",
198 "description": "Opis",
199 "destination_tag": "Tag docelowy:",
@@ -277,6 +281,7 @@
281 "expired": "Przedawniony",
282 "expires": "Wygasa",
283 "expiresOn": "Upływa w dniu",
284 + "expiry_and_validity": "Wygaśnięcie i ważność",
285 "export_backup": "Eksportuj kopię zapasową",
286 "extra_id": "Dodatkowy ID:",
287 "extracted_address_content": "Wysyłasz środki na\n${recipient_name}",
@@ -384,6 +389,7 @@
389 "new_template": "Nowy szablon",
390 "new_wallet": "Nowy portfel",
391 "newConnection": "Nowe połączenie",
392 + "no_cards_found": "Nie znaleziono żadnych kart",
393 "no_id_needed": "Nie potrzeba Dowodu!",
394 "no_id_required": "Nie wymagamy Dowodu. Doładuj i wydawaj gdziekolwiek",
395 "no_relay_on_domain": "Brak przekaźnika dla domeny użytkownika lub przekaźnik jest niedostępny. Wybierz przekaźnik, którego chcesz użyć.",
@@ -452,6 +458,7 @@
458 "pre_seed_button_text": "Rozumiem. Pokaż mi moją fraze seed",
459 "pre_seed_description": "Na następnej stronie zobaczysz serię ${words} słów. To jest Twoja unikalna i prywatna fraza seed i jest to JEDYNY sposób na odzyskanie portfela w przypadku utraty lub awarii telefonu. Twoim obowiązkiem jest zapisanie go i przechowywanie w bezpiecznym miejscu (np. na kartce w SEJFIE).",
460 "pre_seed_title": "WAŻNY",
461 + "prepaid_cards": "Karty przedpłacone",
462 "prevent_screenshots": "Zapobiegaj zrzutom ekranu i nagrywaniu ekranu",
463 "privacy": "Prywatność",
464 "privacy_policy": "Polityka prywatności",
@@ -467,6 +474,7 @@
474 "purple_dark_theme": "Purple Dark Temat",
475 "qr_fullscreen": "Dotknij, aby otworzyć pełnoekranowy kod QR",
476 "qr_payment_amount": "Ten kod QR zawiera kwotę do zapłaty. Czy chcesz nadpisać obecną wartość?",
477 + "quantity": "Ilość",
478 "question_to_disable_2fa": "Czy na pewno chcesz wyłączyć Cake 2FA? Kod 2FA nie będzie już potrzebny do uzyskania dostępu do portfela i niektórych funkcji.",
479 "receivable_balance": "Saldo należności",
480 "receive": "Otrzymaj",
@@ -708,6 +716,7 @@
716 "tokenID": "ID",
717 "tor_connection": "Połączenie Torem",
718 "tor_only": "Tylko sieć Tor",
719 + "total": "Całkowity",
720 "total_saving": "Całkowite oszczędności",
721 "totp_2fa_failure": "Błędny kod. Spróbuj użyć innego kodu lub wygeneruj nowy tajny klucz. Użyj kompatybilnej aplikacji 2FA, która obsługuje 8-cyfrowe kody i SHA512.",
722 "totp_2fa_success": "Powodzenie! Cake 2FA włączony dla tego portfela. Pamiętaj, aby zapisać swoje mnemoniczne ziarno na wypadek utraty dostępu do portfela.",
@@ -798,6 +807,8 @@
807 "use_ssl": "Użyj SSL",
808 "use_suggested": "Użyj sugerowane",
809 "use_testnet": "Użyj testne",
810 + "value": "Wartość",
811 + "value_type": "Typ wartości",
812 "variable_pair_not_supported": "Ta para zmiennych nie jest obsługiwana na wybranych giełdach",
813 "verification": "Weryfikacja",
814 "verify_with_2fa": "Sprawdź za pomocą Cake 2FA",
res/values/strings_pt.arb
+14 -3
@@ -87,6 +87,7 @@
87 "buy": "Comprar",
88 "buy_alert_content": "Atualmente, oferecemos suporte apenas à compra de Bitcoin, Ethereum, Litecoin e Monero. Crie ou troque para sua carteira Bitcoin, Ethereum, Litecoin ou Monero.",
89 "buy_bitcoin": "Compre Bitcoin",
90 + "buy_now": "Comprar agora",
91 "buy_provider_unavailable": "Provedor atualmente indisponível.",
92 "buy_with": "Compre com",
93 "by_cake_pay": "por Cake Pay",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "Bolo tema escuro",
96 "cake_pay_account_note": "Inscreva-se com apenas um endereço de e-mail para ver e comprar cartões. Alguns estão até com desconto!",
97 "cake_pay_learn_more": "Compre e resgate vales-presente instantaneamente no app!\nDeslize da esquerda para a direita para saber mais.",
97 - "cake_pay_subtitle": "Compre vales-presente com desconto (somente nos EUA)",
98 - "cake_pay_title": "Cartões de presente de CakePay",
98 + "cake_pay_subtitle": "Compre cartões pré -pagos em todo o mundo e cartões -presente",
99 "cake_pay_web_cards_subtitle": "Compre cartões pré-pagos e cartões-presente em todo o mundo",
100 "cake_pay_web_cards_title": "Cartões Cake Pay Web",
101 "cake_wallet": "Cake Wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "Alterar carteira atual",
124 "choose_account": "Escolha uma conta",
125 "choose_address": "\n\nEscolha o endereço:",
126 + "choose_card_value": "Escolha um valor de cartão",
127 "choose_derivation": "Escolha a derivação da carteira",
128 "choose_from_available_options": "Escolha entre as opções disponíveis:",
129 "choose_one": "Escolha um",
@@ -166,6 +167,7 @@
167 "copy_address": "Copiar endereço",
168 "copy_id": "Copiar ID",
169 "copyWalletConnectLink": "Copie o link WalletConnect do dApp e cole aqui",
170 + "countries": "Países",
171 "create_account": "Criar conta",
172 "create_backup": "Criar backup",
173 "create_donation_link": "Criar link de doação",
@@ -178,6 +180,7 @@
180 "custom": "personalizado",
181 "custom_drag": "Personalizado (segure e arraste)",
182 "custom_redeem_amount": "Valor de resgate personalizado",
183 + "custom_value": "Valor customizado",
184 "dark_theme": "Sombria",
185 "debit_card": "Cartão de débito",
186 "debit_card_terms": "O armazenamento e uso do número do cartão de pagamento (e credenciais correspondentes ao número do cartão de pagamento) nesta carteira digital estão sujeitos aos Termos e Condições do contrato do titular do cartão aplicável com o emissor do cartão de pagamento, em vigor a partir de tempo ao tempo.",
@@ -190,6 +193,7 @@
193 "delete_wallet": "Excluir carteira",
194 "delete_wallet_confirm_message": "Tem certeza de que deseja excluir a carteira ${wallet_name}?",
195 "deleteConnectionConfirmationPrompt": "Tem certeza de que deseja excluir a conexão com",
196 + "denominations": "Denominações",
197 "descending": "descendente",
198 "description": "Descrição",
199 "destination_tag": "Tag de destino:",
@@ -277,6 +281,7 @@
281 "expired": "Expirada",
282 "expires": "Expira",
283 "expiresOn": "Expira em",
284 + "expiry_and_validity": "Expiração e validade",
285 "export_backup": "Backup de exportação",
286 "extra_id": "ID extra:",
287 "extracted_address_content": "Você enviará fundos para\n${recipient_name}",
@@ -385,6 +390,7 @@
390 "new_template": "Novo modelo",
391 "new_wallet": "Nova carteira",
392 "newConnection": "Nova conexão",
393 + "no_cards_found": "Nenhum cartão encontrado",
394 "no_id_needed": "Nenhum ID necessário!",
395 "no_id_required": "Não é necessário ID. Recarregue e gaste em qualquer lugar",
396 "no_relay_on_domain": "Não há uma retransmissão para o domínio do usuário ou a retransmissão está indisponível. Escolha um relé para usar.",
@@ -454,6 +460,7 @@
460 "pre_seed_button_text": "Compreendo. Me mostre minha semente",
461 "pre_seed_description": "Na próxima página, você verá uma série de ${words} palavras. Esta é a sua semente única e privada e é a ÚNICA maneira de recuperar sua carteira em caso de perda ou mau funcionamento. É SUA responsabilidade anotá-lo e armazená-lo em um local seguro fora do aplicativo Cake Wallet.",
462 "pre_seed_title": "IMPORTANTE",
463 + "prepaid_cards": "Cartões pré-pagos",
464 "prevent_screenshots": "Evite capturas de tela e gravação de tela",
465 "privacy": "Privacidade",
466 "privacy_policy": "Política de privacidade",
@@ -469,6 +476,7 @@
476 "purple_dark_theme": "Tema escuro roxo",
477 "qr_fullscreen": "Toque para abrir o código QR em tela cheia",
478 "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?",
479 + "quantity": "Quantidade",
480 "question_to_disable_2fa": "Tem certeza de que deseja desativar o Cake 2FA? Um código 2FA não será mais necessário para acessar a carteira e certas funções.",
481 "receivable_balance": "Saldo a receber",
482 "receive": "Receber",
@@ -710,6 +718,7 @@
718 "tokenID": "EU IA",
719 "tor_connection": "Conexão Tor",
720 "tor_only": "Tor apenas",
721 + "total": "Total",
722 "total_saving": "Economia total",
723 "totp_2fa_failure": "Código incorreto. Tente um código diferente ou gere uma nova chave secreta. Use um aplicativo 2FA compatível com códigos de 8 dígitos e SHA512.",
724 "totp_2fa_success": "Sucesso! Cake 2FA ativado para esta carteira. Lembre-se de salvar sua semente mnemônica caso perca o acesso à carteira.",
@@ -800,6 +809,8 @@
809 "use_ssl": "Use SSL",
810 "use_suggested": "Uso sugerido",
811 "use_testnet": "Use testNet",
812 + "value": "Valor",
813 + "value_type": "Tipo de valor",
814 "variable_pair_not_supported": "Este par de variáveis não é compatível com as trocas selecionadas",
815 "verification": "Verificação",
816 "verify_with_2fa": "Verificar com Cake 2FA",
@@ -864,4 +875,4 @@
875 "you_will_get": "Converter para",
876 "you_will_send": "Converter de",
877 "yy": "aa"
867 -}
878 +}
\ No newline at end of file
res/values/strings_ru.arb
+13 -2
@@ -87,6 +87,7 @@
87 "buy": "Купить",
88 "buy_alert_content": "В настоящее время мы поддерживаем только покупку биткойнов, Ethereum, Litecoin и Monero. Пожалуйста, создайте или переключитесь на свой кошелек Bitcoin, Ethereum, Litecoin или Monero.",
89 "buy_bitcoin": "Купить Bitcoin",
90 + "buy_now": "Купить сейчас",
91 "buy_provider_unavailable": "Поставщик в настоящее время недоступен.",
92 "buy_with": "Купить с помощью",
93 "by_cake_pay": "от Cake Pay",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "Тейт темная тема",
96 "cake_pay_account_note": "Зарегистрируйтесь, указав только адрес электронной почты, чтобы просматривать и покупать карты. Некоторые даже доступны со скидкой!",
97 "cake_pay_learn_more": "Мгновенно покупайте и используйте подарочные карты в приложении!\nПроведите по экрану слева направо, чтобы узнать больше.",
97 - "cake_pay_subtitle": "Покупайте подарочные карты со скидкой (только для США)",
98 - "cake_pay_title": "Подарочные карты Cake Pay",
98 + "cake_pay_subtitle": "Купить карты с предоплатой и подарочными картами по всему миру",
99 "cake_pay_web_cards_subtitle": "Покупайте карты предоплаты и подарочные карты по всему миру",
100 "cake_pay_web_cards_title": "Веб-карты Cake Pay",
101 "cake_wallet": "Cake Wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "Изменить текущий кошелек",
124 "choose_account": "Выберите аккаунт",
125 "choose_address": "\n\nПожалуйста, выберите адрес:",
126 + "choose_card_value": "Выберите значение карты",
127 "choose_derivation": "Выберите вывод кошелька",
128 "choose_from_available_options": "Выберите из доступных вариантов:",
129 "choose_one": "Выбери один",
@@ -166,6 +167,7 @@
167 "copy_address": "Cкопировать адрес",
168 "copy_id": "Скопировать ID",
169 "copyWalletConnectLink": "Скопируйте ссылку WalletConnect из dApp и вставьте сюда.",
170 + "countries": "Страны",
171 "create_account": "Создать аккаунт",
172 "create_backup": "Создать резервную копию",
173 "create_donation_link": "Создать ссылку для пожертвований",
@@ -178,6 +180,7 @@
180 "custom": "обычай",
181 "custom_drag": "Пользователь (удерживайте и перетаскивайте)",
182 "custom_redeem_amount": "Пользовательская сумма погашения",
183 + "custom_value": "Пользовательское значение",
184 "dark_theme": "Темная",
185 "debit_card": "Дебетовая карта",
186 "debit_card_terms": "Хранение и использование номера вашей платежной карты (и учетных данных, соответствующих номеру вашей платежной карты) в этом цифровом кошельке регулируются положениями и условиями применимого соглашения держателя карты с эмитентом платежной карты, действующим с время от времени.",
@@ -190,6 +193,7 @@
193 "delete_wallet": "Удалить кошелек",
194 "delete_wallet_confirm_message": "Вы уверены, что хотите удалить кошелек ${wallet_name}?",
195 "deleteConnectionConfirmationPrompt": "Вы уверены, что хотите удалить подключение к",
196 + "denominations": "Деноминации",
197 "descending": "Нисходящий",
198 "description": "Описание",
199 "destination_tag": "Целевой тег:",
@@ -277,6 +281,7 @@
281 "expired": "Истекает",
282 "expires": "Истекает",
283 "expiresOn": "Годен до",
284 + "expiry_and_validity": "Истечение и достоверность",
285 "export_backup": "Экспорт резервной копии",
286 "extra_id": "Дополнительный ID:",
287 "extracted_address_content": "Вы будете отправлять средства\n${recipient_name}",
@@ -384,6 +389,7 @@
389 "new_template": "Новый шаблон",
390 "new_wallet": "Новый кошелёк",
391 "newConnection": "Новое соединение",
392 + "no_cards_found": "Карт не найдено",
393 "no_id_needed": "Идентификатор не нужен!",
394 "no_id_required": "Идентификатор не требуется. Пополняйте и тратьте где угодно",
395 "no_relay_on_domain": "Для домена пользователя реле не существует или реле недоступно. Пожалуйста, выберите реле для использования.",
@@ -453,6 +459,7 @@
459 "pre_seed_button_text": "Понятно. Покажите мнемоническую фразу",
460 "pre_seed_description": "На следующей странице вы увидите серию из ${words} слов. Это ваша уникальная и личная мнемоническая фраза, и это ЕДИНСТВЕННЫЙ способ восстановить свой кошелек в случае потери или неисправности. ВАМ необходимо записать ее и хранить в надежном месте вне приложения Cake Wallet.",
461 "pre_seed_title": "ВАЖНО",
462 + "prepaid_cards": "Предоплаченные карты",
463 "prevent_screenshots": "Предотвратить скриншоты и запись экрана",
464 "privacy": "Конфиденциальность",
465 "privacy_policy": "Политика конфиденциальности",
@@ -468,6 +475,7 @@
475 "purple_dark_theme": "Пурпурная темная тема",
476 "qr_fullscreen": "Нажмите, чтобы открыть полноэкранный QR-код",
477 "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?",
478 + "quantity": "Количество",
479 "question_to_disable_2fa": "Вы уверены, что хотите отключить Cake 2FA? Код 2FA больше не потребуется для доступа к кошельку и некоторым функциям.",
480 "receivable_balance": "Баланс дебиторской задолженности",
481 "receive": "Получить",
@@ -709,6 +717,7 @@
717 "tokenID": "ИДЕНТИФИКАТОР",
718 "tor_connection": "Тор соединение",
719 "tor_only": "Только Tor",
720 + "total": "Общий",
721 "total_saving": "Общая экономия",
722 "totp_2fa_failure": "Неверный код. Пожалуйста, попробуйте другой код или создайте новый секретный ключ. Используйте совместимое приложение 2FA, которое поддерживает 8-значные коды и SHA512.",
723 "totp_2fa_success": "Успех! Для этого кошелька включена двухфакторная аутентификация Cake. Не забудьте сохранить мнемоническое семя на случай, если вы потеряете доступ к кошельку.",
@@ -799,6 +808,8 @@
808 "use_ssl": "Использовать SSL",
809 "use_suggested": "Использовать предложенный",
810 "use_testnet": "Используйте Testnet",
811 + "value": "Ценить",
812 + "value_type": "Тип значения",
813 "variable_pair_not_supported": "Эта пара переменных не поддерживается выбранными биржами.",
814 "verification": "Проверка",
815 "verify_with_2fa": "Подтвердить с помощью Cake 2FA",
res/values/strings_th.arb
+13 -2
@@ -87,6 +87,7 @@
87 "buy": "ซื้อ",
88 "buy_alert_content": "ขณะนี้เรารองรับการซื้อ Bitcoin, Ethereum, Litecoin และ Monero เท่านั้น โปรดสร้างหรือเปลี่ยนเป็นกระเป๋าเงิน Bitcoin, Ethereum, Litecoin หรือ Monero",
89 "buy_bitcoin": "ซื้อ Bitcoin",
90 + "buy_now": "ซื้อตอนนี้",
91 "buy_provider_unavailable": "ผู้ให้บริการไม่สามารถใช้งานได้ในปัจจุบัน",
92 "buy_with": "ซื้อด้วย",
93 "by_cake_pay": "โดย Cake Pay",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "ธีมเค้กมืด",
96 "cake_pay_account_note": "ลงทะเบียนด้วยอีเมลเพียงอย่างเดียวเพื่อดูและซื้อบัตร บางบัตรอาจมีส่วนลด!",
97 "cake_pay_learn_more": "ซื้อและเบิกบัตรของขวัญในแอพพลิเคชันทันที!\nกระแทกขวาไปซ้ายเพื่อเรียนรู้เพิ่มเติม",
97 - "cake_pay_subtitle": "ซื้อบัตรของขวัญราคาถูก (สำหรับสหรัฐอเมริกาเท่านั้น)",
98 - "cake_pay_title": "บัตรของขวัญ Cake Pay",
98 + "cake_pay_subtitle": "ซื้อบัตรเติมเงินและบัตรของขวัญทั่วโลก",
99 "cake_pay_web_cards_subtitle": "ซื้อบัตรพร้อมเงินระดับโลกและบัตรของขวัญ",
100 "cake_pay_web_cards_title": "Cake Pay Web Cards",
101 "cake_wallet": "Cake Wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "เปลี่ยนกระเป๋าปัจจุบัน",
124 "choose_account": "เลือกบัญชี",
125 "choose_address": "\n\nโปรดเลือกที่อยู่:",
126 + "choose_card_value": "เลือกค่าบัตร",
127 "choose_derivation": "เลือก Wallet Derivation",
128 "choose_from_available_options": "เลือกจากตัวเลือกที่มีอยู่:",
129 "choose_one": "เลือกหนึ่งรายการ",
@@ -166,6 +167,7 @@
167 "copy_address": "คัดลอกที่อยู่",
168 "copy_id": "คัดลอก ID",
169 "copyWalletConnectLink": "คัดลอกลิงก์ WalletConnect จาก dApp แล้ววางที่นี่",
170 + "countries": "ประเทศ",
171 "create_account": "สร้างบัญชี",
172 "create_backup": "สร้างการสำรองข้อมูล",
173 "create_donation_link": "สร้างลิงค์บริจาค",
@@ -178,6 +180,7 @@
180 "custom": "กำหนดเอง",
181 "custom_drag": "กำหนดเอง (ค้างและลาก)",
182 "custom_redeem_amount": "จำนวนรับคืนที่กำหนดเอง",
183 + "custom_value": "ค่าที่กำหนดเอง",
184 "dark_theme": "เข้ม",
185 "debit_card": "บัตรเดบิต",
186 "debit_card_terms": "การเก็บรักษาและใช้หมายเลขบัตรจ่ายเงิน (และข้อมูลประจำตัวที่เกี่ยวข้องกับหมายเลขบัตรจ่ายเงิน) ในกระเป๋าดิจิทัลนี้ จะต้องยึดถือข้อกำหนดและเงื่อนไขของข้อตกลงผู้ใช้บัตรของผู้ถือบัตรที่เกี่ยวข้องกับบัตรผู้ถือบัตร ซึ่งจะมีผลตั้งแต่เวลานั้น",
@@ -190,6 +193,7 @@
193 "delete_wallet": "ลบกระเป๋า",
194 "delete_wallet_confirm_message": "คุณแน่ใจหรือว่าต้องการลบกระเป๋า${wallet_name}?",
195 "deleteConnectionConfirmationPrompt": "คุณแน่ใจหรือไม่ว่าต้องการลบการเชื่อมต่อไปยัง",
196 + "denominations": "นิกาย",
197 "descending": "ลงมา",
198 "description": "คำอธิบาย",
199 "destination_tag": "แท็กปลายทาง:",
@@ -277,6 +281,7 @@
281 "expired": "หมดอายุ",
282 "expires": "หมดอายุ",
283 "expiresOn": "หมดอายุวันที่",
284 + "expiry_and_validity": "หมดอายุและถูกต้อง",
285 "export_backup": "ส่งออกข้อมูลสำรอง",
286 "extra_id": "ไอดีเพิ่มเติม:",
287 "extracted_address_content": "คุณกำลังจะส่งเงินไปยัง\n${recipient_name}",
@@ -384,6 +389,7 @@
389 "new_template": "แม่แบบใหม่",
390 "new_wallet": "กระเป๋าใหม่",
391 "newConnection": "การเชื่อมต่อใหม่",
392 + "no_cards_found": "ไม่พบการ์ด",
393 "no_id_needed": "ไม่จำเป็นต้องใช้บัตรประชาชน!",
394 "no_id_required": "ไม่จำเป็นต้องใช้บัตรประจำตัว ฝากเงินและใช้งานได้ทุกที่",
395 "no_relay_on_domain": "ไม่มีการส่งต่อสำหรับโดเมนของผู้ใช้ หรือการส่งต่อไม่พร้อมใช้งาน กรุณาเลือกรีเลย์ที่จะใช้",
@@ -452,6 +458,7 @@
458 "pre_seed_button_text": "ฉันเข้าใจ แสดง seed ของฉัน",
459 "pre_seed_description": "บนหน้าถัดไปคุณจะเห็นชุดของคำ ${words} คำ นี่คือ seed ของคุณที่ไม่ซ้ำใดๆ และเป็นความลับเพียงของคุณ และนี่คือเพียงวิธีเดียวที่จะกู้กระเป๋าของคุณในกรณีที่สูญหายหรือมีปัญหา มันเป็นความรับผิดชอบของคุณเพื่อเขียนมันลงบนกระดาษและจัดเก็บไว้ในที่ปลอดภัยนอกแอป Cake Wallet",
460 "pre_seed_title": "สำคัญ",
461 + "prepaid_cards": "บัตรเติมเงิน",
462 "prevent_screenshots": "ป้องกันภาพหน้าจอและการบันทึกหน้าจอ",
463 "privacy": "ความเป็นส่วนตัว",
464 "privacy_policy": "นโยบายความเป็นส่วนตัว",
@@ -467,6 +474,7 @@
474 "purple_dark_theme": "ธีมสีม่วงเข้ม",
475 "qr_fullscreen": "แตะเพื่อเปิดหน้าจอ QR code แบบเต็มจอ",
476 "qr_payment_amount": "QR code นี้มีจำนวนการชำระเงิน คุณต้องการเขียนทับค่าปัจจุบันหรือไม่?",
477 + "quantity": "ปริมาณ",
478 "question_to_disable_2fa": "คุณแน่ใจหรือไม่ว่าต้องการปิดการใช้งาน Cake 2FA ไม่จำเป็นต้องใช้รหัส 2FA ในการเข้าถึงกระเป๋าเงินและฟังก์ชั่นบางอย่างอีกต่อไป",
479 "receivable_balance": "ยอดลูกหนี้",
480 "receive": "รับ",
@@ -708,6 +716,7 @@
716 "tokenID": "บัตรประจำตัวประชาชน",
717 "tor_connection": "การเชื่อมต่อทอร์",
718 "tor_only": "Tor เท่านั้น",
719 + "total": "ทั้งหมด",
720 "total_saving": "ประหยัดรวม",
721 "totp_2fa_failure": "รหัสไม่ถูกต้อง. โปรดลองใช้รหัสอื่นหรือสร้างรหัสลับใหม่ ใช้แอพ 2FA ที่เข้ากันได้ซึ่งรองรับรหัส 8 หลักและ SHA512",
722 "totp_2fa_success": "ความสำเร็จ! Cake 2FA เปิดใช้งานสำหรับกระเป๋าเงินนี้ อย่าลืมบันทึกเมล็ดช่วยจำของคุณในกรณีที่คุณสูญเสียการเข้าถึงกระเป๋าเงิน",
@@ -798,6 +807,8 @@
807 "use_ssl": "ใช้ SSL",
808 "use_suggested": "ใช้ที่แนะนำ",
809 "use_testnet": "ใช้ testnet",
810 + "value": "ค่า",
811 + "value_type": "ประเภทค่า",
812 "variable_pair_not_supported": "คู่ความสัมพันธ์ที่เปลี่ยนแปลงได้นี้ไม่สนับสนุนกับหุ้นที่เลือก",
813 "verification": "การตรวจสอบ",
814 "verify_with_2fa": "ตรวจสอบกับ Cake 2FA",
res/values/strings_tl.arb
+13 -2
@@ -87,6 +87,7 @@
87 "buy": "Bilhin",
88 "buy_alert_content": "Sa kasalukuyan ay sinusuportahan lamang namin ang pagbili ng Bitcoin, Ethereum, Litecoin, at Monero. Mangyaring lumikha o lumipat sa iyong Bitcoin, Ethereum, Litecoin, o Monero Wallet.",
89 "buy_bitcoin": "Bumili ng bitcoin",
90 + "buy_now": "Bumili ka na ngayon",
91 "buy_provider_unavailable": "Kasalukuyang hindi available ang provider.",
92 "buy_with": "Bumili ka",
93 "by_cake_pay": "sa pamamagitan ng cake pay",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "Cake madilim na tema",
96 "cake_pay_account_note": "Mag -sign up na may isang email address lamang upang makita at bumili ng mga kard. Ang ilan ay magagamit kahit sa isang diskwento!",
97 "cake_pay_learn_more": "Agad na bumili at tubusin ang mga kard ng regalo sa app!\nMag -swipe pakaliwa sa kanan upang matuto nang higit pa.",
97 - "cake_pay_subtitle": "Bumili ng mga diskwento na gift card (USA lamang)",
98 - "cake_pay_title": "Cake pay card card",
98 + "cake_pay_subtitle": "Bumili ng mga pandaigdigang prepaid card at gift card",
99 "cake_pay_web_cards_subtitle": "Bumili ng mga pandaigdigang prepaid card at gift card",
100 "cake_pay_web_cards_title": "Cake pay web card",
101 "cake_wallet": "Cake wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "Baguhin ang kasalukuyang pitaka",
124 "choose_account": "Pumili ng account",
125 "choose_address": "Mangyaring piliin ang address:",
126 + "choose_card_value": "Pumili ng isang halaga ng card",
127 "choose_derivation": "Piliin ang derivation ng Wallet",
128 "choose_from_available_options": "Pumili mula sa magagamit na mga pagpipilian:",
129 "choose_one": "Pumili ng isa",
@@ -166,6 +167,7 @@
167 "copy_address": "Kopyahin ang address",
168 "copy_id": "Kopyahin ang id",
169 "copyWalletConnectLink": "Kopyahin ang link ng WalletConnect mula sa dApp at i-paste dito",
170 + "countries": "Mga bansa",
171 "create_account": "Lumikha ng account",
172 "create_backup": "Gumawa ng backup",
173 "create_donation_link": "Lumikha ng link ng donasyon",
@@ -178,6 +180,7 @@
180 "custom": "pasadya",
181 "custom_drag": "Pasadyang (hawakan at i -drag)",
182 "custom_redeem_amount": "Pasadyang tinubos ang halaga",
183 + "custom_value": "Pasadyang halaga",
184 "dark_theme": "Madilim",
185 "debit_card": "Debit card",
186 "debit_card_terms": "Ang pag -iimbak at paggamit ng numero ng iyong card ng pagbabayad (at mga kredensyal na naaayon sa iyong numero ng card ng pagbabayad) sa digital na pitaka na ito ay napapailalim sa mga termino at kundisyon ng naaangkop na kasunduan sa cardholder kasama ang nagbigay ng card ng pagbabayad, tulad ng sa oras -oras.",
@@ -190,6 +193,7 @@
193 "delete_wallet": "Tanggalin ang pitaka",
194 "delete_wallet_confirm_message": "Sigurado ka bang nais mong tanggalin ang ${wallet_name} wallet?",
195 "deleteConnectionConfirmationPrompt": "Sigurado ka bang gusto mong tanggalin ang koneksyon sa",
196 + "denominations": "Denominasyon",
197 "descending": "Pababang",
198 "description": "Paglalarawan",
199 "destination_tag": "Tag ng patutunguhan:",
@@ -277,6 +281,7 @@
281 "expired": "Nag -expire",
282 "expires": "Mag -expire",
283 "expiresOn": "Mag-e-expire sa",
284 + "expiry_and_validity": "Pag -expire at bisa",
285 "export_backup": "I -export ang backup",
286 "extra_id": "Dagdag na ID:",
287 "extracted_address_content": "Magpapadala ka ng pondo sa\n${recipient_name}",
@@ -384,6 +389,7 @@
389 "new_template": "Bagong template",
390 "new_wallet": "Bagong pitaka",
391 "newConnection": "Bagong Koneksyon",
392 + "no_cards_found": "Walang nahanap na mga kard",
393 "no_id_needed": "Hindi kailangan ng ID!",
394 "no_id_required": "Walang kinakailangang ID. I -top up at gumastos kahit saan",
395 "no_relay_on_domain": "Walang relay para sa domain ng user o hindi available ang relay. Mangyaring pumili ng relay na gagamitin.",
@@ -452,6 +458,7 @@
458 "pre_seed_button_text": "Naiintindihan ko. Ipakita sa akin ang aking binhi",
459 "pre_seed_description": "Sa susunod na pahina makikita mo ang isang serye ng mga ${words} na mga salita. Ito ang iyong natatangi at pribadong binhi at ito ang tanging paraan upang mabawi ang iyong pitaka kung sakaling mawala o madepektong paggawa. Responsibilidad mong isulat ito at itago ito sa isang ligtas na lugar sa labas ng cake wallet app.",
460 "pre_seed_title": "Mahalaga",
461 + "prepaid_cards": "Prepaid card",
462 "prevent_screenshots": "Maiwasan ang mga screenshot at pag -record ng screen",
463 "privacy": "Privacy",
464 "privacy_policy": "Patakaran sa Pagkapribado",
@@ -467,6 +474,7 @@
474 "purple_dark_theme": "Purple Madilim na Tema",
475 "qr_fullscreen": "Tapikin upang buksan ang buong screen QR code",
476 "qr_payment_amount": "Ang QR code na ito ay naglalaman ng isang halaga ng pagbabayad. Nais mo bang i -overwrite ang kasalukuyang halaga?",
477 + "quantity": "Dami",
478 "question_to_disable_2fa": "Sigurado ka bang nais mong huwag paganahin ang cake 2fa? Ang isang 2FA code ay hindi na kinakailangan upang ma -access ang pitaka at ilang mga pag -andar.",
479 "receivable_balance": "Natatanggap na balanse",
480 "receive": "Tumanggap",
@@ -708,6 +716,7 @@
716 "tokenID": "ID",
717 "tor_connection": "Koneksyon ng Tor",
718 "tor_only": "Tor lang",
719 + "total": "Kabuuan",
720 "total_saving": "Kabuuang pagtitipid",
721 "totp_2fa_failure": "Maling code. Mangyaring subukan ang ibang code o makabuo ng isang bagong lihim na susi. Gumamit ng isang katugmang 2FA app na sumusuporta sa 8-digit na mga code at SHA512.",
722 "totp_2fa_success": "Tagumpay! Pinagana ang cake 2FA para sa pitaka na ito. Tandaan na i -save ang iyong mnemonic seed kung sakaling mawalan ka ng pag -access sa pitaka.",
@@ -798,6 +807,8 @@
807 "use_ssl": "Gumamit ng SSL",
808 "use_suggested": "Gumamit ng iminungkahing",
809 "use_testnet": "Gumamit ng testnet",
810 + "value": "Halaga",
811 + "value_type": "Uri ng halaga",
812 "variable_pair_not_supported": "Ang variable na pares na ito ay hindi suportado sa mga napiling palitan",
813 "verification": "Pag -verify",
814 "verify_with_2fa": "Mag -verify sa cake 2FA",
res/values/strings_tr.arb
+14 -3
@@ -87,6 +87,7 @@
87 "buy": "Alış",
88 "buy_alert_content": "Şu anda yalnızca Bitcoin, Ethereum, Litecoin ve Monero satın alımını destekliyoruz. Lütfen Bitcoin, Ethereum, Litecoin veya Monero cüzdanınızı oluşturun veya cüzdanınıza geçin.",
89 "buy_bitcoin": "Bitcoin Satın Al",
90 + "buy_now": "Şimdi al",
91 "buy_provider_unavailable": "Sağlayıcı şu anda kullanılamıyor.",
92 "buy_with": "Şunun ile al: ",
93 "by_cake_pay": "Cake Pay tarafından",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "Kek Koyu Tema",
96 "cake_pay_account_note": "Kartları görmek ve satın almak için sadece bir e-posta adresiyle kaydolun. Hatta bazıları indirimli olarak bile mevcut!",
97 "cake_pay_learn_more": "Uygulamada anında hediye kartları satın alın ve harcayın!\nDaha fazla öğrenmek için soldan sağa kaydır.",
97 - "cake_pay_subtitle": "İndirimli hediye kartları satın alın (yalnızca ABD)",
98 - "cake_pay_title": "Cake Pay Hediye Kartları",
98 + "cake_pay_subtitle": "Dünya çapında ön ödemeli kartlar ve hediye kartları satın alın",
99 "cake_pay_web_cards_subtitle": "Dünya çapında ön ödemeli kartlar ve hediye kartları satın alın",
100 "cake_pay_web_cards_title": "Cake Pay Web Kartları",
101 "cake_wallet": "Cake Wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "Şimdiki cüzdanı değiştir",
124 "choose_account": "Hesabı seç",
125 "choose_address": "\n\nLütfen adresi seçin:",
126 + "choose_card_value": "Bir kart değeri seçin",
127 "choose_derivation": "Cüzdan türevini seçin",
128 "choose_from_available_options": "Mevcut seçenekler arasından seçim yap:",
129 "choose_one": "Birini seç",
@@ -166,6 +167,7 @@
167 "copy_address": "Adresi kopyala",
168 "copy_id": "ID'yi kopyala",
169 "copyWalletConnectLink": "WalletConnect bağlantısını dApp'ten kopyalayıp buraya yapıştırın",
170 + "countries": "Ülkeler",
171 "create_account": "Hesap oluştur",
172 "create_backup": "Yedek oluştur",
173 "create_donation_link": "Bağış bağlantısı oluştur",
@@ -178,6 +180,7 @@
180 "custom": "özel",
181 "custom_drag": "Özel (Bekle ve Sürükle)",
182 "custom_redeem_amount": "Özel Harcama Tutarı",
183 + "custom_value": "Özel değer",
184 "dark_theme": "Karanlık",
185 "debit_card": "Ön ödemeli Kart",
186 "debit_card_terms": "Ödeme kartı numaranızın (ve kart numaranıza karşılık gelen kimlik bilgilerinin) bu dijital cüzdanda saklanması ve kullanılması, zaman zaman yürürlükte olan ödeme kartı veren kuruluşla yapılan ilgili kart sahibi sözleşmesinin Hüküm ve Koşullarına tabidir.",
@@ -190,6 +193,7 @@
193 "delete_wallet": "Cüzdanı sil",
194 "delete_wallet_confirm_message": "${wallet_name} isimli cüzdanını silmek istediğinden emin misin?",
195 "deleteConnectionConfirmationPrompt": "Bağlantıyı silmek istediğinizden emin misiniz?",
196 + "denominations": "Mezhepler",
197 "descending": "Azalan",
198 "description": "Tanım",
199 "destination_tag": "Hedef Etiketi:",
@@ -277,6 +281,7 @@
281 "expired": "Süresi doldu",
282 "expires": "Son kullanma tarihi",
283 "expiresOn": "Tarihinde sona eriyor",
284 + "expiry_and_validity": "Sona erme ve geçerlilik",
285 "export_backup": "Yedeği dışa aktar",
286 "extra_id": "Ekstra ID:",
287 "extracted_address_content": "Parayı buraya gönderceksin:\n${recipient_name}",
@@ -308,7 +313,7 @@
313 "gift_card_is_generated": "Hediye Kartı oluşturuldu",
314 "gift_card_number": "Hediye kartı numarası",
315 "gift_card_redeemed_note": "Harcadığın hediye kartları burada görünecek",
311 - "gift_cards": "Hediye kartları",
316 + "gift_cards": "Hediye Kartları",
317 "gift_cards_unavailable": "Hediye kartları şu anda yalnızca Monero, Bitcoin ve Litecoin ile satın alınabilir",
318 "got_it": "Tamamdır",
319 "gross_balance": "Brüt Bakiye",
@@ -384,6 +389,7 @@
389 "new_template": "Yeni Şablon",
390 "new_wallet": "Yeni Cüzdan",
391 "newConnection": "Yeni bağlantı",
392 + "no_cards_found": "Kart bulunamadı",
393 "no_id_needed": "Kimlik gerekmez!",
394 "no_id_required": "Kimlik gerekmez. Para yükleyin ve istediğiniz yerde harcayın",
395 "no_relay_on_domain": "Kullanıcının alanı için bir geçiş yok veya geçiş kullanılamıyor. Lütfen kullanmak için bir röle seçin.",
@@ -452,6 +458,7 @@
458 "pre_seed_button_text": "Anladım. Bana tohumumu göster.",
459 "pre_seed_description": "Bir sonraki sayfada ${words} kelime göreceksin. Bu senin benzersiz ve özel tohumundur, kaybetmen veya silinmesi durumunda cüzdanını kurtarmanın TEK YOLUDUR. Bunu yazmak ve Cake Wallet uygulaması dışında güvenli bir yerde saklamak tamamen SENİN sorumluluğunda.",
460 "pre_seed_title": "UYARI",
461 + "prepaid_cards": "Ön ödemeli kartlar",
462 "prevent_screenshots": "Ekran görüntülerini ve ekran kaydını önleyin",
463 "privacy": "Gizlilik",
464 "privacy_policy": "Gizlilik Politikası",
@@ -467,6 +474,7 @@
474 "purple_dark_theme": "Mor karanlık tema",
475 "qr_fullscreen": "QR kodunu tam ekranda açmak için dokun",
476 "qr_payment_amount": "Bu QR kodu ödeme tutarını içeriyor. Geçerli miktarın üzerine yazmak istediğine emin misin?",
477 + "quantity": "Miktar",
478 "question_to_disable_2fa": "Cake 2FA'yı devre dışı bırakmak istediğinizden emin misiniz? M-cüzdana ve belirli işlevlere erişmek için artık 2FA koduna gerek kalmayacak.",
479 "receivable_balance": "Alacak bakiyesi",
480 "receive": "Para Al",
@@ -708,6 +716,7 @@
716 "tokenID": "İD",
717 "tor_connection": "Tor bağlantısı",
718 "tor_only": "Yalnızca Tor",
719 + "total": "Toplam",
720 "total_saving": "Toplam Tasarruf",
721 "totp_2fa_failure": "Yanlış kod. Lütfen farklı bir kod deneyin veya yeni bir gizli anahtar oluşturun. 8 basamaklı kodları ve SHA512'yi destekleyen uyumlu bir 2FA uygulaması kullanın.",
722 "totp_2fa_success": "Başarı! Bu cüzdan için Cake 2FA etkinleştirildi. Mnemonic seed'inizi cüzdan erişiminizi kaybetme ihtimaline karşı kaydetmeyi unutmayın.",
@@ -798,6 +807,8 @@
807 "use_ssl": "SSL kullan",
808 "use_suggested": "Önerileni Kullan",
809 "use_testnet": "TestNet kullanın",
810 + "value": "Değer",
811 + "value_type": "Değer türü",
812 "variable_pair_not_supported": "Bu değişken paritesi seçilen borsalarda desteklenmemekte",
813 "verification": "Doğrulama",
814 "verify_with_2fa": "Cake 2FA ile Doğrulayın",
res/values/strings_uk.arb
+13 -2
@@ -87,6 +87,7 @@
87 "buy": "Купити",
88 "buy_alert_content": "Наразі ми підтримуємо купівлю лише Bitcoin, Ethereum, Litecoin і Monero. Створіть або перейдіть на свій гаманець Bitcoin, Ethereum, Litecoin або Monero.",
89 "buy_bitcoin": "Купити Bitcoin",
90 + "buy_now": "Купити зараз",
91 "buy_provider_unavailable": "В даний час постачальник недоступний.",
92 "buy_with": "Купити за допомогою",
93 "by_cake_pay": "від Cake Pay",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "Темна тема торта",
96 "cake_pay_account_note": "Зареєструйтеся, використовуючи лише адресу електронної пошти, щоб переглядати та купувати картки. Деякі навіть доступні зі знижкою!",
97 "cake_pay_learn_more": "Миттєво купуйте та активуйте подарункові картки в додатку!\nПроведіть пальцем зліва направо, щоб дізнатися більше.",
97 - "cake_pay_subtitle": "Купуйте подарункові картки зі знижкою (тільки для США)",
98 - "cake_pay_title": "Подарункові картки Cake Pay",
98 + "cake_pay_subtitle": "Купіть у всьому світі передплачені картки та подарункові картки",
99 "cake_pay_web_cards_subtitle": "Купуйте передоплачені та подарункові картки по всьому світу",
100 "cake_pay_web_cards_title": "Веб-картки Cake Pay",
101 "cake_wallet": "Cake Wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "Змінити поточний гаманець",
124 "choose_account": "Оберіть акаунт",
125 "choose_address": "\n\nБудь ласка, оберіть адресу:",
126 + "choose_card_value": "Виберіть значення картки",
127 "choose_derivation": "Виберіть деривацію гаманця",
128 "choose_from_available_options": "Виберіть із доступних варіантів:",
129 "choose_one": "Вибери один",
@@ -166,6 +167,7 @@
167 "copy_address": "Cкопіювати адресу",
168 "copy_id": "Скопіювати ID",
169 "copyWalletConnectLink": "Скопіюйте посилання WalletConnect із dApp і вставте сюди",
170 + "countries": "Країни",
171 "create_account": "Створити обліковий запис",
172 "create_backup": "Створити резервну копію",
173 "create_donation_link": "Створити посилання для пожертв",
@@ -178,6 +180,7 @@
180 "custom": "на замовлення",
181 "custom_drag": "На замовлення (утримуйте та перетягується)",
182 "custom_redeem_amount": "Власна сума викупу",
183 + "custom_value": "Спеціальне значення",
184 "dark_theme": "Темна",
185 "debit_card": "Дебетова картка",
186 "debit_card_terms": "Зберігання та використання номера вашої платіжної картки (та облікових даних, які відповідають номеру вашої платіжної картки) у цьому цифровому гаманці регулюються Умовами відповідної угоди власника картки з емітентом платіжної картки, що діє з час від часу.",
@@ -190,6 +193,7 @@
193 "delete_wallet": "Видалити гаманець",
194 "delete_wallet_confirm_message": "Ви впевнені, що хочете видалити гаманець ${wallet_name}?",
195 "deleteConnectionConfirmationPrompt": "Ви впевнені, що хочете видалити з’єднання з",
196 + "denominations": "Конфесія",
197 "descending": "Низхідний",
198 "description": "опис",
199 "destination_tag": "Тег призначення:",
@@ -277,6 +281,7 @@
281 "expired": "Закінчується",
282 "expires": "Закінчується",
283 "expiresOn": "Термін дії закінчується",
284 + "expiry_and_validity": "Закінчення та обгрунтованість",
285 "export_backup": "Експортувати резервну копію",
286 "extra_id": "Додатковий ID:",
287 "extracted_address_content": "Ви будете відправляти кошти\n${recipient_name}",
@@ -384,6 +389,7 @@
389 "new_template": "Новий шаблон",
390 "new_wallet": "Новий гаманець",
391 "newConnection": "Нове підключення",
392 + "no_cards_found": "Карт не знайдено",
393 "no_id_needed": "Ідентифікатор не потрібен!",
394 "no_id_required": "Ідентифікатор не потрібен. Поповнюйте та витрачайте будь-де",
395 "no_relay_on_domain": "Немає ретранслятора для домену користувача або ретранслятор недоступний. Будь ласка, виберіть реле для використання.",
@@ -452,6 +458,7 @@
458 "pre_seed_button_text": "Зрозуміло. Покажіть мнемонічну фразу",
459 "pre_seed_description": "На наступній сторінці ви побачите серію з ${words} слів. Це ваша унікальна та приватна мнемонічна фраза, і це ЄДИНИЙ спосіб відновити ваш гаманець на випадок втрати або несправності. ВАМ необхідно записати її та зберігати в безпечному місці поза програмою Cake Wallet.",
460 "pre_seed_title": "ВАЖЛИВО",
461 + "prepaid_cards": "Передплачені картки",
462 "prevent_screenshots": "Запобігати знімкам екрана та запису екрана",
463 "privacy": "Конфіденційність",
464 "privacy_policy": "Політика конфіденційності",
@@ -467,6 +474,7 @@
474 "purple_dark_theme": "Фіолетова темна тема",
475 "qr_fullscreen": "Торкніться, щоб відкрити QR-код на весь екран",
476 "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?",
477 + "quantity": "Кількість",
478 "question_to_disable_2fa": "Ви впевнені, що хочете вимкнути Cake 2FA? Код 2FA більше не потрібен для доступу до гаманця та певних функцій.",
479 "receivable_balance": "Баланс дебіторської заборгованості",
480 "receive": "Отримати",
@@ -709,6 +717,7 @@
717 "tokenID": "ID",
718 "tor_connection": "Підключення Tor",
719 "tor_only": "Тільки Tor",
720 + "total": "Загальний",
721 "total_saving": "Загальна економія",
722 "totp_2fa_failure": "Невірний код. Спробуйте інший код або створіть новий секретний ключ. Використовуйте сумісний додаток 2FA, який підтримує 8-значні коди та SHA512.",
723 "totp_2fa_success": "Успіх! Cake 2FA увімкнено для цього гаманця. Пам’ятайте про збереження мнемоніки на випадок, якщо ви втратите доступ до гаманця.",
@@ -799,6 +808,8 @@
808 "use_ssl": "Використати SSL",
809 "use_suggested": "Використати запропоноване",
810 "use_testnet": "Використовуйте тестову мережу",
811 + "value": "Цінність",
812 + "value_type": "Тип значення",
813 "variable_pair_not_supported": "Ця пара змінних не підтримується вибраними біржами",
814 "verification": "Перевірка",
815 "verify_with_2fa": "Перевірте за допомогою Cake 2FA",
res/values/strings_ur.arb
+13 -2
@@ -87,6 +87,7 @@
87 "buy": "خریدنے",
88 "buy_alert_content": "۔ﮟﯾﺮﮐ ﭻﺋﻮﺳ ﺮﭘ ﺱﺍ ﺎﯾ ﮟﯿﺋﺎﻨﺑ ﭧﯿﻟﺍﻭ Monero ﺎﯾ ،Bitcoin، Ethereum، Litecoin ﺎﻨﭘﺍ ﻡ",
89 "buy_bitcoin": "Bitcoin خریدیں۔",
90 + "buy_now": "ابھی خریدئے",
91 "buy_provider_unavailable": "فراہم کنندہ فی الحال دستیاب نہیں ہے۔",
92 "buy_with": "کے ساتھ خریدیں۔",
93 "by_cake_pay": "Cake پے کے ذریعے",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "کیک ڈارک تھیم",
96 "cake_pay_account_note": "کارڈز دیکھنے اور خریدنے کے لیے صرف ایک ای میل ایڈریس کے ساتھ سائن اپ کریں۔ کچھ رعایت پر بھی دستیاب ہیں!",
97 "cake_pay_learn_more": "ایپ میں فوری طور پر گفٹ کارڈز خریدیں اور بھنائیں!\\nمزید جاننے کے لیے بائیں سے دائیں سوائپ کریں۔",
97 - "cake_pay_subtitle": "رعایتی گفٹ کارڈز خریدیں (صرف امریکہ)",
98 - "cake_pay_title": "Cake پے گفٹ کارڈز",
98 + "cake_pay_subtitle": "دنیا بھر میں پری پیڈ کارڈز اور گفٹ کارڈ خریدیں",
99 "cake_pay_web_cards_subtitle": "دنیا بھر میں پری پیڈ کارڈز اور گفٹ کارڈز خریدیں۔",
100 "cake_pay_web_cards_title": "Cake پے ویب کارڈز",
101 "cake_wallet": "Cake والیٹ",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "موجودہ پرس تبدیل کریں۔",
124 "choose_account": "اکاؤنٹ کا انتخاب کریں۔",
125 "choose_address": "\\n\\nبراہ کرم پتہ منتخب کریں:",
126 + "choose_card_value": "کارڈ کی قیمت کا انتخاب کریں",
127 "choose_derivation": "پرس سے ماخوذ منتخب کریں",
128 "choose_from_available_options": "دستیاب اختیارات میں سے انتخاب کریں:",
129 "choose_one": "ایک کا انتخاب کریں",
@@ -166,6 +167,7 @@
167 "copy_address": "ایڈریس کاپی کریں۔",
168 "copy_id": "کاپی ID",
169 "copyWalletConnectLink": "dApp ﮯﺳ WalletConnect ۔ﮟﯾﺮﮐ ﭧﺴﯿﭘ ﮞﺎﮩﯾ ﺭﻭﺍ ﮟﯾﺮﮐ ﯽﭘﺎﮐ ﻮﮐ ﮏﻨﻟ",
170 + "countries": "ممالک",
171 "create_account": "اکاؤنٹ بنائیں",
172 "create_backup": "بیک اپ بنائیں",
173 "create_donation_link": "عطیہ کا لنک بنائیں",
@@ -178,6 +180,7 @@
180 "custom": "اپنی مرضی کے مطابق",
181 "custom_drag": "کسٹم (ہولڈ اینڈ ڈریگ)",
182 "custom_redeem_amount": "حسب ضرورت چھڑانے کی رقم",
183 + "custom_value": "کسٹم ویلیو",
184 "dark_theme": "اندھیرا",
185 "debit_card": "ڈیبٹ کارڈ",
186 "debit_card_terms": "اس ڈیجیٹل والیٹ میں آپ کے ادائیگی کارڈ نمبر (اور آپ کے ادائیگی کارڈ نمبر سے متعلقہ اسناد) کا ذخیرہ اور استعمال ادائیگی کارڈ جاری کنندہ کے ساتھ قابل اطلاق کارڈ ہولڈر کے معاہدے کی شرائط و ضوابط کے ساتھ مشروط ہے، جیسا کہ وقتاً فوقتاً نافذ ہوتا ہے۔",
@@ -190,6 +193,7 @@
193 "delete_wallet": "پرس کو حذف کریں۔",
194 "delete_wallet_confirm_message": "کیا آپ واقعی ${wallet_name} والیٹ کو حذف کرنا چاہتے ہیں؟",
195 "deleteConnectionConfirmationPrompt": "۔ﮟﯿﮨ ﮯﺘﮨﺎﭼ ﺎﻧﺮﮐ ﻑﺬﺣ ﻮﮐ ﻦﺸﮑﻨﮐ ﭖﺁ ﮧﮐ ﮯﮨ ﻦﯿﻘﯾ ﻮﮐ ﭖﺁ ﺎﯿﮐ",
196 + "denominations": "فرق",
197 "descending": "اترتے ہوئے",
198 "description": "ﻞﯿﺼﻔﺗ",
199 "destination_tag": "منزل کا ٹیگ:",
@@ -277,6 +281,7 @@
281 "expired": "میعاد ختم",
282 "expires": "میعاد ختم",
283 "expiresOn": "ﺩﺎﻌﯿﻣ ﯽﻣﺎﺘﺘﺧﺍ",
284 + "expiry_and_validity": "میعاد ختم اور صداقت",
285 "export_backup": "بیک اپ برآمد کریں۔",
286 "extra_id": "اضافی ID:",
287 "extracted_address_content": "آپ فنڈز بھیج رہے ہوں گے\n${recipient_name}",
@@ -384,6 +389,7 @@
389 "new_template": "نیا سانچہ",
390 "new_wallet": "نیا پرس",
391 "newConnection": "ﻦﺸﮑﻨﮐ ﺎﯿﻧ",
392 + "no_cards_found": "کوئی کارڈ نہیں ملا",
393 "no_id_needed": "شناخت کی ضرورت نہیں!",
394 "no_id_required": "کوئی ID درکار نہیں۔ ٹاپ اپ اور کہیں بھی خرچ کریں۔",
395 "no_relay_on_domain": "۔ﮟﯾﺮﮐ ﺏﺎﺨﺘﻧﺍ ﺎﮐ ﮯﻠﯾﺭ ﮯﯿﻟ ﮯﮐ ﮯﻧﺮﮐ ﻝﺎﻤﻌﺘﺳﺍ ﻡﺮﮐ ﮦﺍﺮﺑ ۔ﮯﮨ ﮟﯿﮩﻧ ﺏﺎﯿﺘﺳﺩ ﮯﻠﯾﺭ ﺎﯾ ﮯﮨ ﮟ",
@@ -454,6 +460,7 @@
460 "pre_seed_button_text": "میں سمجھتا ہوں۔ مجھے میرا بیج دکھاؤ",
461 "pre_seed_description": "اگلے صفحے پر آپ کو ${words} الفاظ کا ایک سلسلہ نظر آئے گا۔ یہ آپ کا انوکھا اور نجی بیج ہے اور یہ آپ کے بٹوے کو ضائع یا خرابی کی صورت میں بازیافت کرنے کا واحد طریقہ ہے۔ اسے لکھنا اور اسے کیک والیٹ ایپ سے باہر کسی محفوظ جگہ پر اسٹور کرنا آپ کی ذمہ داری ہے۔",
462 "pre_seed_title": "اہم",
463 + "prepaid_cards": "پری پیڈ کارڈز",
464 "prevent_screenshots": "اسکرین شاٹس اور اسکرین ریکارڈنگ کو روکیں۔",
465 "privacy": "رازداری",
466 "privacy_policy": "رازداری کی پالیسی",
@@ -469,6 +476,7 @@
476 "purple_dark_theme": "ارغوانی ڈارک تھیم",
477 "qr_fullscreen": "فل سکرین QR کوڈ کھولنے کے لیے تھپتھپائیں۔",
478 "qr_payment_amount": "اس QR کوڈ میں ادائیگی کی رقم شامل ہے۔ کیا آپ موجودہ قدر کو اوور رائٹ کرنا چاہتے ہیں؟",
479 + "quantity": "مقدار",
480 "question_to_disable_2fa": "کیا آپ واقعی کیک 2FA کو غیر فعال کرنا چاہتے ہیں؟ بٹوے اور بعض افعال تک رسائی کے لیے اب 2FA کوڈ کی ضرورت نہیں ہوگی۔",
481 "receivable_balance": "قابل وصول توازن",
482 "receive": "وصول کریں۔",
@@ -710,6 +718,7 @@
718 "tokenID": "ID",
719 "tor_connection": "ﻦﺸﮑﻨﮐ ﺭﻮﭨ",
720 "tor_only": "صرف Tor",
721 + "total": "کل",
722 "total_saving": "کل بچت",
723 "totp_2fa_failure": "غلط کوڈ. براہ کرم ایک مختلف کوڈ آزمائیں یا ایک نئی خفیہ کلید بنائیں۔ ایک ہم آہنگ 2FA ایپ استعمال کریں جو 8 ہندسوں کے کوڈز اور SHA512 کو سپورٹ کرتی ہو۔",
724 "totp_2fa_success": "کامیابی! کیک 2FA اس بٹوے کے لیے فعال ہے۔ بٹوے تک رسائی سے محروم ہونے کی صورت میں اپنے یادداشت کے بیج کو محفوظ کرنا یاد رکھیں۔",
@@ -800,6 +809,8 @@
809 "use_ssl": "SSL استعمال کریں۔",
810 "use_suggested": "تجویز کردہ استعمال کریں۔",
811 "use_testnet": "ٹیسٹ نیٹ استعمال کریں",
812 + "value": "قدر",
813 + "value_type": "قدر کی قسم",
814 "variable_pair_not_supported": "یہ متغیر جوڑا منتخب ایکسچینجز کے ساتھ تعاون یافتہ نہیں ہے۔",
815 "verification": "تصدیق",
816 "verify_with_2fa": "کیک 2FA سے تصدیق کریں۔",
res/values/strings_yo.arb
+14 -3
@@ -87,6 +87,7 @@
87 "buy": "Rà",
88 "buy_alert_content": "Lọwọlọwọ a ṣe atilẹyin rira Bitcoin, Ethereum, Litecoin, ati Monero. Jọwọ ṣẹda tabi yipada si Bitcoin, Ethereum, Litecoin, tabi apamọwọ Monero.",
89 "buy_bitcoin": "Ra Bitcoin",
90 + "buy_now": "Ra Bayibayi",
91 "buy_provider_unavailable": "Olupese lọwọlọwọ ko si.",
92 "buy_with": "Rà pẹ̀lú",
93 "by_cake_pay": "láti ọwọ́ Cake Pay",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "Akara oyinbo dudu koko",
96 "cake_pay_account_note": "Ẹ fi àdírẹ́sì ímeèlì nìkan forúkọ sílẹ̀ k'ẹ́ rí àti ra àwọn káàdì. Ẹ lè fi owó tó kéré jù ra àwọn káàdì kan!",
97 "cake_pay_learn_more": "Láìpẹ́ ra àti lo àwọn káàdí ìrajà t'á lò nínú irú kan ìtajà nínú áàpù!\nẸ tẹ̀ òsì de ọ̀tún láti kọ́ jù.",
97 - "cake_pay_subtitle": "Ra àwọn káàdì ìrajà t'á lò nínú ìtajà kan fún owó tí kò pọ̀ (USA nìkan)",
98 - "cake_pay_title": "Àwọn káàdì ìrajà t'á lò nínú ìtajà kan ti Cake Pay",
98 + "cake_pay_subtitle": "Ra awọn kaadi ti a san ni agbaye ati awọn kaadi ẹbun",
99 "cake_pay_web_cards_subtitle": "Ra àwọn káàdì ìrajà t'á lò nínú ìtajà kan àti àwọn káàdì náà t'á lè lò níbikíbi",
100 "cake_pay_web_cards_title": "Àwọn káàdì wẹ́ẹ̀bù ti Cake Pay",
101 "cake_wallet": "Cake Wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "Ẹ pààrọ̀ àpamọ́wọ́ yìí",
124 "choose_account": "Yan àkáǹtì",
125 "choose_address": "\n\nẸ jọ̀wọ́ yan àdírẹ́sì:",
126 + "choose_card_value": "Yan iye kaadi",
127 "choose_derivation": "Yan awọn apamọwọ apamọwọ",
128 "choose_from_available_options": "Ẹ yàn láti àwọn ìyàn yìí:",
129 "choose_one": "Ẹ yàn kan",
@@ -166,6 +167,7 @@
167 "copy_address": "Ṣẹ̀dà àdírẹ́sì",
168 "copy_id": "Ṣẹ̀dà àmì ìdánimọ̀",
169 "copyWalletConnectLink": "Daakọ ọna asopọ WalletConnect lati dApp ki o si lẹẹmọ nibi",
170 + "countries": "Awọn orilẹ-ede",
171 "create_account": "Dá àkáǹtì",
172 "create_backup": "Ṣẹ̀dà nípamọ́",
173 "create_donation_link": "Ṣe kọọkan alabara asopọ",
@@ -178,6 +180,7 @@
180 "custom": "Ohun t'á ti pààrọ̀",
181 "custom_drag": "Aṣa (mu ati fa)",
182 "custom_redeem_amount": "Iye owó l'á máa ná",
183 + "custom_value": "Iye aṣa",
184 "dark_theme": "Dúdú",
185 "debit_card": "Káàdì ìrajà",
186 "debit_card_terms": "Òfin ti olùṣe àjọrò káàdì ìrajà bójú irú ọ̀nà t'á pamọ́ àti a lo òǹkà ti káàdì ìrajà yín (àti ọ̀rọ̀ ìdánimọ̀ tí káàdì náà) nínú àpamọ́wọ́ yìí.",
@@ -190,6 +193,7 @@
193 "delete_wallet": "Pa àpamọ́wọ́",
194 "delete_wallet_confirm_message": "Ṣó dá ẹ lójú pé ẹ fẹ́ pa àpamọ́wọ́ ${wallet_name}?",
195 "deleteConnectionConfirmationPrompt": "Ṣe o da ọ loju pe o fẹ paarẹ asopọ si",
196 + "denominations": "Awọn ede",
197 "descending": "Sọkalẹ",
198 "description": "Apejuwe",
199 "destination_tag": "Orúkọ tí ìbí tó a ránṣẹ́ sí:",
@@ -278,6 +282,7 @@
282 "expired": "Kíkú",
283 "expires": "Ó parí",
284 "expiresOn": "Ipari lori",
285 + "expiry_and_validity": "Ipari ati idaniloju",
286 "export_backup": "Sún ẹ̀dà nípamọ́ síta",
287 "extra_id": "Àmì ìdánimọ̀ tó fikún:",
288 "extracted_address_content": "Ẹ máa máa fi owó ránṣẹ́ sí\n${recipient_name}",
@@ -309,7 +314,7 @@
314 "gift_card_is_generated": "A ti dá káàdí ìrajà t'á lò nínú irú kan ìtajà",
315 "gift_card_number": "Òǹkà káàdì ìrajì",
316 "gift_card_redeemed_note": "Àwọn káàdì ìrajà t'á lò nínú irú kan ìtajà t'ẹ́ ti lò máa fihàn ḿbí",
312 - "gift_cards": "Àwọn káàdì ìrajà t'á lò nínú iye kan ìtajà",
317 + "gift_cards": "Awọn kaadi ẹbun",
318 "gift_cards_unavailable": "A lè fi Monero, Bitcoin, àti Litecoin nìkan ra káàdí ìrajà t'á lò nínú irú kan ìtajà lọ́wọ́lọ́wọ́",
319 "got_it": "Ó dáa",
320 "gross_balance": "Iwontunws.funfun apapọ",
@@ -385,6 +390,7 @@
390 "new_template": "Àwòṣe títun",
391 "new_wallet": "Àpamọ́wọ́ títun",
392 "newConnection": "Tuntun Asopọ",
393 + "no_cards_found": "Ko si awọn kaadi ti a rii",
394 "no_id_needed": "Ẹ kò nílò àmì ìdánimọ̀!",
395 "no_id_required": "Ẹ kò nílò àmì ìdánimọ̀. Ẹ lè fikún owó àti san níbikíbi",
396 "no_relay_on_domain": "Ko si iṣipopada fun agbegbe olumulo tabi yiyi ko si. Jọwọ yan yii lati lo.",
@@ -453,6 +459,7 @@
459 "pre_seed_button_text": "Mo ti gbọ́. O fi hóró mi hàn mi",
460 "pre_seed_description": "Ẹ máa wo àwọn ọ̀rọ̀ ${words} lórí ojú tó ń bọ̀. Èyí ni hóró aládàáni yín tó kì í jọra. Ẹ lè fi í nìkan dá àpamọ́wọ́ yín padà sípò tí àṣìṣe tàbí ìbàjẹ́ bá ṣẹlẹ̀. Hóró yín ni ẹ gbọ́dọ̀ kọ sílẹ̀ àti pamọ́ síbí tó kò léwu níta Cake Wallet.",
461 "pre_seed_title": "Ó TI ṢE PÀTÀKÌ",
462 + "prepaid_cards": "Awọn kaadi ti a ti sanwo",
463 "prevent_screenshots": "Pese asapọ ti awọn ẹrọ eto aṣa",
464 "privacy": "Ìdáwà",
465 "privacy_policy": "Òfin Aládàáni",
@@ -468,6 +475,7 @@
475 "purple_dark_theme": "Akọle dudu dudu",
476 "qr_fullscreen": "Àmì ìlujá túbọ̀ máa tóbi tí o bá tẹ̀",
477 "qr_payment_amount": "Iye owó t'á ránṣé wà nínú àmì ìlujá yìí. Ṣé ẹ fẹ́ pààrọ̀ ẹ̀?",
478 + "quantity": "Ọpọ",
479 "question_to_disable_2fa": "Ṣe o wa daadaa pe o fẹ ko 2FA Cake? Ko si itumọ ti a yoo nilo lati ranse si iwe iwe naa ati eyikeyi iṣẹ ti o ni.",
480 "receivable_balance": "Iwontunws.funfun ti o gba",
481 "receive": "Gbà",
@@ -709,6 +717,7 @@
717 "tokenID": "ID",
718 "tor_connection": "Tor asopọ",
719 "tor_only": "Tor nìkan",
720 + "total": "Apapọ",
721 "total_saving": "Owó t'ẹ́ ti pamọ́",
722 "totp_2fa_failure": "Koodu ti o daju ko ri. Jọwọ jẹ koodu miiran tabi ṣiṣẹ iwe kiakia. Lo fun 2FA eto ti o ba ṣe ni jẹ 2FA ti o gba idaniloju 8-digits ati SHA512.",
723 "totp_2fa_success": "Pelu ogo! Cake 2FA ti fi sii lori iwe iwe yii. Tọ, mọ iye ẹrọ miiran akojọrọ jẹki o kọ ipin eto.",
@@ -799,6 +808,8 @@
808 "use_ssl": "Lo SSL",
809 "use_suggested": "Lo àbá",
810 "use_testnet": "Lo tele",
811 + "value": "Iye",
812 + "value_type": "Iru iye",
813 "variable_pair_not_supported": "A kì í ṣe k'á fi àwọn ilé pàṣípààrọ̀ yìí ṣe pàṣípààrọ̀ irú owó méji yìí",
814 "verification": "Ìjẹ́rìísí",
815 "verify_with_2fa": "Ṣeẹda pẹlu Cake 2FA",
res/values/strings_zh.arb
+13 -2
@@ -87,6 +87,7 @@
87 "buy": "购买",
88 "buy_alert_content": "目前我们仅支持购买比特币、以太坊、莱特币和门罗币。请创建或切换到您的比特币、以太坊、莱特币或门罗币钱包。",
89 "buy_bitcoin": "购买比特币",
90 + "buy_now": "立即购买",
91 "buy_provider_unavailable": "提供者目前不可用。",
92 "buy_with": "一起购买",
93 "by_cake_pay": "通过 Cake Pay",
@@ -94,8 +95,7 @@
95 "cake_dark_theme": "蛋糕黑暗主题",
96 "cake_pay_account_note": "只需使用電子郵件地址註冊即可查看和購買卡片。有些甚至可以打折!",
97 "cake_pay_learn_more": "立即在应用中购买和兑换礼品卡!\n从左向右滑动以了解详情。",
97 - "cake_pay_subtitle": "购买打折礼品卡(仅限美国)",
98 - "cake_pay_title": "Cake Pay 礼品卡",
98 + "cake_pay_subtitle": "购买全球预付费卡和礼品卡",
99 "cake_pay_web_cards_subtitle": "购买全球预付卡和礼品卡",
100 "cake_pay_web_cards_title": "蛋糕支付网络卡",
101 "cake_wallet": "Cake Wallet",
@@ -123,6 +123,7 @@
123 "change_wallet_alert_title": "更换当前钱包",
124 "choose_account": "选择账户",
125 "choose_address": "\n\n請選擇地址:",
126 + "choose_card_value": "选择卡值",
127 "choose_derivation": "选择钱包推导",
128 "choose_from_available_options": "从可用选项中选择:",
129 "choose_one": "选一个",
@@ -166,6 +167,7 @@
167 "copy_address": "复制地址",
168 "copy_id": "复制ID",
169 "copyWalletConnectLink": "从 dApp 复制 WalletConnect 链接并粘贴到此处",
170 + "countries": "国家",
171 "create_account": "创建账户",
172 "create_backup": "创建备份",
173 "create_donation_link": "创建捐赠链接",
@@ -178,6 +180,7 @@
180 "custom": "自定义",
181 "custom_drag": "定制(保持和拖动)",
182 "custom_redeem_amount": "自定义兑换金额",
183 + "custom_value": "自定义值",
184 "dark_theme": "黑暗",
185 "debit_card": "借记卡",
186 "debit_card_terms": "您的支付卡号(以及与您的支付卡号对应的凭证)在此数字钱包中的存储和使用受适用的持卡人与支付卡发卡机构签订的协议的条款和条件的约束,自时不时。",
@@ -190,6 +193,7 @@
193 "delete_wallet": "删除钱包",
194 "delete_wallet_confirm_message": "您确定要删除 ${wallet_name} 钱包吗?",
195 "deleteConnectionConfirmationPrompt": "您确定要删除与",
196 + "denominations": "教派",
197 "descending": "下降",
198 "description": "描述",
199 "destination_tag": "目标Tag:",
@@ -277,6 +281,7 @@
281 "expired": "已过期",
282 "expires": "过期",
283 "expiresOn": "到期",
284 + "expiry_and_validity": "到期和有效性",
285 "export_backup": "导出备份",
286 "extra_id": "额外ID:",
287 "extracted_address_content": "您将汇款至\n${recipient_name}",
@@ -384,6 +389,7 @@
389 "new_template": "新模板",
390 "new_wallet": "新钱包",
391 "newConnection": "新连接",
392 + "no_cards_found": "找不到卡",
393 "no_id_needed": "不需要 ID!",
394 "no_id_required": "不需要身份证。充值并在任何地方消费",
395 "no_relay_on_domain": "用户域没有中继或中继不可用。请选择要使用的继电器。",
@@ -452,6 +458,7 @@
458 "pre_seed_button_text": "我明白。 查看种子",
459 "pre_seed_description": "在下一页上,您将看到${words}个文字。 这是您独有的种子,是丟失或出现故障时恢复钱包的唯一方法。 您有必须将其写下并储存在Cake Wallet应用程序以外的安全地方。",
460 "pre_seed_title": "重要",
461 + "prepaid_cards": "预付费卡",
462 "prevent_screenshots": "防止截屏和录屏",
463 "privacy": "隐私",
464 "privacy_policy": "隐私政策",
@@ -467,6 +474,7 @@
474 "purple_dark_theme": "紫色的黑暗主题",
475 "qr_fullscreen": "点击打开全屏二维码",
476 "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?",
477 + "quantity": "数量",
478 "question_to_disable_2fa": "您确定要禁用 Cake 2FA 吗?访问钱包和某些功能将不再需要 2FA 代码。",
479 "receivable_balance": "应收余额",
480 "receive": "接收",
@@ -708,6 +716,7 @@
716 "tokenID": "ID",
717 "tor_connection": "Tor连接",
718 "tor_only": "仅限 Tor",
719 + "total": "全部的",
720 "total_saving": "总储蓄",
721 "totp_2fa_failure": "不正确的代码。 请尝试不同的代码或生成新的密钥。 使用支持 8 位代码和 SHA512 的兼容 2FA 应用程序。",
722 "totp_2fa_success": "成功!为此钱包启用了 Cake 2FA。请记住保存您的助记词种子,以防您无法访问钱包。",
@@ -798,6 +807,8 @@
807 "use_ssl": "使用SSL",
808 "use_suggested": "使用建议",
809 "use_testnet": "使用TestNet",
810 + "value": "价值",
811 + "value_type": "值类型",
812 "variable_pair_not_supported": "所选交易所不支持此变量对",
813 "verification": "验证",
814 "verify_with_2fa": "用 Cake 2FA 验证",
scripts/android/inject_app_details.sh
+1 -1
@@ -6,7 +6,7 @@ if [ -z "$APP_ANDROID_TYPE" ]; then
6 fi
7
8 cd ../..
9 -sed -i "0,/version:/{s/version:.*/version: ${APP_ANDROID_VERSION}+${APP_ANDROID_BUILD_NUMBER}/}" ./pubspec.yaml
9 +sed -i "0,/version:/{s/version:.*/version: ${APP_ANDROID_VERSION}+${APP_ANDROID_BUILD_NUMBER}/}" ./pubspec.yaml
10 sed -i "0,/version:/{s/__APP_PACKAGE__/${APP_ANDROID_PACKAGE}/}" ./android/app/src/main/AndroidManifest.xml
11 sed -i "0,/__APP_SCHEME__/s/__APP_SCHEME__/${APP_ANDROID_SCHEME}/" ./android/app/src/main/AndroidManifest.xml
12 sed -i "0,/version:/{s/__versionCode__/${APP_ANDROID_BUILD_NUMBER}/}" ./android/app/src/main/AndroidManifest.xml