From 30dc8f9238950226833c0adc861f0cc96158217f Mon Sep 17 00:00:00 2001 From: Serhii Date: Thu, 6 Jun 2024 04:51:22 +0000 Subject: [PATCH] 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 --- .github/workflows/pr_test_build.yml | 4 + lib/cake_pay/cake_pay_api.dart | 245 +++++++++ lib/cake_pay/cake_pay_card.dart | 87 ++++ lib/cake_pay/cake_pay_order.dart | 131 +++++ .../cake_pay_payment_credantials.dart | 15 + lib/cake_pay/cake_pay_service.dart | 107 ++++ lib/cake_pay/cake_pay_states.dart | 67 +++ lib/cake_pay/cake_pay_user_credentials.dart | 6 + lib/cake_pay/cake_pay_vendor.dart | 51 ++ lib/di.dart | 230 +++------ lib/ionia/ionia_any_pay_payment_info.dart | 9 - lib/ionia/ionia_anypay.dart | 91 ---- lib/ionia/ionia_api.dart | 440 ---------------- lib/ionia/ionia_category.dart | 22 - lib/ionia/ionia_create_state.dart | 68 --- lib/ionia/ionia_gift_card.dart | 70 --- lib/ionia/ionia_gift_card_instruction.dart | 28 - lib/ionia/ionia_merchant.dart | 101 ---- lib/ionia/ionia_order.dart | 23 - lib/ionia/ionia_service.dart | 171 ------- lib/ionia/ionia_tip.dart | 18 - lib/ionia/ionia_token_data.dart | 43 -- lib/ionia/ionia_user_credentials.dart | 6 - lib/ionia/ionia_virtual_card.dart | 41 -- lib/router.dart | 95 +--- lib/routes.dart | 23 +- lib/src/screens/base_page.dart | 14 +- .../cake_pay/auth/cake_pay_account_page.dart | 90 ++++ .../auth/cake_pay_verify_otp_page.dart} | 40 +- .../auth/cake_pay_welcome_page.dart} | 65 ++- lib/src/screens/cake_pay/cake_pay.dart | 5 + .../cards/cake_pay_buy_card_page.dart | 474 +++++++++++++++++ .../cards/cake_pay_cards_page.dart} | 248 +++++---- .../cake_pay_confirm_purchase_card_page.dart | 403 +++++++++++++++ .../widgets/cake_pay_alert_modal.dart} | 4 +- .../widgets/cake_pay_tile.dart} | 4 +- .../screens/cake_pay/widgets/card_item.dart | 104 ++++ .../widgets/card_menu.dart | 0 .../cake_pay/widgets/image_placeholder.dart | 29 ++ .../cake_pay/widgets/link_extractor.dart | 66 +++ .../widgets/rounded_checkbox.dart | 0 .../widgets/text_icon_button.dart | 0 .../dashboard/pages/cake_features_page.dart | 52 +- .../dashboard/widgets/filter_widget.dart | 160 +++--- .../screens/dashboard/widgets/header_row.dart | 2 +- .../present_receive_option_picker.dart | 2 +- .../ionia/auth/ionia_create_account_page.dart | 159 ------ .../ionia/auth/ionia_welcome_page.dart | 95 ---- .../ionia/cards/ionia_account_cards_page.dart | 204 -------- .../ionia/cards/ionia_account_page.dart | 178 ------- .../cards/ionia_activate_debit_card_page.dart | 115 ----- .../cards/ionia_buy_card_detail_page.dart | 478 ------------------ .../ionia/cards/ionia_buy_gift_card.dart | 186 ------- .../ionia/cards/ionia_custom_redeem_page.dart | 175 ------- .../ionia/cards/ionia_custom_tip_page.dart | 177 ------- .../ionia/cards/ionia_debit_card_page.dart | 393 -------------- .../cards/ionia_gift_card_detail_page.dart | 215 -------- .../ionia/cards/ionia_more_options_page.dart | 91 ---- .../cards/ionia_payment_status_page.dart | 222 -------- lib/src/screens/ionia/ionia.dart | 9 - lib/src/screens/ionia/widgets/card_item.dart | 144 ------ .../ionia/widgets/ionia_filter_modal.dart | 132 ----- .../send/widgets/confirm_sending_alert.dart | 97 +++- lib/src/widgets/number_text_fild_widget.dart | 145 ++++++ .../cake_pay/cake_pay_account_view_model.dart | 20 + .../cake_pay/cake_pay_auth_view_model.dart | 51 ++ .../cake_pay_buy_card_view_model.dart | 48 ++ .../cake_pay_cards_list_view_model.dart | 221 ++++++++ .../cake_pay_purchase_view_model.dart | 162 ++++++ .../dashboard/cake_features_view_model.dart | 8 +- .../dashboard/dropdown_filter_item.dart | 19 + .../dropdown_filter_item_widget.dart | 68 +++ .../ionia/ionia_account_view_model.dart | 50 -- .../ionia/ionia_auth_view_model.dart | 69 --- .../ionia/ionia_buy_card_view_model.dart | 30 -- .../ionia/ionia_custom_redeem_view_model.dart | 51 -- .../ionia/ionia_custom_tip_view_model.dart | 34 -- .../ionia_gift_card_details_view_model.dart | 54 -- .../ionia_gift_cards_list_view_model.dart | 139 ----- .../ionia_payment_status_view_model.dart | 62 --- .../ionia_purchase_merch_view_model.dart | 104 ---- res/values/strings_ar.arb | 15 +- res/values/strings_bg.arb | 17 +- res/values/strings_cs.arb | 15 +- res/values/strings_de.arb | 17 +- res/values/strings_en.arb | 15 +- res/values/strings_es.arb | 15 +- res/values/strings_fr.arb | 17 +- res/values/strings_ha.arb | 15 +- res/values/strings_hi.arb | 15 +- res/values/strings_hr.arb | 17 +- res/values/strings_id.arb | 17 +- res/values/strings_it.arb | 15 +- res/values/strings_ja.arb | 15 +- res/values/strings_ko.arb | 15 +- res/values/strings_my.arb | 15 +- res/values/strings_nl.arb | 15 +- res/values/strings_pl.arb | 15 +- res/values/strings_pt.arb | 17 +- res/values/strings_ru.arb | 15 +- res/values/strings_th.arb | 15 +- res/values/strings_tl.arb | 15 +- res/values/strings_tr.arb | 17 +- res/values/strings_uk.arb | 15 +- res/values/strings_ur.arb | 15 +- res/values/strings_yo.arb | 17 +- res/values/strings_zh.arb | 15 +- scripts/android/inject_app_details.sh | 2 +- 108 files changed, 3500 insertions(+), 5267 deletions(-) create mode 100644 lib/cake_pay/cake_pay_api.dart create mode 100644 lib/cake_pay/cake_pay_card.dart create mode 100644 lib/cake_pay/cake_pay_order.dart create mode 100644 lib/cake_pay/cake_pay_payment_credantials.dart create mode 100644 lib/cake_pay/cake_pay_service.dart create mode 100644 lib/cake_pay/cake_pay_states.dart create mode 100644 lib/cake_pay/cake_pay_user_credentials.dart create mode 100644 lib/cake_pay/cake_pay_vendor.dart delete mode 100644 lib/ionia/ionia_any_pay_payment_info.dart delete mode 100644 lib/ionia/ionia_anypay.dart delete mode 100644 lib/ionia/ionia_api.dart delete mode 100644 lib/ionia/ionia_category.dart delete mode 100644 lib/ionia/ionia_create_state.dart delete mode 100644 lib/ionia/ionia_gift_card.dart delete mode 100644 lib/ionia/ionia_gift_card_instruction.dart delete mode 100644 lib/ionia/ionia_merchant.dart delete mode 100644 lib/ionia/ionia_order.dart delete mode 100644 lib/ionia/ionia_service.dart delete mode 100644 lib/ionia/ionia_tip.dart delete mode 100644 lib/ionia/ionia_token_data.dart delete mode 100644 lib/ionia/ionia_user_credentials.dart delete mode 100644 lib/ionia/ionia_virtual_card.dart create mode 100644 lib/src/screens/cake_pay/auth/cake_pay_account_page.dart rename lib/src/screens/{ionia/auth/ionia_verify_otp_page.dart => cake_pay/auth/cake_pay_verify_otp_page.dart} (81%) rename lib/src/screens/{ionia/auth/ionia_login_page.dart => cake_pay/auth/cake_pay_welcome_page.dart} (62%) create mode 100644 lib/src/screens/cake_pay/cake_pay.dart create mode 100644 lib/src/screens/cake_pay/cards/cake_pay_buy_card_page.dart rename lib/src/screens/{ionia/cards/ionia_manage_cards_page.dart => cake_pay/cards/cake_pay_cards_page.dart} (50%) create mode 100644 lib/src/screens/cake_pay/cards/cake_pay_confirm_purchase_card_page.dart rename lib/src/screens/{ionia/widgets/ionia_alert_model.dart => cake_pay/widgets/cake_pay_alert_modal.dart} (97%) rename lib/src/screens/{ionia/widgets/ionia_tile.dart => cake_pay/widgets/cake_pay_tile.dart} (94%) create mode 100644 lib/src/screens/cake_pay/widgets/card_item.dart rename lib/src/screens/{ionia => cake_pay}/widgets/card_menu.dart (100%) create mode 100644 lib/src/screens/cake_pay/widgets/image_placeholder.dart create mode 100644 lib/src/screens/cake_pay/widgets/link_extractor.dart rename lib/src/screens/{ionia => cake_pay}/widgets/rounded_checkbox.dart (100%) rename lib/src/screens/{ionia => cake_pay}/widgets/text_icon_button.dart (100%) delete mode 100644 lib/src/screens/ionia/auth/ionia_create_account_page.dart delete mode 100644 lib/src/screens/ionia/auth/ionia_welcome_page.dart delete mode 100644 lib/src/screens/ionia/cards/ionia_account_cards_page.dart delete mode 100644 lib/src/screens/ionia/cards/ionia_account_page.dart delete mode 100644 lib/src/screens/ionia/cards/ionia_activate_debit_card_page.dart delete mode 100644 lib/src/screens/ionia/cards/ionia_buy_card_detail_page.dart delete mode 100644 lib/src/screens/ionia/cards/ionia_buy_gift_card.dart delete mode 100644 lib/src/screens/ionia/cards/ionia_custom_redeem_page.dart delete mode 100644 lib/src/screens/ionia/cards/ionia_custom_tip_page.dart delete mode 100644 lib/src/screens/ionia/cards/ionia_debit_card_page.dart delete mode 100644 lib/src/screens/ionia/cards/ionia_gift_card_detail_page.dart delete mode 100644 lib/src/screens/ionia/cards/ionia_more_options_page.dart delete mode 100644 lib/src/screens/ionia/cards/ionia_payment_status_page.dart delete mode 100644 lib/src/screens/ionia/ionia.dart delete mode 100644 lib/src/screens/ionia/widgets/card_item.dart delete mode 100644 lib/src/screens/ionia/widgets/ionia_filter_modal.dart create mode 100644 lib/src/widgets/number_text_fild_widget.dart create mode 100644 lib/view_model/cake_pay/cake_pay_account_view_model.dart create mode 100644 lib/view_model/cake_pay/cake_pay_auth_view_model.dart create mode 100644 lib/view_model/cake_pay/cake_pay_buy_card_view_model.dart create mode 100644 lib/view_model/cake_pay/cake_pay_cards_list_view_model.dart create mode 100644 lib/view_model/cake_pay/cake_pay_purchase_view_model.dart create mode 100644 lib/view_model/dashboard/dropdown_filter_item.dart create mode 100644 lib/view_model/dashboard/dropdown_filter_item_widget.dart delete mode 100644 lib/view_model/ionia/ionia_account_view_model.dart delete mode 100644 lib/view_model/ionia/ionia_auth_view_model.dart delete mode 100644 lib/view_model/ionia/ionia_buy_card_view_model.dart delete mode 100644 lib/view_model/ionia/ionia_custom_redeem_view_model.dart delete mode 100644 lib/view_model/ionia/ionia_custom_tip_view_model.dart delete mode 100644 lib/view_model/ionia/ionia_gift_card_details_view_model.dart delete mode 100644 lib/view_model/ionia/ionia_gift_cards_list_view_model.dart delete mode 100644 lib/view_model/ionia/ionia_payment_status_view_model.dart delete mode 100644 lib/view_model/ionia/ionia_purchase_merch_view_model.dart diff --git a/.github/workflows/pr_test_build.yml b/.github/workflows/pr_test_build.yml index b4ddcfefe..841ea570d 100644 --- a/.github/workflows/pr_test_build.yml +++ b/.github/workflows/pr_test_build.yml @@ -151,6 +151,10 @@ jobs: echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_evm/lib/.secrets.g.dart echo "const ankrApiKey = '${{ secrets.ANKR_API_KEY }}';" >> cw_solana/lib/.secrets.g.dart + echo "const testCakePayApiKey = '${{ secrets.TEST_CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart + echo "const cakePayApiKey = '${{ secrets.CAKE_PAY_API_KEY }}';" >> lib/.secrets.g.dart + echo "const authorization = '${{ secrets.CAKE_PAY_AUTHORIZATION }}';" >> lib/.secrets.g.dart + echo "const CSRFToken = '${{ secrets.CSRF_TOKEN }}';" >> lib/.secrets.g.dart echo "const quantexExchangeMarkup = '${{ secrets.QUANTEX_EXCHANGE_MARKUP }}';" >> lib/.secrets.g.dart echo "const nano2ApiKey = '${{ secrets.NANO2_API_KEY }}';" >> cw_nano/lib/.secrets.g.dart echo "const tronGridApiKey = '${{ secrets.TRON_GRID_API_KEY }}';" >> cw_tron/lib/.secrets.g.dart diff --git a/lib/cake_pay/cake_pay_api.dart b/lib/cake_pay/cake_pay_api.dart new file mode 100644 index 000000000..f403ebc63 --- /dev/null +++ b/lib/cake_pay/cake_pay_api.dart @@ -0,0 +1,245 @@ +import 'dart:convert'; + +import 'package:cake_wallet/cake_pay/cake_pay_order.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_user_credentials.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_vendor.dart'; +import 'package:http/http.dart' as http; + +class CakePayApi { + static const testBaseUri = false; + + static const baseTestCakePayUri = 'test.cakepay.com'; + static const baseProdCakePayUri = 'buy.cakepay.com'; + + static const baseCakePayUri = testBaseUri ? baseTestCakePayUri : baseProdCakePayUri; + + static const vendorsPath = '/api/vendors'; + static const countriesPath = '/api/countries'; + static const authPath = '/api/auth'; + static final verifyEmailPath = '/api/verify'; + static final logoutPath = '/api/logout'; + static final createOrderPath = '/api/order'; + static final simulatePaymentPath = '/api/simulate_payment'; + + /// AuthenticateUser + Future authenticateUser({required String email, required String apiKey}) async { + try { + final uri = Uri.https(baseCakePayUri, authPath); + final headers = { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': 'Api-Key $apiKey', + }; + final response = await http.post(uri, headers: headers, body: json.encode({'email': email})); + + if (response.statusCode != 200) { + throw Exception('Unexpected http status: ${response.statusCode}'); + } + + final bodyJson = json.decode(response.body) as Map; + + if (bodyJson.containsKey('user') && bodyJson['user']['email'] != null) { + return bodyJson['user']['email'] as String; + } + + throw Exception('Failed to authenticate user with error: $bodyJson'); + } catch (e) { + throw Exception('Failed to authenticate user with error: $e'); + } + } + + /// Verify email + Future verifyEmail({ + required String email, + required String code, + required String apiKey, + }) async { + final uri = Uri.https(baseCakePayUri, verifyEmailPath); + final headers = { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': 'Api-Key $apiKey', + }; + final query = {'email': email, 'otp': code}; + + final response = await http.post(uri, headers: headers, body: json.encode(query)); + + if (response.statusCode != 200) { + throw Exception('Unexpected http status: ${response.statusCode}'); + } + + final bodyJson = json.decode(response.body) as Map; + + if (bodyJson.containsKey('error')) { + throw Exception(bodyJson['error'] as String); + } + + if (bodyJson.containsKey('token')) { + final token = bodyJson['token'] as String; + final userEmail = bodyJson['user']['email'] as String; + return CakePayUserCredentials(userEmail, token); + } else { + throw Exception('E-mail verification failed.'); + } + } + + /// createOrder + Future createOrder({ + required String apiKey, + required int cardId, + required String price, + required int quantity, + required String userEmail, + required String token, + }) async { + final uri = Uri.https(baseCakePayUri, createOrderPath); + final headers = { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': 'Api-Key $apiKey', + }; + final query = { + 'card_id': cardId, + 'price': price, + 'quantity': quantity, + 'user_email': userEmail, + 'token': token, + 'send_email': true + }; + + try { + final response = await http.post(uri, headers: headers, body: json.encode(query)); + + if (response.statusCode != 201) { + final responseBody = json.decode(response.body); + if (responseBody is List) { + throw '${responseBody[0]}'; + } else { + throw Exception('Unexpected error: $responseBody'); + } + } + + final bodyJson = json.decode(response.body) as Map; + return CakePayOrder.fromMap(bodyJson); + } catch (e) { + throw Exception('${e}'); + } + } + + ///Simulate Payment + Future simulatePayment( + {required String CSRFToken, required String authorization, required String orderId}) async { + final uri = Uri.https(baseCakePayUri, simulatePaymentPath + '/$orderId'); + + final headers = { + 'accept': 'application/json', + 'authorization': authorization, + 'X-CSRFToken': CSRFToken, + }; + + final response = await http.get(uri, headers: headers); + + print('Response: ${response.statusCode}'); + + if (response.statusCode != 200) { + throw Exception('Unexpected http status: ${response.statusCode}'); + } + + final bodyJson = json.decode(response.body) as Map; + + throw Exception('You just bot a gift card with id: ${bodyJson['order_id']}'); + } + + /// Logout + Future logoutUser({required String email, required String apiKey}) async { + final uri = Uri.https(baseCakePayUri, logoutPath); + final headers = { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'Authorization': 'Api-Key $apiKey', + }; + + try { + final response = await http.post(uri, headers: headers, body: json.encode({'email': email})); + + if (response.statusCode != 200) { + throw Exception('Unexpected http status: ${response.statusCode}'); + } + } catch (e) { + print('Caught exception: $e'); + } + } + + /// Get Countries + Future> getCountries( + {required String CSRFToken, required String authorization}) async { + final uri = Uri.https(baseCakePayUri, countriesPath); + + final headers = { + 'accept': 'application/json', + 'authorization': authorization, + 'X-CSRFToken': CSRFToken, + }; + + final response = await http.get(uri, headers: headers); + + if (response.statusCode != 200) { + throw Exception('Unexpected http status: ${response.statusCode}'); + } + + final bodyJson = json.decode(response.body) as List; + + return bodyJson.map((country) => country['name'] as String).toList(); + } + + /// Get Vendors + Future> getVendors({ + required String CSRFToken, + required String authorization, + int? page, + String? country, + String? countryCode, + String? search, + List? vendorIds, + bool? giftCards, + bool? prepaidCards, + bool? onDemand, + bool? custom, + }) async { + var queryParams = { + 'page': page?.toString(), + 'country': country, + 'country_code': countryCode, + 'search': search, + 'vendor_ids': vendorIds?.join(','), + 'gift_cards': giftCards?.toString(), + 'prepaid_cards': prepaidCards?.toString(), + 'on_demand': onDemand?.toString(), + 'custom': custom?.toString(), + }; + + final uri = Uri.https(baseCakePayUri, vendorsPath, queryParams); + + var headers = { + 'accept': 'application/json; charset=UTF-8', + 'authorization': authorization, + 'X-CSRFToken': CSRFToken, + }; + + var response = await http.get(uri, headers: headers); + + if (response.statusCode != 200) { + throw Exception(response.body); + } + + final bodyJson = json.decode(response.body); + + if (bodyJson is List && bodyJson.isEmpty) { + return []; + } + + return (bodyJson['results'] as List) + .map((e) => CakePayVendor.fromJson(e as Map)) + .toList(); + } +} diff --git a/lib/cake_pay/cake_pay_card.dart b/lib/cake_pay/cake_pay_card.dart new file mode 100644 index 000000000..26fa0c50b --- /dev/null +++ b/lib/cake_pay/cake_pay_card.dart @@ -0,0 +1,87 @@ +import 'dart:convert'; + +import 'package:cake_wallet/entities/fiat_currency.dart'; + +class CakePayCard { + final int id; + final String name; + final String? description; + final String? termsAndConditions; + final String? howToUse; + final String? expiryAndValidity; + final String? cardImageUrl; + final String? country; + final FiatCurrency fiatCurrency; + final List denominationsUsd; + final List denominations; + final String? minValueUsd; + final String? maxValueUsd; + final String? minValue; + final String? maxValue; + + CakePayCard({ + required this.id, + required this.name, + this.description, + this.termsAndConditions, + this.howToUse, + this.expiryAndValidity, + this.cardImageUrl, + this.country, + required this.fiatCurrency, + required this.denominationsUsd, + required this.denominations, + this.minValueUsd, + this.maxValueUsd, + this.minValue, + this.maxValue, + }); + + factory CakePayCard.fromJson(Map json) { + final name = stripHtmlIfNeeded(json['name'] as String? ?? ''); + final decodedName = fixEncoding(name); + + final description = stripHtmlIfNeeded(json['description'] as String? ?? ''); + final decodedDescription = fixEncoding(description); + + final termsAndConditions = stripHtmlIfNeeded(json['terms_and_conditions'] as String? ?? ''); + final decodedTermsAndConditions = fixEncoding(termsAndConditions); + + final howToUse = stripHtmlIfNeeded(json['how_to_use'] as String? ?? ''); + final decodedHowToUse = fixEncoding(howToUse); + + final fiatCurrency = FiatCurrency.deserialize(raw: json['currency_code'] as String? ?? ''); + + final List denominationsUsd = + (json['denominations_usd'] as List?)?.map((e) => e.toString()).toList() ?? []; + final List denominations = + (json['denominations'] as List?)?.map((e) => e.toString()).toList() ?? []; + + return CakePayCard( + id: json['id'] as int? ?? 0, + name: decodedName, + description: decodedDescription, + termsAndConditions: decodedTermsAndConditions, + howToUse: decodedHowToUse, + expiryAndValidity: json['expiry_and_validity'] as String?, + cardImageUrl: json['card_image_url'] as String?, + country: json['country'] as String?, + fiatCurrency: fiatCurrency, + denominationsUsd: denominationsUsd, + denominations: denominations, + minValueUsd: json['min_value_usd'] as String?, + maxValueUsd: json['max_value_usd'] as String?, + minValue: json['min_value'] as String?, + maxValue: json['max_value'] as String?, + ); + } + + static String stripHtmlIfNeeded(String text) { + return text.replaceAll(RegExp(r'<[^>]*>|&[^;]+;'), ' '); + } + + static String fixEncoding(String text) { + final bytes = latin1.encode(text); + return utf8.decode(bytes, allowMalformed: true); + } +} diff --git a/lib/cake_pay/cake_pay_order.dart b/lib/cake_pay/cake_pay_order.dart new file mode 100644 index 000000000..8cb6e784a --- /dev/null +++ b/lib/cake_pay/cake_pay_order.dart @@ -0,0 +1,131 @@ + +class CakePayOrder { + final String orderId; + final List cards; + final String? externalId; + final double amountUsd; + final String status; + final String? vouchers; + final PaymentData paymentData; + + CakePayOrder({ + required this.orderId, + required this.cards, + required this.externalId, + required this.amountUsd, + required this.status, + required this.vouchers, + required this.paymentData, + }); + + factory CakePayOrder.fromMap(Map map) { + return CakePayOrder( + orderId: map['order_id'] as String, + cards: (map['cards'] as List) + .map((x) => OrderCard.fromMap(x as Map)) + .toList(), + externalId: map['external_id'] as String?, + amountUsd: map['amount_usd'] as double, + status: map['status'] as String, + vouchers: map['vouchers'] as String?, + paymentData: PaymentData.fromMap(map['payment_data'] as Map)); + } +} + +class OrderCard { + final int cardId; + final int? externalId; + final String price; + final int quantity; + final String currencyCode; + + OrderCard({ + required this.cardId, + required this.externalId, + required this.price, + required this.quantity, + required this.currencyCode, + }); + + factory OrderCard.fromMap(Map map) { + return OrderCard( + cardId: map['card_id'] as int, + externalId: map['external_id'] as int?, + price: map['price'] as String, + quantity: map['quantity'] as int, + currencyCode: map['currency_code'] as String, + ); + } +} + +class PaymentData { + final CryptoPaymentData btc; + final CryptoPaymentData xmr; + final DateTime invoiceTime; + final DateTime expirationTime; + final int? commission; + + PaymentData({ + required this.btc, + required this.xmr, + required this.invoiceTime, + required this.expirationTime, + required this.commission, + }); + + factory PaymentData.fromMap(Map map) { + return PaymentData( + btc: CryptoPaymentData.fromMap(map['BTC'] as Map), + xmr: CryptoPaymentData.fromMap(map['XMR'] as Map), + invoiceTime: DateTime.fromMillisecondsSinceEpoch(map['invoice_time'] as int), + expirationTime: DateTime.fromMillisecondsSinceEpoch(map['expiration_time'] as int), + commission: map['commission'] as int?, + ); + } +} + +class CryptoPaymentData { + final String price; + final PaymentUrl? paymentUrls; + final String address; + + CryptoPaymentData({ + required this.price, + this.paymentUrls, + required this.address, + }); + + factory CryptoPaymentData.fromMap(Map map) { + return CryptoPaymentData( + price: map['price'] as String, + paymentUrls: PaymentUrl.fromMap(map['paymentUrls'] as Map?), + address: map['address'] as String, + ); + } +} + +class PaymentUrl { + final String? bip21; + final String? bip72; + final String? bip72b; + final String? bip73; + final String? bolt11; + + PaymentUrl({ + this.bip21, + this.bip72, + this.bip72b, + this.bip73, + this.bolt11, + }); + + factory PaymentUrl.fromMap(Map? map) { + return PaymentUrl( + bip21: map?['BIP21'] as String?, + bip72: map?['BIP72'] as String?, + bip72b: map?['BIP72b'] as String?, + bip73: map?['BIP73'] as String?, + bolt11: map?['BOLT11'] as String?, + ); + } +} diff --git a/lib/cake_pay/cake_pay_payment_credantials.dart b/lib/cake_pay/cake_pay_payment_credantials.dart new file mode 100644 index 000000000..12c4ce6c2 --- /dev/null +++ b/lib/cake_pay/cake_pay_payment_credantials.dart @@ -0,0 +1,15 @@ +class PaymentCredential { + final double amount; + final int quantity; + final double totalAmount; + final String? userName; + final String fiatCurrency; + + PaymentCredential({ + required this.amount, + required this.quantity, + required this.totalAmount, + required this.userName, + required this.fiatCurrency, + }); +} \ No newline at end of file diff --git a/lib/cake_pay/cake_pay_service.dart b/lib/cake_pay/cake_pay_service.dart new file mode 100644 index 000000000..be8e1d189 --- /dev/null +++ b/lib/cake_pay/cake_pay_service.dart @@ -0,0 +1,107 @@ +import 'package:cake_wallet/.secrets.g.dart' as secrets; +import 'package:cake_wallet/cake_pay/cake_pay_api.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_order.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_vendor.dart'; +import 'package:cake_wallet/core/secure_storage.dart'; + +class CakePayService { + CakePayService(this.secureStorage, this.cakePayApi); + + static const cakePayEmailStorageKey = 'cake_pay_email'; + static const cakePayUsernameStorageKey = 'cake_pay_username'; + static const cakePayUserTokenKey = 'cake_pay_user_token'; + + static String get testCakePayApiKey => secrets.testCakePayApiKey; + + static String get cakePayApiKey => secrets.cakePayApiKey; + + static String get CSRFToken => secrets.CSRFToken; + + static String get authorization => secrets.authorization; + + final SecureStorage secureStorage; + final CakePayApi cakePayApi; + + /// Get Available Countries + Future> getCountries() async => + await cakePayApi.getCountries(CSRFToken: CSRFToken, authorization: authorization); + + /// Get Vendors + Future> getVendors({ + int? page, + String? country, + String? countryCode, + String? search, + List? vendorIds, + bool? giftCards, + bool? prepaidCards, + bool? onDemand, + bool? custom, + }) async { + final result = await cakePayApi.getVendors( + CSRFToken: CSRFToken, + authorization: authorization, + page: page, + country: country, + countryCode: countryCode, + search: search, + vendorIds: vendorIds, + giftCards: giftCards, + prepaidCards: prepaidCards, + onDemand: onDemand, + custom: custom); + return result; + } + + /// LogIn + Future logIn(String email) async { + final userName = await cakePayApi.authenticateUser(email: email, apiKey: cakePayApiKey); + await secureStorage.write(key: cakePayEmailStorageKey, value: userName); + await secureStorage.write(key: cakePayUsernameStorageKey, value: userName); + } + + /// Verify email + Future verifyEmail(String code) async { + final email = (await secureStorage.read(key: cakePayEmailStorageKey))!; + final credentials = + await cakePayApi.verifyEmail(email: email, code: code, apiKey: cakePayApiKey); + await secureStorage.write(key: cakePayUserTokenKey, value: credentials.token); + await secureStorage.write(key: cakePayUsernameStorageKey, value: credentials.username); + } + + Future getUserEmail() async { + return (await secureStorage.read(key: cakePayEmailStorageKey)); + } + + /// Check is user logged + Future isLogged() async { + final username = await secureStorage.read(key: cakePayUsernameStorageKey) ?? ''; + final password = await secureStorage.read(key: cakePayUserTokenKey) ?? ''; + return username.isNotEmpty && password.isNotEmpty; + } + + /// Logout + Future logout(String email) async { + await secureStorage.delete(key: cakePayUsernameStorageKey); + await secureStorage.delete(key: cakePayUserTokenKey); + await cakePayApi.logoutUser(email: email, apiKey: cakePayApiKey); + } + + /// Purchase Gift Card + Future createOrder( + {required int cardId, required String price, required int quantity}) async { + final userEmail = (await secureStorage.read(key: cakePayEmailStorageKey))!; + final token = (await secureStorage.read(key: cakePayUserTokenKey))!; + return await cakePayApi.createOrder( + apiKey: cakePayApiKey, + cardId: cardId, + price: price, + quantity: quantity, + token: token, + userEmail: userEmail); + } + + ///Simulate Purchase Gift Card + Future simulatePayment({required String orderId}) async => await cakePayApi.simulatePayment( + CSRFToken: CSRFToken, authorization: authorization, orderId: orderId); +} diff --git a/lib/cake_pay/cake_pay_states.dart b/lib/cake_pay/cake_pay_states.dart new file mode 100644 index 000000000..2c49353c1 --- /dev/null +++ b/lib/cake_pay/cake_pay_states.dart @@ -0,0 +1,67 @@ +import 'cake_pay_card.dart'; + +abstract class CakePayUserVerificationState {} + +class CakePayUserVerificationStateInitial extends CakePayUserVerificationState {} + +class CakePayUserVerificationStateSuccess extends CakePayUserVerificationState {} + +class CakePayUserVerificationStatePending extends CakePayUserVerificationState {} + +class CakePayUserVerificationStateLoading extends CakePayUserVerificationState {} + +class CakePayUserVerificationStateFailure extends CakePayUserVerificationState { + CakePayUserVerificationStateFailure({required this.error}); + + final String error; +} + +abstract class CakePayOtpState {} + +class CakePayOtpValidating extends CakePayOtpState {} + +class CakePayOtpSuccess extends CakePayOtpState {} + +class CakePayOtpSendDisabled extends CakePayOtpState {} + +class CakePayOtpSendEnabled extends CakePayOtpState {} + +class CakePayOtpFailure extends CakePayOtpState { + CakePayOtpFailure({required this.error}); + + final String error; +} + +class CakePayCreateCardState {} + +class CakePayCreateCardStateSuccess extends CakePayCreateCardState {} + +class CakePayCreateCardStateLoading extends CakePayCreateCardState {} + +class CakePayCreateCardStateFailure extends CakePayCreateCardState { + CakePayCreateCardStateFailure({required this.error}); + + final String error; +} + +class CakePayCardsState {} + +class CakePayCardsStateNoCards extends CakePayCardsState {} + +class CakePayCardsStateFetching extends CakePayCardsState {} + +class CakePayCardsStateFailure extends CakePayCardsState {} + +class CakePayCardsStateSuccess extends CakePayCardsState { + CakePayCardsStateSuccess({required this.card}); + + final CakePayCard card; +} + +abstract class CakePayVendorState {} + +class InitialCakePayVendorLoadingState extends CakePayVendorState {} + +class CakePayVendorLoadingState extends CakePayVendorState {} + +class CakePayVendorLoadedState extends CakePayVendorState {} diff --git a/lib/cake_pay/cake_pay_user_credentials.dart b/lib/cake_pay/cake_pay_user_credentials.dart new file mode 100644 index 000000000..5899b31ad --- /dev/null +++ b/lib/cake_pay/cake_pay_user_credentials.dart @@ -0,0 +1,6 @@ +class CakePayUserCredentials { + const CakePayUserCredentials(this.username, this.token); + + final String username; + final String token; +} \ No newline at end of file diff --git a/lib/cake_pay/cake_pay_vendor.dart b/lib/cake_pay/cake_pay_vendor.dart new file mode 100644 index 000000000..c947fa882 --- /dev/null +++ b/lib/cake_pay/cake_pay_vendor.dart @@ -0,0 +1,51 @@ +import 'dart:convert'; + +import 'cake_pay_card.dart'; + +class CakePayVendor { + final int id; + final String name; + final bool unavailable; + final String? cakeWarnings; + final List countries; + final CakePayCard? card; + + CakePayVendor({ + required this.id, + required this.name, + required this.unavailable, + this.cakeWarnings, + required this.countries, + this.card, + }); + + factory CakePayVendor.fromJson(Map json) { + final name = stripHtmlIfNeeded(json['name'] as String); + final decodedName = fixEncoding(name); + + var cardsJson = json['cards'] as List?; + CakePayCard? firstCard; + + if (cardsJson != null && cardsJson.isNotEmpty) { + firstCard = CakePayCard.fromJson(cardsJson.first as Map); + } + + return CakePayVendor( + id: json['id'] as int, + name: decodedName, + unavailable: json['unavailable'] as bool? ?? false, + cakeWarnings: json['cake_warnings'] as String?, + countries: List.from(json['countries'] as List? ?? []), + card: firstCard, + ); + } + + static String stripHtmlIfNeeded(String text) { + return text.replaceAll(RegExp(r'<[^>]*>|&[^;]+;'), ' '); + } + + static String fixEncoding(String text) { + final bytes = latin1.encode(text); + return utf8.decode(bytes, allowMalformed: true); + } +} diff --git a/lib/di.dart b/lib/di.dart index 31655b402..2c09d8cbc 100644 --- a/lib/di.dart +++ b/lib/di.dart @@ -2,7 +2,6 @@ import 'package:cake_wallet/.secrets.g.dart' as secrets; import 'package:cake_wallet/anonpay/anonpay_api.dart'; import 'package:cake_wallet/anonpay/anonpay_info_base.dart'; import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart'; -import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart'; import 'package:cake_wallet/anypay/anypay_api.dart'; import 'package:cake_wallet/bitcoin/bitcoin.dart'; import 'package:cake_wallet/bitcoin_cash/bitcoin_cash.dart'; @@ -33,16 +32,10 @@ import 'package:cake_wallet/entities/qr_view_data.dart'; import 'package:cake_wallet/entities/template.dart'; import 'package:cake_wallet/entities/transaction_description.dart'; import 'package:cake_wallet/ethereum/ethereum.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_card.dart'; import 'package:cake_wallet/exchange/exchange_template.dart'; import 'package:cake_wallet/exchange/trade.dart'; import 'package:cake_wallet/haven/haven.dart'; -import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart'; -import 'package:cake_wallet/ionia/ionia_anypay.dart'; -import 'package:cake_wallet/ionia/ionia_api.dart'; -import 'package:cake_wallet/ionia/ionia_gift_card.dart'; -import 'package:cake_wallet/ionia/ionia_merchant.dart'; -import 'package:cake_wallet/ionia/ionia_service.dart'; -import 'package:cake_wallet/ionia/ionia_tip.dart'; import 'package:cake_wallet/monero/monero.dart'; import 'package:cake_wallet/nano/nano.dart'; import 'package:cake_wallet/polygon/polygon.dart'; @@ -72,14 +65,6 @@ import 'package:cake_wallet/src/screens/exchange/exchange_template_page.dart'; import 'package:cake_wallet/src/screens/exchange_trade/exchange_confirm_page.dart'; import 'package:cake_wallet/src/screens/exchange_trade/exchange_trade_page.dart'; import 'package:cake_wallet/src/screens/faq/faq_page.dart'; -import 'package:cake_wallet/src/screens/ionia/cards/ionia_account_cards_page.dart'; -import 'package:cake_wallet/src/screens/ionia/cards/ionia_account_page.dart'; -import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_redeem_page.dart'; -import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_tip_page.dart'; -import 'package:cake_wallet/src/screens/ionia/cards/ionia_gift_card_detail_page.dart'; -import 'package:cake_wallet/src/screens/ionia/cards/ionia_more_options_page.dart'; -import 'package:cake_wallet/src/screens/ionia/cards/ionia_payment_status_page.dart'; -import 'package:cake_wallet/src/screens/ionia/ionia.dart'; import 'package:cake_wallet/src/screens/monero_accounts/monero_account_edit_or_create_page.dart'; import 'package:cake_wallet/src/screens/monero_accounts/monero_account_list_page.dart'; 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 import 'package:cake_wallet/src/screens/support/support_page.dart'; import 'package:cake_wallet/src/screens/support_chat/support_chat_page.dart'; import 'package:cake_wallet/src/screens/support_other_links/support_other_links_page.dart'; +import 'package:cake_wallet/src/screens/wallet/wallet_edit_page.dart'; +import 'package:cake_wallet/src/screens/wallet_connect/wc_connections_listing_view.dart'; +import 'package:cake_wallet/themes/theme_list.dart'; +import 'package:cake_wallet/utils/device_info.dart'; +import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart'; +import 'package:cake_wallet/utils/payment_request.dart'; +import 'package:cake_wallet/utils/responsive_layout_util.dart'; +import 'package:cake_wallet/view_model/dashboard/desktop_sidebar_view_model.dart'; +import 'package:cake_wallet/view_model/anon_invoice_page_view_model.dart'; +import 'package:cake_wallet/view_model/anonpay_details_view_model.dart'; +import 'package:cake_wallet/view_model/dashboard/home_settings_view_model.dart'; +import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart'; +import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart'; +import 'package:cake_wallet/view_model/cake_pay/cake_pay_auth_view_model.dart'; +import 'package:cake_wallet/view_model/cake_pay/cake_pay_buy_card_view_model.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_service.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_api.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_vendor.dart'; +import 'package:cake_wallet/src/screens/cake_pay/auth/cake_pay_account_page.dart'; +import 'package:cake_wallet/src/screens/cake_pay/cake_pay.dart'; +import 'package:cake_wallet/view_model/cake_pay/cake_pay_account_view_model.dart'; +import 'package:cake_wallet/view_model/cake_pay/cake_pay_cards_list_view_model.dart'; +import 'package:cake_wallet/view_model/cake_pay/cake_pay_purchase_view_model.dart'; +import 'package:cake_wallet/view_model/nano_account_list/nano_account_edit_or_create_view_model.dart'; +import 'package:cake_wallet/view_model/nano_account_list/nano_account_list_view_model.dart'; +import 'package:cake_wallet/view_model/node_list/pow_node_list_view_model.dart'; +import 'package:cake_wallet/view_model/seed_type_view_model.dart'; +import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart'; +import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart'; +import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart'; +import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart'; +import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart'; +import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart'; +import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart'; +import 'package:cake_wallet/view_model/settings/trocador_providers_view_model.dart'; +import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.dart'; +import 'package:cake_wallet/view_model/wallet_list/wallet_edit_view_model.dart'; +import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart'; +import 'package:cake_wallet/view_model/wallet_restore_choose_derivation_view_model.dart'; +import 'package:cw_core/nano_account.dart'; +import 'package:cw_core/unspent_coins_info.dart'; +import 'package:cw_core/wallet_service.dart'; +import 'package:cw_core/transaction_info.dart'; +import 'package:cw_core/node.dart'; import 'package:cake_wallet/src/screens/trade_details/trade_details_page.dart'; import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart'; import 'package:cake_wallet/src/screens/transaction_details/transaction_details_page.dart'; import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_details_page.dart'; import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart'; -import 'package:cake_wallet/src/screens/wallet/wallet_edit_page.dart'; -import 'package:cake_wallet/src/screens/wallet_connect/wc_connections_listing_view.dart'; import 'package:cake_wallet/src/screens/wallet_keys/wallet_keys_page.dart'; import 'package:cake_wallet/src/screens/wallet_list/wallet_list_page.dart'; -import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart'; import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/store/authentication_store.dart'; import 'package:cake_wallet/store/dashboard/fiat_conversion_store.dart'; @@ -148,14 +174,7 @@ import 'package:cake_wallet/store/templates/exchange_template_store.dart'; import 'package:cake_wallet/store/templates/send_template_store.dart'; import 'package:cake_wallet/store/wallet_list_store.dart'; import 'package:cake_wallet/store/yat/yat_store.dart'; -import 'package:cake_wallet/themes/theme_list.dart'; import 'package:cake_wallet/tron/tron.dart'; -import 'package:cake_wallet/utils/device_info.dart'; -import 'package:cake_wallet/utils/payment_request.dart'; -import 'package:cake_wallet/utils/responsive_layout_util.dart'; -import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart'; -import 'package:cake_wallet/view_model/anon_invoice_page_view_model.dart'; -import 'package:cake_wallet/view_model/anonpay_details_view_model.dart'; import 'package:cake_wallet/view_model/auth_view_model.dart'; import 'package:cake_wallet/view_model/backup_view_model.dart'; 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'; import 'package:cake_wallet/view_model/dashboard/balance_view_model.dart'; import 'package:cake_wallet/view_model/dashboard/cake_features_view_model.dart'; import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; -import 'package:cake_wallet/view_model/dashboard/desktop_sidebar_view_model.dart'; -import 'package:cake_wallet/view_model/dashboard/home_settings_view_model.dart'; -import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart'; -import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart'; import 'package:cake_wallet/view_model/edit_backup_password_view_model.dart'; import 'package:cake_wallet/view_model/exchange/exchange_trade_view_model.dart'; import 'package:cake_wallet/view_model/exchange/exchange_view_model.dart'; import 'package:cake_wallet/view_model/hardware_wallet/ledger_view_model.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_account_view_model.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_auth_view_model.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_buy_card_view_model.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_custom_redeem_view_model.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_custom_tip_view_model.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_gift_card_details_view_model.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_gift_cards_list_view_model.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_payment_status_view_model.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_purchase_merch_view_model.dart'; import 'package:cake_wallet/view_model/link_view_model.dart'; import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart'; import 'package:cake_wallet/view_model/monero_account_list/monero_account_edit_or_create_view_model.dart'; import 'package:cake_wallet/view_model/monero_account_list/monero_account_list_view_model.dart'; -import 'package:cake_wallet/view_model/nano_account_list/nano_account_edit_or_create_view_model.dart'; -import 'package:cake_wallet/view_model/nano_account_list/nano_account_list_view_model.dart'; import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart'; import 'package:cake_wallet/view_model/node_list/node_list_view_model.dart'; -import 'package:cake_wallet/view_model/node_list/pow_node_list_view_model.dart'; import 'package:cake_wallet/view_model/order_details_view_model.dart'; import 'package:cake_wallet/view_model/rescan_view_model.dart'; -import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart'; import 'package:cake_wallet/view_model/restore_from_backup_view_model.dart'; -import 'package:cake_wallet/view_model/seed_type_view_model.dart'; import 'package:cake_wallet/view_model/send/send_template_view_model.dart'; import 'package:cake_wallet/view_model/send/send_view_model.dart'; -import 'package:cake_wallet/view_model/set_up_2fa_viewmodel.dart'; -import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart'; -import 'package:cake_wallet/view_model/settings/other_settings_view_model.dart'; -import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart'; -import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart'; import 'package:cake_wallet/view_model/settings/silent_payments_settings_view_model.dart'; -import 'package:cake_wallet/view_model/settings/trocador_providers_view_model.dart'; import 'package:cake_wallet/view_model/setup_pin_code_view_model.dart'; import 'package:cake_wallet/view_model/support_view_model.dart'; 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_ import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_item.dart'; import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_list_view_model.dart'; import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_edit_or_create_view_model.dart'; -import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.dart'; import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart'; import 'package:cake_wallet/view_model/wallet_hardware_restore_view_model.dart'; import 'package:cake_wallet/view_model/wallet_keys_view_model.dart'; -import 'package:cake_wallet/view_model/wallet_list/wallet_edit_view_model.dart'; -import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart'; import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart'; import 'package:cake_wallet/view_model/wallet_new_vm.dart'; -import 'package:cake_wallet/view_model/wallet_restore_choose_derivation_view_model.dart'; import 'package:cake_wallet/view_model/wallet_restore_view_model.dart'; import 'package:cake_wallet/view_model/wallet_seed_view_model.dart'; import 'package:cw_core/crypto_currency.dart'; -import 'package:cw_core/nano_account.dart'; -import 'package:cw_core/node.dart'; import 'package:cw_core/receive_page_option.dart'; -import 'package:cw_core/transaction_info.dart'; -import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/wallet_info.dart'; -import 'package:cw_core/wallet_service.dart'; import 'package:cw_core/wallet_type.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; @@ -239,6 +225,7 @@ import 'package:get_it/get_it.dart'; import 'package:hive/hive.dart'; import 'package:mobx/mobx.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'cake_pay/cake_pay_payment_credantials.dart'; final getIt = GetIt.instance; @@ -993,6 +980,8 @@ Future setup({ trades: _tradesSource, settingsStore: getIt.get())); + getIt.registerFactory(() => CakeFeaturesViewModel(getIt.get())); + getIt.registerFactory(() => BackupService(getIt.get(), _walletInfoSource, getIt.get(), getIt.get())); @@ -1088,113 +1077,60 @@ Future setup({ getIt.registerFactoryParam( (QrViewData viewData, _) => FullscreenQRPage(qrViewData: viewData)); - getIt.registerFactory(() => IoniaApi()); + getIt.registerFactory(() => CakePayApi()); getIt.registerFactory(() => AnyPayApi()); - getIt.registerFactory( - () => IoniaService(getIt.get(), getIt.get())); + getIt.registerFactory( + () => CakePayService(getIt.get(), getIt.get())); - getIt.registerFactory(() => IoniaAnyPay( - getIt.get(), getIt.get(), getIt.get().wallet!)); + getIt.registerFactory(() => CakePayCardsListViewModel(cakePayService: getIt.get())); - getIt.registerFactory(() => IoniaGiftCardsListViewModel(ioniaService: getIt.get())); + getIt.registerFactory(() => CakePayAuthViewModel(cakePayService: getIt.get())); - getIt.registerFactory(() => CakeFeaturesViewModel(getIt.get())); - - getIt.registerFactory(() => IoniaAuthViewModel(ioniaService: getIt.get())); - - getIt.registerFactoryParam( - (double amount, merchant) { - return IoniaMerchPurchaseViewModel( - ioniaAnyPayService: getIt.get(), - amount: amount, - ioniaMerchant: merchant, + getIt.registerFactoryParam( + (PaymentCredential paymentCredential, CakePayCard card) { + return CakePayPurchaseViewModel( + cakePayService: getIt.get(), + paymentCredential: paymentCredential, + card: card, sendViewModel: getIt.get()); }); - getIt.registerFactoryParam( - (IoniaMerchant merchant, _) { - return IoniaBuyCardViewModel(ioniaMerchant: merchant); + getIt.registerFactoryParam( + (CakePayVendor vendor, _) { + return CakePayBuyCardViewModel(vendor: vendor); }); - getIt.registerFactory(() => IoniaAccountViewModel(ioniaService: getIt.get())); + getIt.registerFactory(() => CakePayAccountViewModel(cakePayService: getIt.get())); - getIt.registerFactory(() => IoniaCreateAccountPage(getIt.get())); + getIt.registerFactory(() => CakePayWelcomePage(getIt.get())); - getIt.registerFactory(() => IoniaLoginPage(getIt.get())); - - getIt.registerFactoryParam, void>((List args, _) { + getIt.registerFactoryParam, void>((List args, _) { final email = args.first as String; final isSignIn = args[1] as bool; - return IoniaVerifyIoniaOtp(getIt.get(), email, isSignIn); + return CakePayVerifyOtpPage(getIt.get(), email, isSignIn); }); - getIt.registerFactory(() => IoniaWelcomePage()); + getIt.registerFactoryParam, void>((List args, _) { + final vendor = args.first as CakePayVendor; - getIt.registerFactoryParam, void>((List args, _) { - final merchant = args.first as IoniaMerchant; - - return IoniaBuyGiftCardPage(getIt.get(param1: merchant)); + return CakePayBuyCardPage(getIt.get(param1: vendor), + getIt.get()); }); - getIt.registerFactoryParam, void>( + getIt.registerFactoryParam, void>( (List args, _) { - final amount = args.first as double; - final merchant = args.last as IoniaMerchant; - return IoniaBuyGiftCardDetailPage( - getIt.get(param1: amount, param2: merchant)); + final paymentCredential = args.first as PaymentCredential; + final card = args[1] as CakePayCard; + return CakePayBuyCardDetailPage( + getIt.get(param1: paymentCredential, param2: card)); }); - getIt.registerFactoryParam( - (IoniaGiftCard giftCard, _) { - return IoniaGiftCardDetailsViewModel( - ioniaService: getIt.get(), giftCard: giftCard); - }); + getIt.registerFactory(() => CakePayCardsPage(getIt.get())); - getIt.registerFactoryParam, void>((List args, _) { - final amount = args[0] as double; - final merchant = args[1] as IoniaMerchant; - final tip = args[2] as IoniaTip; - - return IoniaCustomTipViewModel(amount: amount, tip: tip, ioniaMerchant: merchant); - }); - - getIt.registerFactoryParam( - (IoniaGiftCard giftCard, _) { - return IoniaGiftCardDetailPage(getIt.get(param1: giftCard)); - }); - - getIt.registerFactoryParam, void>((List args, _) { - final giftCard = args.first as IoniaGiftCard; - - return IoniaMoreOptionsPage(giftCard); - }); - - getIt.registerFactoryParam( - (IoniaGiftCard giftCard, _) => - IoniaCustomRedeemViewModel(giftCard: giftCard, ioniaService: getIt.get())); - - getIt.registerFactoryParam, void>((List args, _) { - final giftCard = args.first as IoniaGiftCard; - - return IoniaCustomRedeemPage(getIt.get(param1: giftCard)); - }); - - getIt.registerFactoryParam, void>((List args, _) { - return IoniaCustomTipPage(getIt.get(param1: args)); - }); - - getIt.registerFactory(() => IoniaManageCardsPage(getIt.get())); - - getIt.registerFactory(() => IoniaDebitCardPage(getIt.get())); - - getIt.registerFactory(() => IoniaActivateDebitCardPage(getIt.get())); - - getIt.registerFactory(() => IoniaAccountPage(getIt.get())); - - getIt.registerFactory(() => IoniaAccountCardsPage(getIt.get())); + getIt.registerFactory(() => CakePayAccountPage(getIt.get())); getIt.registerFactoryParam( (TransactionInfo transactionInfo, _) => RBFDetailsPage( @@ -1225,18 +1161,6 @@ Future setup({ (AnonpayInvoiceInfo anonpayInvoiceInfo, _) => AnonpayDetailsPage( anonpayDetailsViewModel: getIt.get(param1: anonpayInvoiceInfo))); - getIt.registerFactoryParam( - (IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo) => - IoniaPaymentStatusViewModel(getIt.get(), - paymentInfo: paymentInfo, committedInfo: committedInfo)); - - getIt.registerFactoryParam( - (IoniaAnyPayPaymentInfo paymentInfo, AnyPayPaymentCommittedInfo committedInfo) => - IoniaPaymentStatusPage( - getIt.get(param1: paymentInfo, param2: committedInfo))); - getIt.registerFactoryParam((balanceViewModel, _) => HomeSettingsPage(getIt.get(param1: balanceViewModel))); diff --git a/lib/ionia/ionia_any_pay_payment_info.dart b/lib/ionia/ionia_any_pay_payment_info.dart deleted file mode 100644 index 6146a46fe..000000000 --- a/lib/ionia/ionia_any_pay_payment_info.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'package:cake_wallet/anypay/any_pay_payment.dart'; -import 'package:cake_wallet/ionia/ionia_order.dart'; - -class IoniaAnyPayPaymentInfo { - const IoniaAnyPayPaymentInfo(this.ioniaOrder, this.anyPayPayment); - - final IoniaOrder ioniaOrder; - final AnyPayPayment anyPayPayment; -} diff --git a/lib/ionia/ionia_anypay.dart b/lib/ionia/ionia_anypay.dart deleted file mode 100644 index f4053094b..000000000 --- a/lib/ionia/ionia_anypay.dart +++ /dev/null @@ -1,91 +0,0 @@ -import 'package:cw_core/monero_amount_format.dart'; -import 'package:cw_core/monero_transaction_priority.dart'; -import 'package:cw_core/output_info.dart'; -import 'package:cw_core/pending_transaction.dart'; -import 'package:cw_core/wallet_base.dart'; -import 'package:cake_wallet/anypay/any_pay_payment.dart'; -import 'package:cake_wallet/anypay/any_pay_payment_instruction.dart'; -import 'package:cake_wallet/ionia/ionia_service.dart'; -import 'package:cake_wallet/anypay/anypay_api.dart'; -import 'package:cake_wallet/anypay/any_pay_chain.dart'; -import 'package:cake_wallet/anypay/any_pay_trasnaction.dart'; -import 'package:cake_wallet/bitcoin/bitcoin.dart'; -import 'package:cake_wallet/monero/monero.dart'; -import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart'; -import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart'; - -class IoniaAnyPay { - IoniaAnyPay(this.ioniaService, this.anyPayApi, this.wallet); - - final IoniaService ioniaService; - final AnyPayApi anyPayApi; - final WalletBase wallet; - - Future purchase({ - required String merchId, - required double amount}) async { - final invoice = await ioniaService.purchaseGiftCard( - merchId: merchId, - amount: amount, - currency: wallet.currency.title.toUpperCase()); - final anypayPayment = await anyPayApi.paymentRequest(invoice.uri); - return IoniaAnyPayPaymentInfo(invoice, anypayPayment); - } - - Future commitInvoice(AnyPayPayment payment) async { - final transactionCredentials = payment.instructions - .where((instruction) => instruction.type == AnyPayPaymentInstruction.transactionType) - .map((AnyPayPaymentInstruction instruction) { - switch(payment.chain.toUpperCase()) { - case AnyPayChain.xmr: - return monero!.createMoneroTransactionCreationCredentialsRaw( - outputs: instruction.outputs.map((out) => - OutputInfo( - isParsedAddress: false, - address: out.address, - cryptoAmount: moneroAmountToString(amount: out.amount), - formattedCryptoAmount: out.amount, - sendAll: false)).toList(), - priority: MoneroTransactionPriority.medium); // FIXME: HARDCODED PRIORITY - case AnyPayChain.btc: - return bitcoin!.createBitcoinTransactionCredentialsRaw( - instruction.outputs.map((out) => - OutputInfo( - isParsedAddress: false, - address: out.address, - formattedCryptoAmount: out.amount, - sendAll: false)).toList(), - feeRate: instruction.requiredFeeRate); - case AnyPayChain.ltc: - return bitcoin!.createBitcoinTransactionCredentialsRaw( - instruction.outputs.map((out) => - OutputInfo( - isParsedAddress: false, - address: out.address, - formattedCryptoAmount: out.amount, - sendAll: false)).toList(), - feeRate: instruction.requiredFeeRate); - default: - throw Exception('Incorrect transaction chain: ${payment.chain.toUpperCase()}'); - } - }); - final transactions = (await Future.wait(transactionCredentials - .map((Object credentials) async => await wallet.createTransaction(credentials)))) - .map((PendingTransaction pendingTransaction) { - switch (payment.chain.toUpperCase()){ - case AnyPayChain.xmr: - final ptx = monero!.pendingTransactionInfo(pendingTransaction); - return AnyPayTransaction(ptx['hex'] ?? '', id: ptx['id'] ?? '', key: ptx['key']); - default: - return AnyPayTransaction(pendingTransaction.hex, id: pendingTransaction.id, key: null); - } - }) - .toList(); - - return await anyPayApi.payment( - payment.paymentUrl, - chain: payment.chain, - currency: payment.chain, - transactions: transactions); - } -} \ No newline at end of file diff --git a/lib/ionia/ionia_api.dart b/lib/ionia/ionia_api.dart deleted file mode 100644 index 274e557c7..000000000 --- a/lib/ionia/ionia_api.dart +++ /dev/null @@ -1,440 +0,0 @@ -import 'dart:convert'; -import 'package:cake_wallet/ionia/ionia_merchant.dart'; -import 'package:cake_wallet/ionia/ionia_order.dart'; -import 'package:http/http.dart'; -import 'package:cake_wallet/ionia/ionia_user_credentials.dart'; -import 'package:cake_wallet/ionia/ionia_virtual_card.dart'; -import 'package:cake_wallet/ionia/ionia_category.dart'; -import 'package:cake_wallet/ionia/ionia_gift_card.dart'; - -class IoniaApi { - static const baseUri = 'api.ionia.io'; - static const pathPrefix = 'cake'; - static const requestedUUIDHeader = 'requestedUUID'; - static final createUserUri = Uri.https(baseUri, '/$pathPrefix/CreateUser'); - static final verifyEmailUri = Uri.https(baseUri, '/$pathPrefix/VerifyEmail'); - static final signInUri = Uri.https(baseUri, '/$pathPrefix/SignIn'); - static final createCardUri = Uri.https(baseUri, '/$pathPrefix/CreateCard'); - static final getCardsUri = Uri.https(baseUri, '/$pathPrefix/GetCards'); - static final getMerchantsUrl = Uri.https(baseUri, '/$pathPrefix/GetMerchants'); - static final getMerchantsByFilterUrl = Uri.https(baseUri, '/$pathPrefix/GetMerchantsByFilter'); - static final getPurchaseMerchantsUrl = Uri.https(baseUri, '/$pathPrefix/PurchaseGiftCard'); - static final getCurrentUserGiftCardSummariesUrl = Uri.https(baseUri, '/$pathPrefix/GetCurrentUserGiftCardSummaries'); - static final changeGiftCardUrl = Uri.https(baseUri, '/$pathPrefix/ChargeGiftCard'); - static final getGiftCardUrl = Uri.https(baseUri, '/$pathPrefix/GetGiftCard'); - static final getPaymentStatusUrl = Uri.https(baseUri, '/$pathPrefix/PaymentStatus'); - - // Create user - - Future createUser(String email, {required String clientId}) async { - final headers = {'clientId': clientId}; - final query = {'emailAddress': email}; - final uri = createUserUri.replace(queryParameters: query); - final response = await put(uri, headers: headers); - - if (response.statusCode != 200) { - throw Exception('Unexpected http status: ${response.statusCode}'); - } - - final bodyJson = json.decode(response.body) as Map; - final data = bodyJson['Data'] as Map; - final isSuccessful = bodyJson['Successful'] as bool; - - if (!isSuccessful) { - throw Exception(data['ErrorMessage'] as String); - } - - return data['username'] as String; - } - - // Verify email - - Future verifyEmail({ - required String email, - required String code, - required String clientId}) async { - final headers = { - 'clientId': clientId, - 'EmailAddress': email}; - final query = {'verificationCode': code}; - final uri = verifyEmailUri.replace(queryParameters: query); - final response = await put(uri, headers: headers); - - if (response.statusCode != 200) { - throw Exception('Unexpected http status: ${response.statusCode}'); - } - - final bodyJson = json.decode(response.body) as Map; - final data = bodyJson['Data'] as Map; - final isSuccessful = bodyJson['Successful'] as bool; - - if (!isSuccessful) { - throw Exception(bodyJson['ErrorMessage'] as String); - } - - final password = data['password'] as String; - final username = data['username'] as String; - return IoniaUserCredentials(username, password); - } - - // Sign In - - Future signIn(String email, {required String clientId}) async { - final headers = {'clientId': clientId}; - final query = {'emailAddress': email}; - final uri = signInUri.replace(queryParameters: query); - final response = await put(uri, headers: headers); - - if (response.statusCode != 200) { - throw Exception('Unexpected http status: ${response.statusCode}'); - } - - final bodyJson = json.decode(response.body) as Map; - final data = bodyJson['Data'] as Map; - final isSuccessful = bodyJson['Successful'] as bool; - - if (!isSuccessful) { - throw Exception(data['ErrorMessage'] as String); - } - } - - // Get virtual card - - Future getCards({ - required String username, - required String password, - required String clientId}) async { - final headers = { - 'clientId': clientId, - 'username': username, - 'password': password}; - final response = await post(getCardsUri, headers: headers); - - if (response.statusCode != 200) { - throw Exception('Unexpected http status: ${response.statusCode}'); - } - - final bodyJson = json.decode(response.body) as Map; - final data = bodyJson['Data'] as Map; - final isSuccessful = bodyJson['Successful'] as bool; - - if (!isSuccessful) { - throw Exception(data['message'] as String); - } - - final virtualCard = data['VirtualCard'] as Map; - return IoniaVirtualCard.fromMap(virtualCard); - } - - // Create virtual card - - Future createCard({ - required String username, - required String password, - required String clientId}) async { - final headers = { - 'clientId': clientId, - 'username': username, - 'password': password}; - final response = await post(createCardUri, headers: headers); - - if (response.statusCode != 200) { - throw Exception('Unexpected http status: ${response.statusCode}'); - } - - final bodyJson = json.decode(response.body) as Map; - final data = bodyJson['Data'] as Map; - final isSuccessful = bodyJson['Successful'] as bool? ?? false; - - if (!isSuccessful) { - throw Exception(data['message'] as String); - } - - return IoniaVirtualCard.fromMap(data); - } - - // Get Merchants - - Future> getMerchants({ - required String username, - required String password, - required String clientId}) async { - final headers = { - 'clientId': clientId, - 'username': username, - 'password': password}; - final response = await post(getMerchantsUrl, headers: headers); - - if (response.statusCode != 200) { - return []; - } - - final decodedBody = json.decode(response.body) as Map; - final isSuccessful = decodedBody['Successful'] as bool? ?? false; - - if (!isSuccessful) { - return []; - } - - final data = decodedBody['Data'] as List; - final merch = []; - - for (final item in data) { - try { - final element = item as Map; - merch.add(IoniaMerchant.fromJsonMap(element)); - } catch(_) {} - } - - return merch; - } - - // Get Merchants By Filter - - Future> getMerchantsByFilter({ - required String username, - required String password, - required String clientId, - String? search, - List? categories, - int merchantFilterType = 0}) async { - // MerchantFilterType: {All = 0, Nearby = 1, Popular = 2, Online = 3, MyFaves = 4, Search = 5} - - final headers = { - 'clientId': clientId, - 'username': username, - 'password': password, - 'Content-Type': 'application/json'}; - final body = {'MerchantFilterType': merchantFilterType}; - - if (search != null) { - body['SearchCriteria'] = search; - } - - if (categories != null) { - body['Categories'] = categories - .map((e) => e.ids) - .expand((e) => e) - .toList(); - } - - final response = await post(getMerchantsByFilterUrl, headers: headers, body: json.encode(body)); - - if (response.statusCode != 200) { - return []; - } - - final decodedBody = json.decode(response.body) as Map; - final isSuccessful = decodedBody['Successful'] as bool? ?? false; - - if (!isSuccessful) { - return []; - } - - final data = decodedBody['Data'] as List; - final merch = []; - - for (final item in data) { - try { - final element = item['Merchant'] as Map; - merch.add(IoniaMerchant.fromJsonMap(element)); - } catch(_) {} - } - - return merch; - } - - // Purchase Gift Card - - Future purchaseGiftCard({ - required String requestedUUID, - required String merchId, - required double amount, - required String currency, - required String username, - required String password, - required String clientId}) async { - final headers = { - 'clientId': clientId, - 'username': username, - 'password': password, - requestedUUIDHeader: requestedUUID, - 'Content-Type': 'application/json'}; - final body = { - 'Amount': amount, - 'Currency': currency, - 'MerchantId': merchId}; - final response = await post(getPurchaseMerchantsUrl, headers: headers, body: json.encode(body)); - - if (response.statusCode != 200) { - throw Exception('Unexpected response'); - } - - final decodedBody = json.decode(response.body) as Map; - final isSuccessful = decodedBody['Successful'] as bool? ?? false; - - if (!isSuccessful) { - throw Exception(decodedBody['ErrorMessage'] as String); - } - - final data = decodedBody['Data'] as Map; - return IoniaOrder.fromMap(data); - } - - // Get Current User Gift Card Summaries - - Future> getCurrentUserGiftCardSummaries({ - required String username, - required String password, - required String clientId}) async { - final headers = { - 'clientId': clientId, - 'username': username, - 'password': password}; - final response = await post(getCurrentUserGiftCardSummariesUrl, headers: headers); - - if (response.statusCode != 200) { - return []; - } - - final decodedBody = json.decode(response.body) as Map; - final isSuccessful = decodedBody['Successful'] as bool? ?? false; - - if (!isSuccessful) { - return []; - } - - final data = decodedBody['Data'] as List; - final cards = []; - - for (final item in data) { - try { - final element = item as Map; - cards.add(IoniaGiftCard.fromJsonMap(element)); - } catch(_) {} - } - - return cards; - } - - // Charge Gift Card - - Future chargeGiftCard({ - required String username, - required String password, - required String clientId, - required int giftCardId, - required double amount}) async { - final headers = { - 'clientId': clientId, - 'username': username, - 'password': password, - 'Content-Type': 'application/json'}; - final body = { - 'Id': giftCardId, - 'Amount': amount}; - final response = await post( - changeGiftCardUrl, - headers: headers, - body: json.encode(body)); - - if (response.statusCode != 200) { - throw Exception('Failed to update Gift Card with ID ${giftCardId};Incorrect response status: ${response.statusCode};'); - } - - final decodedBody = json.decode(response.body) as Map; - final isSuccessful = decodedBody['Successful'] as bool? ?? false; - - if (!isSuccessful) { - final data = decodedBody['Data'] as Map; - final msg = data['Message'] as String? ?? ''; - - if (msg.isNotEmpty) { - throw Exception(msg); - } - - throw Exception('Failed to update Gift Card with ID ${giftCardId};'); - } - } - - // Get Gift Card - - Future getGiftCard({ - required String username, - required String password, - required String clientId, - required int id}) async { - final headers = { - 'clientId': clientId, - 'username': username, - 'password': password, - 'Content-Type': 'application/json'}; - final body = {'Id': id}; - final response = await post( - getGiftCardUrl, - headers: headers, - body: json.encode(body)); - - if (response.statusCode != 200) { - throw Exception('Failed to get Gift Card with ID ${id};Incorrect response status: ${response.statusCode};'); - } - - final decodedBody = json.decode(response.body) as Map; - final isSuccessful = decodedBody['Successful'] as bool? ?? false; - - if (!isSuccessful) { - final msg = decodedBody['ErrorMessage'] as String ?? ''; - - if (msg.isNotEmpty) { - throw Exception(msg); - } - - throw Exception('Failed to get Gift Card with ID ${id};'); - } - - final data = decodedBody['Data'] as Map; - return IoniaGiftCard.fromJsonMap(data); - } - - // Payment Status - - Future getPaymentStatus({ - required String username, - required String password, - required String clientId, - required String orderId, - required String paymentId}) async { - final headers = { - 'clientId': clientId, - 'username': username, - 'password': password, - 'Content-Type': 'application/json'}; - final body = { - 'order_id': orderId, - 'paymentId': paymentId}; - final response = await post( - getPaymentStatusUrl, - headers: headers, - body: json.encode(body)); - - if (response.statusCode != 200) { - throw Exception('Failed to get Payment Status for order_id ${orderId} paymentId ${paymentId};Incorrect response status: ${response.statusCode};'); - } - - final decodedBody = json.decode(response.body) as Map; - final isSuccessful = decodedBody['Successful'] as bool? ?? false; - - if (!isSuccessful) { - final msg = decodedBody['ErrorMessage'] as String ?? ''; - - if (msg.isNotEmpty) { - throw Exception(msg); - } - - throw Exception('Failed to get Payment Status for order_id ${orderId} paymentId ${paymentId}'); - } - - final data = decodedBody['Data'] as Map; - return data['gift_card_id'] as int; - } -} \ No newline at end of file diff --git a/lib/ionia/ionia_category.dart b/lib/ionia/ionia_category.dart deleted file mode 100644 index 284b513a7..000000000 --- a/lib/ionia/ionia_category.dart +++ /dev/null @@ -1,22 +0,0 @@ -class IoniaCategory { - const IoniaCategory({ - required this.index, - required this.title, - required this.ids, - required this.iconPath}); - - static const allCategories = [all, apparel, onlineOnly, food, entertainment, delivery, travel]; - static const all = IoniaCategory(index: 0, title: 'All', ids: [], iconPath: 'assets/images/category.png'); - static const apparel = IoniaCategory(index: 1, title: 'Apparel', ids: [1], iconPath: 'assets/images/tshirt.png'); - static const onlineOnly = IoniaCategory(index: 2, title: 'Online Only', ids: [13, 43], iconPath: 'assets/images/global.png'); - static const food = IoniaCategory(index: 3, title: 'Food', ids: [4], iconPath: 'assets/images/food.png'); - static const entertainment = IoniaCategory(index: 4, title: 'Entertainment', ids: [5], iconPath: 'assets/images/gaming.png'); - static const delivery = IoniaCategory(index: 5, title: 'Delivery', ids: [114, 109], iconPath: 'assets/images/delivery.png'); - static const travel = IoniaCategory(index: 6, title: 'Travel', ids: [12], iconPath: 'assets/images/airplane.png'); - - - final int index; - final String title; - final List ids; - final String iconPath; -} diff --git a/lib/ionia/ionia_create_state.dart b/lib/ionia/ionia_create_state.dart deleted file mode 100644 index a4f1f9cad..000000000 --- a/lib/ionia/ionia_create_state.dart +++ /dev/null @@ -1,68 +0,0 @@ -import 'package:cake_wallet/ionia/ionia_virtual_card.dart'; -import 'package:flutter/material.dart'; - -abstract class IoniaCreateAccountState {} - -class IoniaInitialCreateState extends IoniaCreateAccountState {} - -class IoniaCreateStateSuccess extends IoniaCreateAccountState {} - -class IoniaCreateStateLoading extends IoniaCreateAccountState {} - -class IoniaCreateStateFailure extends IoniaCreateAccountState { - IoniaCreateStateFailure({required this.error}); - - final String error; -} - -abstract class IoniaOtpState {} - -class IoniaOtpValidating extends IoniaOtpState {} - -class IoniaOtpSuccess extends IoniaOtpState {} - -class IoniaOtpSendDisabled extends IoniaOtpState {} - -class IoniaOtpSendEnabled extends IoniaOtpState {} - -class IoniaOtpFailure extends IoniaOtpState { - IoniaOtpFailure({required this.error}); - - final String error; -} - -class IoniaCreateCardState {} - -class IoniaCreateCardSuccess extends IoniaCreateCardState {} - -class IoniaCreateCardLoading extends IoniaCreateCardState {} - -class IoniaCreateCardFailure extends IoniaCreateCardState { - IoniaCreateCardFailure({required this.error}); - - final String error; -} - -class IoniaFetchCardState {} - -class IoniaNoCardState extends IoniaFetchCardState {} - -class IoniaFetchingCard extends IoniaFetchCardState {} - -class IoniaFetchCardFailure extends IoniaFetchCardState {} - -class IoniaCardSuccess extends IoniaFetchCardState { - IoniaCardSuccess({required this.card}); - - final IoniaVirtualCard card; -} - -abstract class IoniaMerchantState {} - -class InitialIoniaMerchantLoadingState extends IoniaMerchantState {} - -class IoniaLoadingMerchantState extends IoniaMerchantState {} - -class IoniaLoadedMerchantState extends IoniaMerchantState {} - - diff --git a/lib/ionia/ionia_gift_card.dart b/lib/ionia/ionia_gift_card.dart deleted file mode 100644 index 2ba0fd136..000000000 --- a/lib/ionia/ionia_gift_card.dart +++ /dev/null @@ -1,70 +0,0 @@ -import 'dart:convert'; -import 'package:cake_wallet/ionia/ionia_gift_card_instruction.dart'; -import 'package:flutter/foundation.dart'; - -class IoniaGiftCard { - IoniaGiftCard({ - required this.id, - required this.merchantId, - required this.legalName, - required this.systemName, - required this.barcodeUrl, - required this.cardNumber, - required this.cardPin, - required this.instructions, - required this.tip, - required this.purchaseAmount, - required this.actualAmount, - required this.totalTransactionAmount, - required this.totalDashTransactionAmount, - required this.remainingAmount, - required this.createdDateFormatted, - required this.lastTransactionDateFormatted, - required this.isActive, - required this.isEmpty, - required this.logoUrl}); - - factory IoniaGiftCard.fromJsonMap(Map element) { - return IoniaGiftCard( - id: element['Id'] as int, - merchantId: element['MerchantId'] as int, - legalName: element['LegalName'] as String, - systemName: element['SystemName'] as String, - barcodeUrl: element['BarcodeUrl'] as String, - cardNumber: element['CardNumber'] as String, - cardPin: element['CardPin'] as String, - tip: element['Tip'] as double, - purchaseAmount: element['PurchaseAmount'] as double, - actualAmount: element['ActualAmount'] as double, - totalTransactionAmount: element['TotalTransactionAmount'] as double, - totalDashTransactionAmount: (element['TotalDashTransactionAmount'] as double?) ?? 0.0, - remainingAmount: element['RemainingAmount'] as double, - isActive: element['IsActive'] as bool, - isEmpty: element['IsEmpty'] as bool, - logoUrl: element['LogoUrl'] as String, - createdDateFormatted: element['CreatedDate'] as String, - lastTransactionDateFormatted: element['LastTransactionDate'] as String, - instructions: IoniaGiftCardInstruction.parseListOfInstructions(element['PaymentInstructions'] as String)); - } - - final int id; - final int merchantId; - final String legalName; - final String systemName; - final String barcodeUrl; - final String cardNumber; - final String cardPin; - final List instructions; - final double tip; - final double purchaseAmount; - final double actualAmount; - final double totalTransactionAmount; - final double totalDashTransactionAmount; - double remainingAmount; - final String createdDateFormatted; - final String lastTransactionDateFormatted; - final bool isActive; - final bool isEmpty; - final String logoUrl; - -} \ No newline at end of file diff --git a/lib/ionia/ionia_gift_card_instruction.dart b/lib/ionia/ionia_gift_card_instruction.dart deleted file mode 100644 index fb6751c09..000000000 --- a/lib/ionia/ionia_gift_card_instruction.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'dart:convert'; -import 'package:intl/intl.dart' show toBeginningOfSentenceCase; - -class IoniaGiftCardInstruction { - IoniaGiftCardInstruction(this.header, this.body); - - factory IoniaGiftCardInstruction.fromJsonMap(Map element) { - return IoniaGiftCardInstruction( - toBeginningOfSentenceCase(element['title'] as String? ?? '') ?? '', - element['description'] as String); - } - - static List parseListOfInstructions(String instructionsJSON) { - List instructions = []; - - if (instructionsJSON.isNotEmpty) { - final decodedInstructions = json.decode(instructionsJSON) as List; - instructions = decodedInstructions - .map((dynamic e) =>IoniaGiftCardInstruction.fromJsonMap(e as Map)) - .toList(); - } - - return instructions; - } - - final String header; - final String body; -} \ No newline at end of file diff --git a/lib/ionia/ionia_merchant.dart b/lib/ionia/ionia_merchant.dart deleted file mode 100644 index c355a25c3..000000000 --- a/lib/ionia/ionia_merchant.dart +++ /dev/null @@ -1,101 +0,0 @@ -import 'package:cake_wallet/ionia/ionia_gift_card_instruction.dart'; -import 'package:cake_wallet/generated/i18n.dart'; - -class IoniaMerchant { - IoniaMerchant({ - required this.id, - required this.legalName, - required this.systemName, - required this.description, - required this.website, - required this.termsAndConditions, - required this.logoUrl, - required this.cardImageUrl, - required this.cardholderAgreement, - required this.isActive, - required this.isOnline, - required this.isPhysical, - required this.isVariablePurchase, - required this.minimumCardPurchase, - required this.maximumCardPurchase, - required this.acceptsTips, - required this.createdDateFormatted, - required this.modifiedDateFormatted, - required this.usageInstructions, - required this.usageInstructionsBak, - required this.hasBarcode, - required this.instructions, - required this.savingsPercentage}); - - factory IoniaMerchant.fromJsonMap(Map element) { - return IoniaMerchant( - id: element["Id"] as int, - legalName: element["LegalName"] as String, - systemName: element["SystemName"] as String, - description: element["Description"] as String, - website: element["Website"] as String, - termsAndConditions: element["TermsAndConditions"] as String, - logoUrl: element["LogoUrl"] as String, - cardImageUrl: element["CardImageUrl"] as String, - cardholderAgreement: element["CardholderAgreement"] as String, - isActive: element["IsActive"] as bool?, - isOnline: element["IsOnline"] as bool, - isPhysical: element["IsPhysical"] as bool, - isVariablePurchase: element["IsVariablePurchase"] as bool, - minimumCardPurchase: element["MinimumCardPurchase"] as double, - maximumCardPurchase: element["MaximumCardPurchase"] as double, - acceptsTips: element["AcceptsTips"] as bool, - createdDateFormatted: element["CreatedDate"] as String?, - modifiedDateFormatted: element["ModifiedDate"] as String?, - usageInstructions: element["UsageInstructions"] as String?, - usageInstructionsBak: element["UsageInstructionsBak"] as String?, - hasBarcode: element["HasBarcode"] as bool, - instructions: IoniaGiftCardInstruction.parseListOfInstructions(element['PaymentInstructions'] as String), - savingsPercentage: element["SavingsPercentage"] as double); - } - - final int id; - final String legalName; - final String systemName; - final String description; - final String website; - final String termsAndConditions; - final String logoUrl; - final String cardImageUrl; - final String cardholderAgreement; - final bool? isActive; - final bool isOnline; - final bool? isPhysical; - final bool isVariablePurchase; - final double minimumCardPurchase; - final double maximumCardPurchase; - final bool acceptsTips; - final String? createdDateFormatted; - final String? modifiedDateFormatted; - final String? usageInstructions; - final String? usageInstructionsBak; - final bool hasBarcode; - final List instructions; - final double savingsPercentage; - - double get discount => savingsPercentage; - - String get avaibilityStatus { - var status = ''; - - if (isOnline) { - status += S.current.online; - } - - if (isPhysical ?? false) { - if (status.isNotEmpty) { - status = '$status & '; - } - - status = '${status}${S.current.in_store}'; - } - - return status; - } - -} diff --git a/lib/ionia/ionia_order.dart b/lib/ionia/ionia_order.dart deleted file mode 100644 index a9cae07e9..000000000 --- a/lib/ionia/ionia_order.dart +++ /dev/null @@ -1,23 +0,0 @@ -import 'package:flutter/foundation.dart'; - -class IoniaOrder { - IoniaOrder({required this.id, - required this.uri, - required this.currency, - required this.amount, - required this.paymentId}); - factory IoniaOrder.fromMap(Map obj) { - return IoniaOrder( - id: obj['order_id'] as String, - uri: obj['uri'] as String, - currency: obj['currency'] as String, - amount: obj['amount'] as double, - paymentId: obj['paymentId'] as String); - } - - final String id; - final String uri; - final String currency; - final double amount; - final String paymentId; -} \ No newline at end of file diff --git a/lib/ionia/ionia_service.dart b/lib/ionia/ionia_service.dart deleted file mode 100644 index 821824a87..000000000 --- a/lib/ionia/ionia_service.dart +++ /dev/null @@ -1,171 +0,0 @@ -import 'package:cake_wallet/core/secure_storage.dart'; -import 'package:cake_wallet/ionia/ionia_merchant.dart'; -import 'package:cake_wallet/ionia/ionia_order.dart'; -import 'package:cake_wallet/ionia/ionia_virtual_card.dart'; -import 'package:cake_wallet/.secrets.g.dart' as secrets; -import 'package:cake_wallet/ionia/ionia_api.dart'; -import 'package:cake_wallet/ionia/ionia_gift_card.dart'; -import 'package:cake_wallet/ionia/ionia_category.dart'; - -class IoniaService { - IoniaService(this.secureStorage, this.ioniaApi); - - static const ioniaEmailStorageKey = 'ionia_email'; - static const ioniaUsernameStorageKey = 'ionia_username'; - static const ioniaPasswordStorageKey = 'ionia_password'; - - static String get clientId => secrets.ioniaClientId; - - final SecureStorage secureStorage; - final IoniaApi ioniaApi; - - // Create user - - Future createUser(String email) async { - final username = await ioniaApi.createUser(email, clientId: clientId); - await secureStorage.write(key: ioniaEmailStorageKey, value: email); - await secureStorage.write(key: ioniaUsernameStorageKey, value: username); - } - - // Verify email - - Future verifyEmail(String code) async { - final email = (await secureStorage.read(key: ioniaEmailStorageKey))!; - final credentials = await ioniaApi.verifyEmail(email: email, code: code, clientId: clientId); - await secureStorage.write(key: ioniaPasswordStorageKey, value: credentials.password); - await secureStorage.write(key: ioniaUsernameStorageKey, value: credentials.username); - } - - // Sign In - - Future signIn(String email) async { - await ioniaApi.signIn(email, clientId: clientId); - await secureStorage.write(key: ioniaEmailStorageKey, value: email); - } - - Future getUserEmail() async { - return (await secureStorage.read(key: ioniaEmailStorageKey))!; - } - - // Check is user logined - - Future isLogined() async { - final username = await secureStorage.read(key: ioniaUsernameStorageKey) ?? ''; - final password = await secureStorage.read(key: ioniaPasswordStorageKey) ?? ''; - return username.isNotEmpty && password.isNotEmpty; - } - - // Logout - - Future logout() async { - await secureStorage.delete(key: ioniaUsernameStorageKey); - await secureStorage.delete(key: ioniaPasswordStorageKey); - } - - // Create virtual card - - Future createCard() async { - final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!; - final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!; - return ioniaApi.createCard(username: username, password: password, clientId: clientId); - } - - // Get virtual card - - Future getCard() async { - final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!; - final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!; - return ioniaApi.getCards(username: username, password: password, clientId: clientId); - } - - // Get Merchants - - Future> getMerchants() async { - final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!; - final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!; - return ioniaApi.getMerchants(username: username, password: password, clientId: clientId); - } - - // Get Merchants By Filter - - Future> getMerchantsByFilter({ - String? search, - List? categories, - int merchantFilterType = 0}) async { - final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!; - final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!; - return ioniaApi.getMerchantsByFilter( - username: username, - password: password, - clientId: clientId, - search: search, - categories: categories, - merchantFilterType: merchantFilterType); - } - - // Purchase Gift Card - - Future purchaseGiftCard({ - required String merchId, - required double amount, - required String currency}) async { - final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!; - final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!; - final deviceId = ''; - return ioniaApi.purchaseGiftCard( - requestedUUID: deviceId, - merchId: merchId, - amount: amount, - currency: currency, - username: username, - password: password, - clientId: clientId); - } - - // Get Current User Gift Card Summaries - - Future> getCurrentUserGiftCardSummaries() async { - final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!; - final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!; - return ioniaApi.getCurrentUserGiftCardSummaries(username: username, password: password, clientId: clientId); - } - - // Charge Gift Card - - Future chargeGiftCard({ - required int giftCardId, - required double amount}) async { - final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!; - final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!; - await ioniaApi.chargeGiftCard( - username: username, - password: password, - clientId: clientId, - giftCardId: giftCardId, - amount: amount); - } - - // Redeem - - Future redeem({required int giftCardId, required double amount}) async { - await chargeGiftCard(giftCardId: giftCardId, amount: amount); - } - - // Get Gift Card - - Future getGiftCard({required int id}) async { - final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!; - final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!; - return ioniaApi.getGiftCard(username: username, password: password, clientId: clientId,id: id); - } - - // Payment Status - - Future getPaymentStatus({ - required String orderId, - required String paymentId}) async { - final username = (await secureStorage.read(key: ioniaUsernameStorageKey))!; - final password = (await secureStorage.read(key: ioniaPasswordStorageKey))!; - return ioniaApi.getPaymentStatus(username: username, password: password, clientId: clientId, orderId: orderId, paymentId: paymentId); - } -} \ No newline at end of file diff --git a/lib/ionia/ionia_tip.dart b/lib/ionia/ionia_tip.dart deleted file mode 100644 index 089c108f4..000000000 --- a/lib/ionia/ionia_tip.dart +++ /dev/null @@ -1,18 +0,0 @@ -class IoniaTip { - const IoniaTip({ - required this.originalAmount, - required this.percentage, - this.isCustom = false}); - - final double originalAmount; - final double percentage; - final bool isCustom; - - double get additionalAmount => double.parse((originalAmount * percentage / 100).toStringAsFixed(2)); - - static const tipList = [ - IoniaTip(originalAmount: 0, percentage: 0), - IoniaTip(originalAmount: 10, percentage: 10), - IoniaTip(originalAmount: 20, percentage: 20) - ]; -} diff --git a/lib/ionia/ionia_token_data.dart b/lib/ionia/ionia_token_data.dart deleted file mode 100644 index 13682ae0e..000000000 --- a/lib/ionia/ionia_token_data.dart +++ /dev/null @@ -1,43 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'dart:convert'; - -class IoniaTokenData { - IoniaTokenData({required this.accessToken, required this.tokenType, required this.expiredAt}); - - factory IoniaTokenData.fromJson(String source) { - final decoded = json.decode(source) as Map; - final accessToken = decoded['access_token'] as String; - final expiresIn = decoded['expires_in'] as int; - final tokenType = decoded['token_type'] as String; - final expiredAtInMilliseconds = decoded['expired_at'] as int; - DateTime expiredAt; - - if (expiredAtInMilliseconds != null) { - expiredAt = DateTime.fromMillisecondsSinceEpoch(expiredAtInMilliseconds); - } else { - expiredAt = DateTime.now().add(Duration(seconds: expiresIn)); - } - - return IoniaTokenData( - accessToken: accessToken, - tokenType: tokenType, - expiredAt: expiredAt); - } - - final String accessToken; - final String tokenType; - final DateTime expiredAt; - - bool get isExpired => DateTime.now().isAfter(expiredAt); - - @override - String toString() => '$tokenType $accessToken'; - - String toJson() { - return json.encode({ - 'access_token': accessToken, - 'token_type': tokenType, - 'expired_at': expiredAt.millisecondsSinceEpoch - }); - } -} \ No newline at end of file diff --git a/lib/ionia/ionia_user_credentials.dart b/lib/ionia/ionia_user_credentials.dart deleted file mode 100644 index c398385f5..000000000 --- a/lib/ionia/ionia_user_credentials.dart +++ /dev/null @@ -1,6 +0,0 @@ -class IoniaUserCredentials { - const IoniaUserCredentials(this.username, this.password); - - final String username; - final String password; -} \ No newline at end of file diff --git a/lib/ionia/ionia_virtual_card.dart b/lib/ionia/ionia_virtual_card.dart deleted file mode 100644 index ca3e35dbc..000000000 --- a/lib/ionia/ionia_virtual_card.dart +++ /dev/null @@ -1,41 +0,0 @@ -class IoniaVirtualCard { - IoniaVirtualCard({ - required this.token, - required this.createdAt, - required this.lastFour, - required this.state, - required this.pan, - required this.cvv, - required this.expirationMonth, - required this.expirationYear, - required this.fundsLimit, - required this.spendLimit}); - - factory IoniaVirtualCard.fromMap(Map source) { - final created = source['created'] as String; - final createdAt = DateTime.tryParse(created); - - return IoniaVirtualCard( - token: source['token'] as String, - createdAt: createdAt, - lastFour: source['lastFour'] as String, - state: source['state'] as String, - pan: source['pan'] as String, - cvv: source['cvv'] as String, - expirationMonth: source['expirationMonth'] as String, - expirationYear: source['expirationYear'] as String, - fundsLimit: source['FundsLimit'] as double, - spendLimit: source['spend_limit'] as double); - } - - final String token; - final String lastFour; - final String state; - final String pan; - final String cvv; - final String expirationMonth; - final String expirationYear; - final DateTime? createdAt; - final double fundsLimit; - final double spendLimit; -} \ No newline at end of file diff --git a/lib/router.dart b/lib/router.dart index e113e42f9..c09664cef 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -1,6 +1,5 @@ import 'package:cake_wallet/anonpay/anonpay_info_base.dart'; import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart'; -import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart'; import 'package:cake_wallet/buy/order.dart'; import 'package:cake_wallet/core/totp_request_details.dart'; import 'package:cake_wallet/core/wallet_connect/web3wallet_service.dart'; @@ -10,7 +9,6 @@ import 'package:cake_wallet/entities/qr_view_data.dart'; import 'package:cake_wallet/entities/wallet_nft_response.dart'; import 'package:cake_wallet/exchange/trade.dart'; import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/screens/anonpay_details/anonpay_details_page.dart'; 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'; import 'package:cake_wallet/src/screens/exchange_trade/exchange_confirm_page.dart'; import 'package:cake_wallet/src/screens/exchange_trade/exchange_trade_page.dart'; import 'package:cake_wallet/src/screens/faq/faq_page.dart'; -import 'package:cake_wallet/src/screens/ionia/cards/ionia_account_cards_page.dart'; -import 'package:cake_wallet/src/screens/ionia/cards/ionia_account_page.dart'; -import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_redeem_page.dart'; -import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_tip_page.dart'; -import 'package:cake_wallet/src/screens/ionia/cards/ionia_gift_card_detail_page.dart'; -import 'package:cake_wallet/src/screens/ionia/cards/ionia_more_options_page.dart'; -import 'package:cake_wallet/src/screens/ionia/cards/ionia_payment_status_page.dart'; -import 'package:cake_wallet/src/screens/ionia/ionia.dart'; import 'package:cake_wallet/src/screens/monero_accounts/monero_account_edit_or_create_page.dart'; import 'package:cake_wallet/src/screens/nano/nano_change_rep_page.dart'; 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'; import 'package:cake_wallet/src/screens/settings/other_settings_page.dart'; import 'package:cake_wallet/src/screens/settings/privacy_page.dart'; import 'package:cake_wallet/src/screens/settings/security_backup_page.dart'; +import 'package:cake_wallet/src/screens/cake_pay/auth/cake_pay_account_page.dart'; import 'package:cake_wallet/src/screens/settings/silent_payments_settings.dart'; import 'package:cake_wallet/src/screens/settings/tor_page.dart'; import 'package:cake_wallet/src/screens/settings/trocador_providers_page.dart'; +import 'package:cake_wallet/src/screens/settings/tor_page.dart'; import 'package:cake_wallet/src/screens/setup_2fa/modify_2fa_page.dart'; import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa.dart'; 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'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; - +import 'package:cake_wallet/src/screens/cake_pay/cake_pay.dart'; import 'src/screens/dashboard/pages/nft_import_page.dart'; late RouteSettings currentRouteSettings; @@ -518,73 +510,30 @@ Route createRoute(RouteSettings settings) { param1: settings.arguments as QrViewData, )); - case Routes.ioniaWelcomePage: + case Routes.cakePayCardsPage: + return CupertinoPageRoute(builder: (_) => getIt.get()); + + case Routes.cakePayBuyCardPage: + final args = settings.arguments as List; return CupertinoPageRoute( - fullscreenDialog: true, - builder: (_) => getIt.get(), + builder: (_) => getIt.get(param1: args)); + + case Routes.cakePayBuyCardDetailPage: + final args = settings.arguments as List; + return CupertinoPageRoute( + builder: (_) => getIt.get(param1: args)); + + case Routes.cakePayWelcomePage: + return CupertinoPageRoute( + builder: (_) => getIt.get(), ); - case Routes.ioniaLoginPage: - return CupertinoPageRoute(builder: (_) => getIt.get()); - - case Routes.ioniaCreateAccountPage: - return CupertinoPageRoute(builder: (_) => getIt.get()); - - case Routes.ioniaManageCardsPage: - return CupertinoPageRoute(builder: (_) => getIt.get()); - - case Routes.ioniaBuyGiftCardPage: + case Routes.cakePayVerifyOtpPage: final args = settings.arguments as List; - return CupertinoPageRoute( - builder: (_) => getIt.get(param1: args)); + return CupertinoPageRoute(builder: (_) => getIt.get(param1: args)); - case Routes.ioniaBuyGiftCardDetailPage: - final args = settings.arguments as List; - return CupertinoPageRoute( - builder: (_) => getIt.get(param1: args)); - - case Routes.ioniaVerifyIoniaOtpPage: - final args = settings.arguments as List; - return CupertinoPageRoute(builder: (_) => getIt.get(param1: args)); - - case Routes.ioniaDebitCardPage: - return CupertinoPageRoute(builder: (_) => getIt.get()); - - case Routes.ioniaActivateDebitCardPage: - return CupertinoPageRoute(builder: (_) => getIt.get()); - - case Routes.ioniaAccountPage: - return CupertinoPageRoute(builder: (_) => getIt.get()); - - case Routes.ioniaAccountCardsPage: - return CupertinoPageRoute(builder: (_) => getIt.get()); - - case Routes.ioniaCustomTipPage: - final args = settings.arguments as List; - return CupertinoPageRoute(builder: (_) => getIt.get(param1: args)); - - case Routes.ioniaGiftCardDetailPage: - final args = settings.arguments as List; - return CupertinoPageRoute( - builder: (_) => getIt.get(param1: args.first)); - - case Routes.ioniaCustomRedeemPage: - final args = settings.arguments as List; - return CupertinoPageRoute( - builder: (_) => getIt.get(param1: args)); - - case Routes.ioniaMoreOptionsPage: - final args = settings.arguments as List; - return CupertinoPageRoute( - builder: (_) => getIt.get(param1: args)); - - case Routes.ioniaPaymentStatusPage: - final args = settings.arguments as List; - final paymentInfo = args.first as IoniaAnyPayPaymentInfo; - final commitedInfo = args[1] as AnyPayPaymentCommittedInfo; - return CupertinoPageRoute( - builder: (_) => - getIt.get(param1: paymentInfo, param2: commitedInfo)); + case Routes.cakePayAccountPage: + return CupertinoPageRoute(builder: (_) => getIt.get()); case Routes.webViewPage: final args = settings.arguments as List; diff --git a/lib/routes.dart b/lib/routes.dart index b5208416f..78a93bee7 100644 --- a/lib/routes.dart +++ b/lib/routes.dart @@ -64,22 +64,13 @@ class Routes { static const unspentCoinsDetails = '/unspent_coins_details'; static const addressPage = '/address_page'; static const fullscreenQR = '/fullscreen_qr'; - static const ioniaWelcomePage = '/cake_pay_welcome_page'; - static const ioniaCreateAccountPage = '/cake_pay_create_account_page'; - static const ioniaLoginPage = '/cake_pay_login_page'; - static const ioniaManageCardsPage = '/manage_cards_page'; - static const ioniaBuyGiftCardPage = '/buy_gift_card_page'; - static const ioniaBuyGiftCardDetailPage = '/buy_gift_card_detail_page'; - static const ioniaVerifyIoniaOtpPage = '/cake_pay_verify_otp_page'; - static const ioniaDebitCardPage = '/debit_card_page'; - static const ioniaActivateDebitCardPage = '/activate_debit_card_page'; - static const ioniaAccountPage = 'ionia_account_page'; - static const ioniaAccountCardsPage = 'ionia_account_cards_page'; - static const ioniaCustomTipPage = 'ionia_custom_tip_page'; - static const ioniaGiftCardDetailPage = '/ionia_gift_card_detail_page'; - static const ioniaPaymentStatusPage = '/ionia_payment_status_page'; - static const ioniaMoreOptionsPage = '/ionia_more_options_page'; - static const ioniaCustomRedeemPage = '/ionia_custom_redeem_page'; + static const cakePayWelcomePage = '/cake_pay_welcome_page'; + static const cakePayLoginPage = '/cake_pay_login_page'; + static const cakePayCardsPage = '/cake_pay_cards_page'; + static const cakePayBuyCardPage = '/cake_pay_buy_card_page'; + static const cakePayBuyCardDetailPage = '/cake_pay_buy_card_detail_page'; + static const cakePayVerifyOtpPage = '/cake_pay_verify_otp_page'; + static const cakePayAccountPage = '/cake_pay_account_page'; static const webViewPage = '/web_view_page'; static const silentPaymentsSettings = '/silent_payments_settings'; static const connectionSync = '/connection_sync_page'; diff --git a/lib/src/screens/base_page.dart b/lib/src/screens/base_page.dart index bf60525e4..fbf4bb1fa 100644 --- a/lib/src/screens/base_page.dart +++ b/lib/src/screens/base_page.dart @@ -7,7 +7,7 @@ import 'package:cake_wallet/store/settings_store.dart'; import 'package:cake_wallet/src/widgets/nav_bar.dart'; import 'package:cake_wallet/generated/i18n.dart'; -enum AppBarStyle { regular, withShadow, transparent } +enum AppBarStyle { regular, withShadow, transparent, completelyTransparent } abstract class BasePage extends StatelessWidget { BasePage() : _scaffoldKey = GlobalKey(); @@ -125,7 +125,7 @@ abstract class BasePage extends StatelessWidget { Widget? floatingActionButton(BuildContext context) => null; - ObstructingPreferredSizeWidget appBar(BuildContext context) { + PreferredSizeWidget appBar(BuildContext context) { final appBarColor = pageBackgroundColor(context); switch (appBarStyle) { @@ -156,6 +156,16 @@ abstract class BasePage extends StatelessWidget { border: null, ); + case AppBarStyle.completelyTransparent: + return AppBar( + leading: leading(context), + title: middle(context), + actions: [if (trailing(context) != null) trailing(context)!], + backgroundColor: Colors.transparent, + elevation: 0, + centerTitle: true, + ); + default: // FIX-ME: NavBar no context return NavBar( diff --git a/lib/src/screens/cake_pay/auth/cake_pay_account_page.dart b/lib/src/screens/cake_pay/auth/cake_pay_account_page.dart new file mode 100644 index 000000000..4a958a661 --- /dev/null +++ b/lib/src/screens/cake_pay/auth/cake_pay_account_page.dart @@ -0,0 +1,90 @@ +import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; +import 'package:cake_wallet/routes.dart'; +import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/src/screens/cake_pay/widgets/cake_pay_tile.dart'; +import 'package:cake_wallet/src/widgets/primary_button.dart'; +import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; +import 'package:cake_wallet/typography.dart'; +import 'package:cake_wallet/view_model/cake_pay/cake_pay_account_view_model.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; + +class CakePayAccountPage extends BasePage { + CakePayAccountPage(this.cakePayAccountViewModel); + + final CakePayAccountViewModel cakePayAccountViewModel; + + + + @override + Widget leading(BuildContext context) { + return MergeSemantics( + child: SizedBox( + height: 37, + width: 37, + child: ButtonTheme( + minWidth: double.minPositive, + child: Semantics( + label: S.of(context).seed_alert_back, + child: TextButton( + style: ButtonStyle( + overlayColor: MaterialStateColor.resolveWith( + (states) => Colors.transparent), + ), + onPressed: () => Navigator.pop(context), + child: backButton(context), + ), + ), + ), + ), + ); + } + + @override + Widget middle(BuildContext context) { + return Text( + S.current.account, + style: textMediumSemiBold( + color: Theme.of(context).extension()!.titleColor, + ), + ); + } + + @override + Widget body(BuildContext context) { + return ScrollableWithBottomSection( + contentPadding: EdgeInsets.all(24), + content: Column( + children: [ + SizedBox(height: 20), + Observer( + builder: (_) => Container(decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + width: 1.0, + color: + Theme.of(context).extension()!.secondaryTextColor), + ), + ), + child: CakePayTile(title: S.of(context).email_address, subTitle: cakePayAccountViewModel.email)), + ), + ], + ), + bottomSectionPadding: EdgeInsets.all(30), + bottomSection: Column( + children: [ + PrimaryButton( + color: Theme.of(context).primaryColor, + textColor: Colors.white, + text: S.of(context).logout, + onPressed: () { + cakePayAccountViewModel.logout(); + Navigator.pushNamedAndRemoveUntil(context, Routes.dashboard, (route) => false); + }, + ), + ], + ), + ); + } +} diff --git a/lib/src/screens/ionia/auth/ionia_verify_otp_page.dart b/lib/src/screens/cake_pay/auth/cake_pay_verify_otp_page.dart similarity index 81% rename from lib/src/screens/ionia/auth/ionia_verify_otp_page.dart rename to lib/src/screens/cake_pay/auth/cake_pay_verify_otp_page.dart index e8327b71c..34b02db93 100644 --- a/lib/src/screens/ionia/auth/ionia_verify_otp_page.dart +++ b/lib/src/screens/cake_pay/auth/cake_pay_verify_otp_page.dart @@ -1,39 +1,38 @@ -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; -import 'package:cake_wallet/themes/extensions/keyboard_theme.dart'; -import 'package:cake_wallet/ionia/ionia_create_state.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_states.dart'; import 'package:cake_wallet/palette.dart'; -import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart'; import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; +import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; +import 'package:cake_wallet/themes/extensions/keyboard_theme.dart'; import 'package:cake_wallet/typography.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_auth_view_model.dart'; +import 'package:cake_wallet/view_model/cake_pay/cake_pay_auth_view_model.dart'; import 'package:flutter/material.dart'; -import 'package:cake_wallet/generated/i18n.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:keyboard_actions/keyboard_actions.dart'; import 'package:mobx/mobx.dart'; -class IoniaVerifyIoniaOtp extends BasePage { - IoniaVerifyIoniaOtp(this._authViewModel, this._email, this.isSignIn) +class CakePayVerifyOtpPage extends BasePage { + CakePayVerifyOtpPage(this._authViewModel, this._email, this.isSignIn) : _codeController = TextEditingController(), _codeFocus = FocusNode() { _codeController.addListener(() { final otp = _codeController.text; _authViewModel.otp = otp; - if (otp.length > 3) { - _authViewModel.otpState = IoniaOtpSendEnabled(); + if (otp.length > 5) { + _authViewModel.otpState = CakePayOtpSendEnabled(); } else { - _authViewModel.otpState = IoniaOtpSendDisabled(); + _authViewModel.otpState = CakePayOtpSendDisabled(); } }); } - final IoniaAuthViewModel _authViewModel; + final CakePayAuthViewModel _authViewModel; final bool isSignIn; final String _email; @@ -53,11 +52,11 @@ class IoniaVerifyIoniaOtp extends BasePage { @override Widget body(BuildContext context) { - reaction((_) => _authViewModel.otpState, (IoniaOtpState state) { - if (state is IoniaOtpFailure) { + reaction((_) => _authViewModel.otpState, (CakePayOtpState state) { + if (state is CakePayOtpFailure) { _onOtpFailure(context, state.error); } - if (state is IoniaOtpSuccess) { + if (state is CakePayOtpSuccess) { _onOtpSuccessful(context); } }); @@ -98,9 +97,7 @@ class IoniaVerifyIoniaOtp extends BasePage { Text(S.of(context).didnt_get_code), SizedBox(width: 20), InkWell( - onTap: () => isSignIn - ? _authViewModel.signIn(_email) - : _authViewModel.createUser(_email), + onTap: () => _authViewModel.logIn(_email), child: Text( S.of(context).resend_code, style: textSmallSemiBold(color: Palette.blueCraiola), @@ -120,8 +117,8 @@ class IoniaVerifyIoniaOtp extends BasePage { builder: (_) => LoadingPrimaryButton( text: S.of(context).continue_text, onPressed: _verify, - isDisabled: _authViewModel.otpState is IoniaOtpSendDisabled, - isLoading: _authViewModel.otpState is IoniaOtpValidating, + isDisabled: _authViewModel.otpState is CakePayOtpSendDisabled, + isLoading: _authViewModel.otpState is CakePayOtpValidating, color: Theme.of(context).primaryColor, textColor: Colors.white, ), @@ -149,8 +146,7 @@ class IoniaVerifyIoniaOtp extends BasePage { } void _onOtpSuccessful(BuildContext context) => - Navigator.of(context) - .pushNamedAndRemoveUntil(Routes.ioniaManageCardsPage, (route) => route.isFirst); + Navigator.pop(context); void _verify() async => await _authViewModel.verifyEmail(_codeController.text); } diff --git a/lib/src/screens/ionia/auth/ionia_login_page.dart b/lib/src/screens/cake_pay/auth/cake_pay_welcome_page.dart similarity index 62% rename from lib/src/screens/ionia/auth/ionia_login_page.dart rename to lib/src/screens/cake_pay/auth/cake_pay_welcome_page.dart index 1bdcfc3a4..cd893daf4 100644 --- a/lib/src/screens/ionia/auth/ionia_login_page.dart +++ b/lib/src/screens/cake_pay/auth/cake_pay_welcome_page.dart @@ -1,22 +1,22 @@ import 'package:cake_wallet/core/email_validator.dart'; -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; -import 'package:cake_wallet/ionia/ionia_create_state.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_states.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart'; import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; +import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; import 'package:cake_wallet/typography.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_auth_view_model.dart'; +import 'package:cake_wallet/view_model/cake_pay/cake_pay_auth_view_model.dart'; import 'package:flutter/material.dart'; -import 'package:cake_wallet/generated/i18n.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:mobx/mobx.dart'; -class IoniaLoginPage extends BasePage { - IoniaLoginPage(this._authViewModel) +class CakePayWelcomePage extends BasePage { + CakePayWelcomePage(this._authViewModel) : _formKey = GlobalKey(), _emailController = TextEditingController() { _emailController.text = _authViewModel.email; @@ -25,14 +25,14 @@ class IoniaLoginPage extends BasePage { final GlobalKey _formKey; - final IoniaAuthViewModel _authViewModel; + final CakePayAuthViewModel _authViewModel; final TextEditingController _emailController; @override Widget middle(BuildContext context) { return Text( - S.current.login, + S.current.welcome_to_cakepay, style: textMediumSemiBold( color: Theme.of(context).extension()!.titleColor, ), @@ -41,25 +41,40 @@ class IoniaLoginPage extends BasePage { @override Widget body(BuildContext context) { - reaction((_) => _authViewModel.signInState, (IoniaCreateAccountState state) { - if (state is IoniaCreateStateFailure) { + reaction((_) => _authViewModel.userVerificationState, (CakePayUserVerificationState state) { + if (state is CakePayUserVerificationStateFailure) { _onLoginUserFailure(context, state.error); } - if (state is IoniaCreateStateSuccess) { + if (state is CakePayUserVerificationStateSuccess) { _onLoginSuccessful(context, _authViewModel); } }); return ScrollableWithBottomSection( contentPadding: EdgeInsets.all(24), - content: Form( - key: _formKey, - child: BaseTextFormField( - hintText: S.of(context).email_address, - keyboardType: TextInputType.emailAddress, - validator: EmailValidator(), - controller: _emailController, - onSubmit: (text) => _login(), - ), + content: Column( + children: [ + SizedBox(height: 90), + Form( + key: _formKey, + child: BaseTextFormField( + hintText: S.of(context).email_address, + keyboardType: TextInputType.emailAddress, + validator: EmailValidator(), + controller: _emailController, + onSubmit: (text) => _login(), + ), + ), + SizedBox(height: 20), + Text( + S.of(context).about_cake_pay, + style: textLarge( + color: Theme.of(context).extension()!.titleColor, + ), + ), + SizedBox(height: 20), + Text(S.of(context).cake_pay_account_note, + style: textLarge(color: Theme.of(context).extension()!.titleColor)), + ], ), bottomSectionPadding: EdgeInsets.symmetric(vertical: 36, horizontal: 24), bottomSection: Column( @@ -71,7 +86,8 @@ class IoniaLoginPage extends BasePage { builder: (_) => LoadingPrimaryButton( text: S.of(context).login, onPressed: _login, - isLoading: _authViewModel.signInState is IoniaCreateStateLoading, + isLoading: + _authViewModel.userVerificationState is CakePayUserVerificationStateLoading, color: Theme.of(context).primaryColor, textColor: Colors.white, ), @@ -98,9 +114,10 @@ class IoniaLoginPage extends BasePage { }); } - void _onLoginSuccessful(BuildContext context, IoniaAuthViewModel authViewModel) => Navigator.pushNamed( + void _onLoginSuccessful(BuildContext context, CakePayAuthViewModel authViewModel) => + Navigator.pushReplacementNamed( context, - Routes.ioniaVerifyIoniaOtpPage, + Routes.cakePayVerifyOtpPage, arguments: [authViewModel.email, true], ); @@ -108,6 +125,6 @@ class IoniaLoginPage extends BasePage { if (_formKey.currentState != null && !_formKey.currentState!.validate()) { return; } - await _authViewModel.signIn(_emailController.text); + await _authViewModel.logIn(_emailController.text); } } diff --git a/lib/src/screens/cake_pay/cake_pay.dart b/lib/src/screens/cake_pay/cake_pay.dart new file mode 100644 index 000000000..a65b6bed3 --- /dev/null +++ b/lib/src/screens/cake_pay/cake_pay.dart @@ -0,0 +1,5 @@ +export 'auth/cake_pay_welcome_page.dart'; +export 'auth/cake_pay_verify_otp_page.dart'; +export 'cards/cake_pay_confirm_purchase_card_page.dart'; +export 'cards/cake_pay_cards_page.dart'; +export 'cards/cake_pay_buy_card_page.dart'; diff --git a/lib/src/screens/cake_pay/cards/cake_pay_buy_card_page.dart b/lib/src/screens/cake_pay/cards/cake_pay_buy_card_page.dart new file mode 100644 index 000000000..6e1af1c32 --- /dev/null +++ b/lib/src/screens/cake_pay/cards/cake_pay_buy_card_page.dart @@ -0,0 +1,474 @@ +import 'package:auto_size_text/auto_size_text.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_card.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_payment_credantials.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_service.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/routes.dart'; +import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/src/screens/cake_pay/widgets/image_placeholder.dart'; +import 'package:cake_wallet/src/screens/cake_pay/widgets/link_extractor.dart'; +import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; +import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; +import 'package:cake_wallet/src/widgets/number_text_fild_widget.dart'; +import 'package:cake_wallet/src/widgets/primary_button.dart'; +import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; +import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; +import 'package:cake_wallet/themes/extensions/keyboard_theme.dart'; +import 'package:cake_wallet/themes/extensions/send_page_theme.dart'; +import 'package:cake_wallet/typography.dart'; +import 'package:cake_wallet/utils/responsive_layout_util.dart'; +import 'package:cake_wallet/view_model/cake_pay/cake_pay_buy_card_view_model.dart'; +import 'package:cake_wallet/view_model/dashboard/dropdown_filter_item_widget.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:keyboard_actions/keyboard_actions.dart'; + +class CakePayBuyCardPage extends BasePage { + CakePayBuyCardPage( + this.cakePayBuyCardViewModel, + this.cakePayService, + ) : _amountFieldFocus = FocusNode(), + _amountController = TextEditingController(), + _quantityFieldFocus = FocusNode(), + _quantityController = + TextEditingController(text: cakePayBuyCardViewModel.quantity.toString()) { + _amountController.addListener(() { + cakePayBuyCardViewModel.onAmountChanged(_amountController.text); + }); + } + + final CakePayBuyCardViewModel cakePayBuyCardViewModel; + final CakePayService cakePayService; + + @override + String get title => cakePayBuyCardViewModel.card.name; + + @override + bool get extendBodyBehindAppBar => true; + + @override + AppBarStyle get appBarStyle => AppBarStyle.completelyTransparent; + + @override + Widget? middle(BuildContext context) { + return Text( + title, + textAlign: TextAlign.center, + maxLines: 2, + style: TextStyle( + fontSize: 18.0, + fontWeight: FontWeight.bold, + fontFamily: 'Lato', + color: titleColor(context)), + ); + } + + final TextEditingController _amountController; + final FocusNode _amountFieldFocus; + final TextEditingController _quantityController; + final FocusNode _quantityFieldFocus; + + @override + Widget body(BuildContext context) { + final card = cakePayBuyCardViewModel.card; + final vendor = cakePayBuyCardViewModel.vendor; + + return KeyboardActions( + disableScroll: true, + config: KeyboardActionsConfig( + keyboardActionsPlatform: KeyboardActionsPlatform.IOS, + keyboardBarColor: Theme.of(context).extension()!.keyboardBarColor, + nextFocus: false, + actions: [ + KeyboardActionsItem( + focusNode: _amountFieldFocus, + toolbarButtons: [(_) => KeyboardDoneButton()], + ), + ]), + child: Container( + color: Theme.of(context).colorScheme.background, + child: ScrollableWithBottomSection( + contentPadding: EdgeInsets.zero, + content: Column( + children: [ + ClipRRect( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(25.0), bottomRight: Radius.circular(25.0)), + child: Container( + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + Theme.of(context).extension()!.firstGradientColor, + Theme.of(context).extension()!.secondGradientColor, + ], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + ), + height: responsiveLayoutUtil.screenHeight * 0.35, + width: double.infinity, + child: Column( + children: [ + Expanded(flex: 4, child: const SizedBox()), + Expanded( + flex: 7, + child: ClipRRect( + borderRadius: BorderRadius.all(Radius.circular(10)), + child: Image.network( + card.cardImageUrl ?? '', + fit: BoxFit.cover, + loadingBuilder: (BuildContext context, Widget child, + ImageChunkEvent? loadingProgress) { + if (loadingProgress == null) return child; + return Center(child: CircularProgressIndicator()); + }, + errorBuilder: (context, error, stackTrace) => + CakePayCardImagePlaceholder(), + ), + ), + ), + Expanded(child: const SizedBox()), + ], + )), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 24), + child: Container( + height: responsiveLayoutUtil.screenHeight * 0.5, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox(height: 24), + Expanded( + child: Text(S.of(context).enter_amount, + style: TextStyle( + color: Theme.of(context).extension()!.titleColor, + fontSize: 24, + fontWeight: FontWeight.w600, + )), + ), + card.denominations.isNotEmpty + ? Expanded( + flex: 2, + child: _DenominationsAmountWidget( + fiatCurrency: card.fiatCurrency.title, + denominations: card.denominations, + amountFieldFocus: _amountFieldFocus, + amountController: _amountController, + quantityFieldFocus: _quantityFieldFocus, + quantityController: _quantityController, + onAmountChanged: cakePayBuyCardViewModel.onAmountChanged, + onQuantityChanged: cakePayBuyCardViewModel.onQuantityChanged, + cakePayBuyCardViewModel: cakePayBuyCardViewModel, + ), + ) + : Expanded( + flex: 2, + child: _EnterAmountWidget( + minValue: card.minValue ?? '-', + maxValue: card.maxValue ?? '-', + fiatCurrency: card.fiatCurrency.title, + amountFieldFocus: _amountFieldFocus, + amountController: _amountController, + onAmountChanged: cakePayBuyCardViewModel.onAmountChanged, + ), + ), + Expanded( + flex: 5, + child: Column( + children: [ + if (vendor.cakeWarnings != null) + Padding( + padding: const EdgeInsets.only(bottom: 8.0), + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).primaryColor, + borderRadius: BorderRadius.circular(10), + border: Border.all(color: Colors.white.withOpacity(0.20)), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + vendor.cakeWarnings!, + textAlign: TextAlign.center, + style: textSmallSemiBold(color: Colors.white), + ), + ), + ), + ), + Expanded( + child: SingleChildScrollView( + child: ClickableLinksText( + text: card.description ?? '', + textStyle: TextStyle( + color: Theme.of(context) + .extension()! + .secondaryTextColor, + fontSize: 18, + fontWeight: FontWeight.w400, + ), + ), + ), + ), + ], + ), + ), + ], + ), + ), + ), + ], + ), + bottomSection: Column( + children: [ + Observer(builder: (_) { + return Padding( + padding: EdgeInsets.only(bottom: 12), + child: PrimaryButton( + onPressed: () => navigateToCakePayBuyCardDetailPage(context, card), + text: S.of(context).buy_now, + isDisabled: !cakePayBuyCardViewModel.isEnablePurchase, + color: Theme.of(context).primaryColor, + textColor: Colors.white, + ), + ); + }), + ], + ), + ), + ), + ); + } + + Future navigateToCakePayBuyCardDetailPage(BuildContext context, CakePayCard card) async { + final userName = await cakePayService.getUserEmail(); + final paymentCredential = PaymentCredential( + amount: cakePayBuyCardViewModel.amount, + quantity: cakePayBuyCardViewModel.quantity, + totalAmount: cakePayBuyCardViewModel.totalAmount, + userName: userName, + fiatCurrency: card.fiatCurrency.title, + ); + + Navigator.pushNamed( + context, + Routes.cakePayBuyCardDetailPage, + arguments: [paymentCredential, card], + ); + } +} + +class _DenominationsAmountWidget extends StatelessWidget { + const _DenominationsAmountWidget({ + required this.fiatCurrency, + required this.denominations, + required this.amountFieldFocus, + required this.amountController, + required this.quantityFieldFocus, + required this.quantityController, + required this.cakePayBuyCardViewModel, + required this.onAmountChanged, + required this.onQuantityChanged, + }); + + final String fiatCurrency; + final List denominations; + final FocusNode amountFieldFocus; + final TextEditingController amountController; + final FocusNode quantityFieldFocus; + final TextEditingController quantityController; + final CakePayBuyCardViewModel cakePayBuyCardViewModel; + final Function(String) onAmountChanged; + final Function(int?) onQuantityChanged; + + @override + Widget build(BuildContext context) { + return Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + flex: 12, + child: Column( + children: [ + Expanded( + child: DropdownFilterList( + items: denominations, + itemPrefix: fiatCurrency, + selectedItem: denominations.first, + textStyle: textMediumSemiBold( + color: Theme.of(context).extension()!.titleColor), + onItemSelected: (value) { + amountController.text = value; + onAmountChanged(value); + }, + caption: '', + ), + ), + const SizedBox(height: 4), + Expanded( + child: Container( + width: double.infinity, + decoration: BoxDecoration( + border: Border( + top: BorderSide( + width: 1.0, + color: Theme.of(context).extension()!.secondaryTextColor), + ), + ), + child: Text(S.of(context).choose_card_value + ':', + maxLines: 2, + style: textSmall( + color: Theme.of(context).extension()!.secondaryTextColor)), + ), + ), + ], + ), + ), + Expanded(child: const SizedBox()), + Expanded( + flex: 8, + child: Column( + children: [ + Expanded( + child: NumberTextField( + controller: quantityController, + focusNode: quantityFieldFocus, + min: 1, + max: 99, + onChanged: (value) => onQuantityChanged(value), + ), + ), + const SizedBox(height: 4), + Expanded( + child: Container( + width: double.infinity, + decoration: BoxDecoration( + border: Border( + top: BorderSide( + width: 1.0, + color: Theme.of(context).extension()!.secondaryTextColor), + ), + ), + child: Text(S.of(context).quantity + ':', + maxLines: 1, + style: textSmall( + color: Theme.of(context).extension()!.secondaryTextColor)), + ), + ), + ], + ), + ), + Expanded(child: const SizedBox()), + Expanded( + flex: 12, + child: Column( + children: [ + Expanded( + child: Container( + alignment: Alignment.bottomCenter, + child: Observer( + builder: (_) => AutoSizeText( + '$fiatCurrency ${cakePayBuyCardViewModel.totalAmount}', + maxLines: 1, + style: textMediumSemiBold( + color: + Theme.of(context).extension()!.titleColor)))), + ), + const SizedBox(height: 4), + Expanded( + child: Container( + width: double.infinity, + decoration: BoxDecoration( + border: Border( + top: BorderSide( + width: 1.0, + color: + Theme.of(context).extension()!.secondaryTextColor), + ), + ), + child: Text(S.of(context).total + ':', + maxLines: 1, + style: textSmall( + color: + Theme.of(context).extension()!.secondaryTextColor)), + ), + ), + ], + )), + ], + ); + } +} + +class _EnterAmountWidget extends StatelessWidget { + const _EnterAmountWidget({ + required this.minValue, + required this.maxValue, + required this.fiatCurrency, + required this.amountFieldFocus, + required this.amountController, + required this.onAmountChanged, + }); + + final String minValue; + final String maxValue; + final String fiatCurrency; + final FocusNode amountFieldFocus; + final TextEditingController amountController; + final Function(String) onAmountChanged; + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Container( + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + width: 1.0, + color: Theme.of(context).extension()!.secondaryTextColor), + ), + ), + child: BaseTextFormField( + controller: amountController, + keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true), + hintText: '0.00', + maxLines: null, + borderColor: Colors.transparent, + prefixIcon: Padding( + padding: const EdgeInsets.only(top: 12), + child: Text( + '$fiatCurrency: ', + style: textMediumSemiBold( + color: Theme.of(context).extension()!.titleColor), + ), + ), + textStyle: + textMediumSemiBold(color: Theme.of(context).extension()!.titleColor), + placeholderTextStyle: textMediumSemiBold( + color: Theme.of(context).extension()!.secondaryTextColor), + inputFormatters: [ + FilteringTextInputFormatter.deny(RegExp('[\-|\ ]')), + FilteringTextInputFormatter.allow( + RegExp(r'^\d+(\.|\,)?\d{0,2}'), + ), + ], + ), + ), + SizedBox(height: 4), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(S.of(context).min_amount(minValue) + ' $fiatCurrency', + style: textSmall( + color: Theme.of(context).extension()!.secondaryTextColor)), + Text(S.of(context).max_amount(maxValue) + ' $fiatCurrency', + style: textSmall( + color: Theme.of(context).extension()!.secondaryTextColor)), + ], + ), + ], + ); + } +} diff --git a/lib/src/screens/ionia/cards/ionia_manage_cards_page.dart b/lib/src/screens/cake_pay/cards/cake_pay_cards_page.dart similarity index 50% rename from lib/src/screens/ionia/cards/ionia_manage_cards_page.dart rename to lib/src/screens/cake_pay/cards/cake_pay_cards_page.dart index c29f571b4..35a58ce0a 100644 --- a/lib/src/screens/ionia/cards/ionia_manage_cards_page.dart +++ b/lib/src/screens/cake_pay/cards/cake_pay_cards_page.dart @@ -1,42 +1,40 @@ -import 'package:cake_wallet/ionia/ionia_create_state.dart'; -import 'package:cake_wallet/ionia/ionia_merchant.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_states.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_vendor.dart'; +import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/src/screens/base_page.dart'; -import 'package:cake_wallet/src/widgets/gradient_background.dart'; -import 'package:cake_wallet/src/screens/ionia/widgets/card_item.dart'; -import 'package:cake_wallet/src/screens/ionia/widgets/card_menu.dart'; -import 'package:cake_wallet/src/screens/ionia/widgets/ionia_filter_modal.dart'; +import 'package:cake_wallet/src/screens/cake_pay/widgets/card_item.dart'; +import 'package:cake_wallet/src/screens/cake_pay/widgets/card_menu.dart'; +import 'package:cake_wallet/src/screens/dashboard/widgets/filter_widget.dart'; import 'package:cake_wallet/src/widgets/cake_scrollbar.dart'; -import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart'; -import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart'; -import 'package:cake_wallet/themes/theme_base.dart'; -import 'package:cake_wallet/utils/debounce.dart'; -import 'package:cake_wallet/typography.dart'; -import 'package:cake_wallet/utils/show_pop_up.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_gift_cards_list_view_model.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart'; +import 'package:cake_wallet/src/widgets/gradient_background.dart'; import 'package:cake_wallet/themes/extensions/balance_page_theme.dart'; +import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart'; +import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart'; import 'package:cake_wallet/themes/extensions/filter_theme.dart'; +import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart'; +import 'package:cake_wallet/typography.dart'; +import 'package:cake_wallet/utils/debounce.dart'; +import 'package:cake_wallet/utils/responsive_layout_util.dart'; +import 'package:cake_wallet/utils/show_pop_up.dart'; +import 'package:cake_wallet/view_model/cake_pay/cake_pay_cards_list_view_model.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; -class IoniaManageCardsPage extends BasePage { - IoniaManageCardsPage(this._cardsListViewModel): searchFocusNode = FocusNode() { +class CakePayCardsPage extends BasePage { + CakePayCardsPage(this._cardsListViewModel) : searchFocusNode = FocusNode() { _searchController.addListener(() { if (_searchController.text != _cardsListViewModel.searchString) { _searchDebounce.run(() { - _cardsListViewModel.searchMerchant(_searchController.text); + _cardsListViewModel.resetLoadingNextPageState(); + _cardsListViewModel.getVendors(text: _searchController.text); }); } }); - - _cardsListViewModel.getMerchants(); - } + final FocusNode searchFocusNode; - final IoniaGiftCardsListViewModel _cardsListViewModel; + final CakePayCardsListViewModel _cardsListViewModel; final _searchDebounce = Debounce(Duration(milliseconds: 500)); final _searchController = TextEditingController(); @@ -46,8 +44,7 @@ class IoniaManageCardsPage extends BasePage { @override Widget Function(BuildContext, Widget) get rootWrapper => - (BuildContext context, Widget scaffold) => - GradientBackground(scaffold: scaffold); + (BuildContext context, Widget scaffold) => GradientBackground(scaffold: scaffold); @override bool get resizeToAvoidBottomInset => false; @@ -58,7 +55,7 @@ class IoniaManageCardsPage extends BasePage { @override Widget middle(BuildContext context) { return Text( - S.of(context).gift_cards, + 'Cake Pay', style: textMediumSemiBold( color: Theme.of(context).extension()!.textColor, ), @@ -68,9 +65,17 @@ class IoniaManageCardsPage extends BasePage { @override Widget trailing(BuildContext context) { return _TrailingIcon( - asset: 'assets/images/profile.png', - onPressed: () => Navigator.pushNamed(context, Routes.ioniaAccountPage), - ); + asset: 'assets/images/profile.png', + iconColor: pageIconColor(context) ?? Colors.white, + onPressed: () { + _cardsListViewModel.isCakePayUserAuthenticated().then((value) { + if (value) { + Navigator.pushNamed(context, Routes.cakePayAccountPage); + return; + } + Navigator.pushNamed(context, Routes.cakePayWelcomePage); + }); + }); } @override @@ -79,8 +84,12 @@ class IoniaManageCardsPage extends BasePage { label: S.of(context).filter_by, child: InkWell( onTap: () async { - await showCategoryFilter(context); - _cardsListViewModel.getMerchants(); + _cardsListViewModel.storeInitialFilterStates(); + await showFilterWidget(context); + if (_cardsListViewModel.hasFiltersChanged) { + _cardsListViewModel.resetLoadingNextPageState(); + _cardsListViewModel.getVendors(); + } }, child: Container( width: 32, @@ -120,7 +129,7 @@ class IoniaManageCardsPage extends BasePage { ), SizedBox(height: 8), Expanded( - child: IoniaManageCardsPageBody( + child: CakePayCardsPageBody( cardsListViewModel: _cardsListViewModel, ), ), @@ -129,36 +138,35 @@ class IoniaManageCardsPage extends BasePage { ); } - Future showCategoryFilter(BuildContext context) async { + Future showFilterWidget(BuildContext context) async { return showPopUp( context: context, builder: (BuildContext context) { - return IoniaFilterModal( - ioniaGiftCardsListViewModel: _cardsListViewModel, - ); + return FilterWidget(filterItems: _cardsListViewModel.createFilterItems); }, ); } } -class IoniaManageCardsPageBody extends StatefulWidget { - const IoniaManageCardsPageBody({ +class CakePayCardsPageBody extends StatefulWidget { + const CakePayCardsPageBody({ Key? key, required this.cardsListViewModel, }) : super(key: key); - final IoniaGiftCardsListViewModel cardsListViewModel; + final CakePayCardsListViewModel cardsListViewModel; @override - _IoniaManageCardsPageBodyState createState() => _IoniaManageCardsPageBodyState(); + _CakePayCardsPageBodyState createState() => _CakePayCardsPageBodyState(); } -class _IoniaManageCardsPageBodyState extends State { +class _CakePayCardsPageBodyState extends State { double get backgroundHeight => MediaQuery.of(context).size.height * 0.75; double thumbHeight = 72; - bool get isAlwaysShowScrollThumb => merchantsList == null ? false : merchantsList.length > 3; - List get merchantsList => widget.cardsListViewModel.ioniaMerchants; + bool get isAlwaysShowScrollThumb => merchantsList.isEmpty ? false : merchantsList.length > 3; + + List get merchantsList => widget.cardsListViewModel.cakePayVendors; final _scrollController = ScrollController(); @@ -166,61 +174,93 @@ class _IoniaManageCardsPageBodyState extends State { void initState() { _scrollController.addListener(() { final scrollOffsetFromTop = _scrollController.hasClients - ? (_scrollController.offset / _scrollController.position.maxScrollExtent * (backgroundHeight - thumbHeight)) + ? (_scrollController.offset / + _scrollController.position.maxScrollExtent * + (backgroundHeight - thumbHeight)) : 0.0; widget.cardsListViewModel.setScrollOffsetFromTop(scrollOffsetFromTop); + + double threshold = 200.0; + bool isNearBottom = + _scrollController.offset >= _scrollController.position.maxScrollExtent - threshold; + if (isNearBottom && !_scrollController.position.outOfRange) { + widget.cardsListViewModel.fetchNextPage(); + } }); super.initState(); } @override Widget build(BuildContext context) { - return Observer( - builder: (_) { - final merchantState = widget.cardsListViewModel.merchantState; - if (merchantState is IoniaLoadedMerchantState) { + return Observer(builder: (_) { + final vendorsState = widget.cardsListViewModel.vendorsState; + if (vendorsState is CakePayVendorLoadedState) { + bool isLoadingMore = widget.cardsListViewModel.isLoadingNextPage; + final vendors = widget.cardsListViewModel.cakePayVendors; + + if (vendors.isEmpty) { + return Center(child: Text(S.of(context).no_cards_found)); + } return Stack(children: [ - ListView.separated( - padding: EdgeInsets.only(left: 2, right: 22), - controller: _scrollController, - itemCount: merchantsList.length, - separatorBuilder: (_, __) => SizedBox(height: 4), - itemBuilder: (_, index) { - final merchant = merchantsList[index]; - return CardItem( - logoUrl: merchant.logoUrl, - onTap: () { - Navigator.of(context).pushNamed(Routes.ioniaBuyGiftCardPage, arguments: [merchant]); - }, - title: merchant.legalName, - subTitle: merchant.avaibilityStatus, - backgroundColor: Theme.of(context).extension()!.syncedBackgroundColor, - titleColor: Theme.of(context).extension()!.textColor, - subtitleColor: Theme.of(context).extension()!.labelTextColor, - discount: merchant.discount, - ); - }, - ), - isAlwaysShowScrollThumb - ? CakeScrollbar( - backgroundHeight: backgroundHeight, - thumbHeight: thumbHeight, - rightOffset: 1, - width: 3, - backgroundColor: Theme.of(context).extension()!.iconColor.withOpacity(0.05), - thumbColor: Theme.of(context).extension()!.iconColor.withOpacity(0.5), - fromTop: widget.cardsListViewModel.scrollOffsetFromTop, - ) - : Offstage() - ]); - } - return Center( - child: CircularProgressIndicator( - backgroundColor: Theme.of(context).extension()!.textColor, - valueColor: AlwaysStoppedAnimation(Theme.of(context).extension()!.firstGradientBottomPanelColor), + GridView.builder( + controller: _scrollController, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: responsiveLayoutUtil.shouldRenderTabletUI ? 2 : 1, + childAspectRatio: 5, + crossAxisSpacing: responsiveLayoutUtil.shouldRenderTabletUI ? 10 : 5, + mainAxisSpacing: responsiveLayoutUtil.shouldRenderTabletUI ? 10 : 5, + ), + padding: EdgeInsets.only(left: 2, right: 22), + itemCount: vendors.length + (isLoadingMore ? 1 : 0), + itemBuilder: (_, index) { + if (index >= vendors.length) { + return _VendorLoadedIndicator(); + } + final vendor = vendors[index]; + return CardItem( + logoUrl: vendor.card?.cardImageUrl, + onTap: () { + Navigator.of(context).pushNamed(Routes.cakePayBuyCardPage, arguments: [vendor]); + }, + title: vendor.name, + subTitle: vendor.card?.description ?? '', + backgroundColor: + Theme.of(context).extension()!.syncedBackgroundColor, + titleColor: Theme.of(context).extension()!.textColor, + subtitleColor: Theme.of(context).extension()!.labelTextColor, + discount: 0.0, + ); + }, ), - ); + isAlwaysShowScrollThumb + ? CakeScrollbar( + backgroundHeight: backgroundHeight, + thumbHeight: thumbHeight, + rightOffset: 1, + width: 3, + backgroundColor: + Theme.of(context).extension()!.iconColor.withOpacity(0.05), + thumbColor: + Theme.of(context).extension()!.iconColor.withOpacity(0.5), + fromTop: widget.cardsListViewModel.scrollOffsetFromTop, + ) + : Offstage() + ]); } + return _VendorLoadedIndicator(); + }); + } +} + +class _VendorLoadedIndicator extends StatelessWidget { + @override + Widget build(BuildContext context) { + return Center( + child: CircularProgressIndicator( + backgroundColor: Theme.of(context).extension()!.textColor, + valueColor: AlwaysStoppedAnimation( + Theme.of(context).extension()!.firstGradientBottomPanelColor), + ), ); } } @@ -233,6 +273,7 @@ class _SearchWidget extends StatelessWidget { }) : super(key: key); final TextEditingController controller; final FocusNode focusNode; + @override Widget build(BuildContext context) { final searchIcon = ExcludeSemantics( @@ -284,30 +325,25 @@ class _SearchWidget extends StatelessWidget { } class _TrailingIcon extends StatelessWidget { - const _TrailingIcon({required this.asset, this.onPressed}); + const _TrailingIcon({required this.asset, this.onPressed, required this.iconColor}); final String asset; final VoidCallback? onPressed; + final Color iconColor; @override Widget build(BuildContext context) { return Semantics( - label: S.of(context).profile, - child: Material( - color: Colors.transparent, - child: IconButton( - padding: EdgeInsets.zero, - constraints: BoxConstraints(), - highlightColor: Colors.transparent, - splashColor: Colors.transparent, - iconSize: 25, - onPressed: onPressed, - icon: Image.asset( - asset, - color: Theme.of(context).extension()!.textColor, + label: S.of(context).profile, + child: Material( + color: Colors.transparent, + child: IconButton( + padding: EdgeInsets.zero, + constraints: BoxConstraints(), + highlightColor: Colors.transparent, + onPressed: onPressed, + icon: ImageIcon(AssetImage(asset), size: 25, color: iconColor), ), - ), - ), - ); + )); } } diff --git a/lib/src/screens/cake_pay/cards/cake_pay_confirm_purchase_card_page.dart b/lib/src/screens/cake_pay/cards/cake_pay_confirm_purchase_card_page.dart new file mode 100644 index 000000000..15aa576c8 --- /dev/null +++ b/lib/src/screens/cake_pay/cards/cake_pay_confirm_purchase_card_page.dart @@ -0,0 +1,403 @@ +import 'package:cake_wallet/core/execution_state.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_card.dart'; +import 'package:cake_wallet/routes.dart'; +import 'package:cake_wallet/src/screens/base_page.dart'; +import 'package:cake_wallet/src/screens/cake_pay/widgets/cake_pay_alert_modal.dart'; +import 'package:cake_wallet/src/screens/cake_pay/widgets/image_placeholder.dart'; +import 'package:cake_wallet/src/screens/cake_pay/widgets/link_extractor.dart'; +import 'package:cake_wallet/src/screens/cake_pay/widgets/text_icon_button.dart'; +import 'package:cake_wallet/src/screens/send/widgets/confirm_sending_alert.dart'; +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; +import 'package:cake_wallet/src/widgets/primary_button.dart'; +import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; +import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; +import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart'; +import 'package:cake_wallet/themes/extensions/picker_theme.dart'; +import 'package:cake_wallet/themes/extensions/receive_page_theme.dart'; +import 'package:cake_wallet/themes/extensions/send_page_theme.dart'; +import 'package:cake_wallet/typography.dart'; +import 'package:cake_wallet/utils/show_pop_up.dart'; +import 'package:cake_wallet/view_model/cake_pay/cake_pay_purchase_view_model.dart'; +import 'package:cake_wallet/view_model/send/send_view_model_state.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_mobx/flutter_mobx.dart'; +import 'package:mobx/mobx.dart'; + +class CakePayBuyCardDetailPage extends BasePage { + CakePayBuyCardDetailPage(this.cakePayPurchaseViewModel); + + final CakePayPurchaseViewModel cakePayPurchaseViewModel; + + @override + String get title => cakePayPurchaseViewModel.card.name; + + @override + Widget? middle(BuildContext context) { + return Text( + title, + textAlign: TextAlign.center, + maxLines: 2, + style: TextStyle( + fontSize: 18.0, + fontWeight: FontWeight.bold, + fontFamily: 'Lato', + color: titleColor(context)), + ); + } + + @override + Widget? trailing(BuildContext context) => null; + + bool _effectsInstalled = false; + + @override + Widget body(BuildContext context) { + _setEffects(context); + + final card = cakePayPurchaseViewModel.card; + + return ScrollableWithBottomSection( + contentPadding: EdgeInsets.zero, + content: Observer(builder: (_) { + return Column( + children: [ + SizedBox(height: 36), + ClipRRect( + borderRadius: + BorderRadius.horizontal(left: Radius.circular(20), right: Radius.circular(20)), + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).extension()!.searchBackgroundFillColor, + borderRadius: BorderRadius.circular(20), + border: Border.all(color: Colors.white.withOpacity(0.20)), + ), + child: Row( + children: [ + Expanded( + child: Container( + child: ClipRRect( + borderRadius: BorderRadius.horizontal( + left: Radius.circular(20), right: Radius.circular(20)), + child: Image.network( + card.cardImageUrl ?? '', + fit: BoxFit.cover, + loadingBuilder: (BuildContext context, Widget child, + ImageChunkEvent? loadingProgress) { + if (loadingProgress == null) return child; + return Center(child: CircularProgressIndicator()); + }, + errorBuilder: (context, error, stackTrace) => + CakePayCardImagePlaceholder(), + ), + )), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: Column(children: [ + Row( + children: [ + Text( + S.of(context).value + ':', + style: textLarge( + color: + Theme.of(context).extension()!.titleColor), + ), + SizedBox(width: 8), + Text( + '${cakePayPurchaseViewModel.amount.toStringAsFixed(2)} ${cakePayPurchaseViewModel.fiatCurrency}', + style: textLarge( + color: + Theme.of(context).extension()!.titleColor), + ), + ], + ), + SizedBox(height: 16), + Row( + children: [ + Text( + S.of(context).quantity + ':', + style: textLarge( + color: + Theme.of(context).extension()!.titleColor), + ), + SizedBox(width: 8), + Text( + '${cakePayPurchaseViewModel.quantity}', + style: textLarge( + color: + Theme.of(context).extension()!.titleColor), + ), + ], + ), + SizedBox(height: 16), + Row( + children: [ + Text( + S.of(context).total + ':', + style: textLarge( + color: + Theme.of(context).extension()!.titleColor), + ), + SizedBox(width: 8), + Text( + '${cakePayPurchaseViewModel.totalAmount.toStringAsFixed(2)} ${cakePayPurchaseViewModel.fiatCurrency}', + style: textLarge( + color: + Theme.of(context).extension()!.titleColor), + ), + ], + ), + ]), + ), + ) + ], + ), + ), + ), + SizedBox(height: 20), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 24.0), + child: TextIconButton( + label: S.of(context).how_to_use_card, + onTap: () => _showHowToUseCard(context, card), + ), + ), + SizedBox(height: 20), + if (card.expiryAndValidity != null && card.expiryAndValidity!.isNotEmpty) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 24.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(S.of(context).expiry_and_validity + ':', + style: textMediumSemiBold( + color: Theme.of(context).extension()!.titleColor)), + SizedBox(height: 10), + Container( + width: double.infinity, + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + color: Theme.of(context).extension()!.secondaryTextColor, + width: 1, + ), + ), + ), + child: Padding( + padding: const EdgeInsets.only(bottom: 8.0), + child: Text( + card.expiryAndValidity ?? '', + style: textMedium( + color: Theme.of(context).extension()!.secondaryTextColor, + ), + ), + ), + ), + ], + ), + ), + ], + ); + }), + bottomSection: Column( + children: [ + Padding( + padding: EdgeInsets.only(bottom: 12), + child: Observer(builder: (_) { + return LoadingPrimaryButton( + isLoading: cakePayPurchaseViewModel.sendViewModel.state is IsExecutingState, + onPressed: () => purchaseCard(context), + text: S.of(context).purchase_gift_card, + color: Theme.of(context).primaryColor, + textColor: Colors.white, + ); + }), + ), + SizedBox(height: 8), + InkWell( + onTap: () => _showTermsAndCondition(context, card.termsAndConditions), + child: Text(S.of(context).settings_terms_and_conditions, + style: textMediumSemiBold( + color: Theme.of(context).primaryColor, + ).copyWith(fontSize: 12)), + ), + SizedBox(height: 16) + ], + ), + ); + } + + void _showTermsAndCondition(BuildContext context, String? termsAndConditions) { + showPopUp( + context: context, + builder: (BuildContext context) { + return CakePayAlertModal( + title: S.of(context).settings_terms_and_conditions, + content: Align( + alignment: Alignment.bottomLeft, + child: ClickableLinksText( + text: termsAndConditions ?? '', + textStyle: TextStyle( + color: Theme.of(context).extension()!.secondaryTextColor, + fontSize: 18, + fontWeight: FontWeight.w400, + ), + ), + ), + actionTitle: S.of(context).agree, + showCloseButton: false, + heightFactor: 0.6, + ); + }); + } + + Future purchaseCard(BuildContext context) async { + bool isLogged = await cakePayPurchaseViewModel.cakePayService.isLogged(); + if (!isLogged) { + Navigator.of(context).pushNamed(Routes.cakePayWelcomePage); + } else { + await cakePayPurchaseViewModel.createOrder(); + } + } + + void _showHowToUseCard( + BuildContext context, + CakePayCard card, + ) { + showPopUp( + context: context, + builder: (BuildContext context) { + return CakePayAlertModal( + title: S.of(context).how_to_use_card, + content: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Padding( + padding: EdgeInsets.all(10), + child: Text( + card.name, + style: textLargeSemiBold( + color: Theme.of(context).extension()!.tilesTextColor, + ), + )), + ClickableLinksText( + text: card.howToUse ?? '', + textStyle: TextStyle( + color: Theme.of(context).extension()!.secondaryTextColor, + fontSize: 18, + fontWeight: FontWeight.w400, + ), + linkStyle: TextStyle( + color: Theme.of(context).extension()!.titleColor, + fontSize: 18, + fontStyle: FontStyle.italic, + fontWeight: FontWeight.w400, + ), + ), + ]), + actionTitle: S.current.got_it, + ); + }); + } + + Future _showConfirmSendingAlert(BuildContext context) async { + if (cakePayPurchaseViewModel.order == null) { + return; + } + ReactionDisposer? disposer; + + disposer = reaction((_) => cakePayPurchaseViewModel.isOrderExpired, (bool isExpired) { + if (isExpired) { + if (Navigator.of(context).canPop()) { + Navigator.of(context).pop(); + } + if (disposer != null) { + disposer(); + } + } + }); + + final order = cakePayPurchaseViewModel.order; + final pendingTransaction = cakePayPurchaseViewModel.sendViewModel.pendingTransaction!; + + await showPopUp( + context: context, + builder: (_) { + return Observer( + builder: (_) => ConfirmSendingAlert( + alertTitle: S.of(context).confirm_sending, + paymentId: S.of(context).payment_id, + paymentIdValue: order?.orderId, + expirationTime: cakePayPurchaseViewModel.formattedRemainingTime, + onDispose: () => _handleDispose(disposer), + amount: S.of(context).send_amount, + amountValue: pendingTransaction.amountFormatted, + fiatAmountValue: + cakePayPurchaseViewModel.sendViewModel.pendingTransactionFiatAmountFormatted, + fee: S.of(context).send_fee, + feeValue: pendingTransaction.feeFormatted, + feeFiatAmount: + cakePayPurchaseViewModel.sendViewModel.pendingTransactionFeeFiatAmountFormatted, + feeRate: pendingTransaction.feeRate, + outputs: cakePayPurchaseViewModel.sendViewModel.outputs, + rightButtonText: S.of(context).send, + leftButtonText: S.of(context).cancel, + actionRightButton: () async { + Navigator.of(context).pop(); + await cakePayPurchaseViewModel.sendViewModel.commitTransaction(); + }, + actionLeftButton: () => Navigator.of(context).pop())); + }, + ); + } + + void _setEffects(BuildContext context) { + if (_effectsInstalled) { + return; + } + + reaction((_) => cakePayPurchaseViewModel.sendViewModel.state, (ExecutionState state) { + if (state is FailureState) { + WidgetsBinding.instance.addPostFrameCallback((_) { + showStateAlert(context, S.of(context).error, state.error); + }); + } + + if (state is ExecutedSuccessfullyState) { + WidgetsBinding.instance.addPostFrameCallback((_) async { + await _showConfirmSendingAlert(context); + }); + } + + if (state is TransactionCommitted) { + WidgetsBinding.instance.addPostFrameCallback((_) { + cakePayPurchaseViewModel.sendViewModel.clearOutputs(); + if (context.mounted) { + showStateAlert(context, S.of(context).sending, S.of(context).transaction_sent); + } + }); + } + }); + + _effectsInstalled = true; + } + + void showStateAlert(BuildContext context, String title, String content) { + showPopUp( + context: context, + builder: (BuildContext context) { + return AlertWithOneAction( + alertTitle: title, + alertContent: content, + buttonText: S.of(context).ok, + buttonAction: () => Navigator.of(context).pop()); + }); + } + + void _handleDispose(ReactionDisposer? disposer) { + cakePayPurchaseViewModel.dispose(); + if (disposer != null) { + disposer(); + } + } +} diff --git a/lib/src/screens/ionia/widgets/ionia_alert_model.dart b/lib/src/screens/cake_pay/widgets/cake_pay_alert_modal.dart similarity index 97% rename from lib/src/screens/ionia/widgets/ionia_alert_model.dart rename to lib/src/screens/cake_pay/widgets/cake_pay_alert_modal.dart index 57a93a127..742ba1486 100644 --- a/lib/src/screens/ionia/widgets/ionia_alert_model.dart +++ b/lib/src/screens/cake_pay/widgets/cake_pay_alert_modal.dart @@ -5,8 +5,8 @@ import 'package:cake_wallet/themes/extensions/cake_scrollbar_theme.dart'; import 'package:cake_wallet/typography.dart'; import 'package:flutter/material.dart'; -class IoniaAlertModal extends StatelessWidget { - const IoniaAlertModal({ +class CakePayAlertModal extends StatelessWidget { + const CakePayAlertModal({ Key? key, required this.title, required this.content, diff --git a/lib/src/screens/ionia/widgets/ionia_tile.dart b/lib/src/screens/cake_pay/widgets/cake_pay_tile.dart similarity index 94% rename from lib/src/screens/ionia/widgets/ionia_tile.dart rename to lib/src/screens/cake_pay/widgets/cake_pay_tile.dart index 932674451..a26786ab2 100644 --- a/lib/src/screens/ionia/widgets/ionia_tile.dart +++ b/lib/src/screens/cake_pay/widgets/cake_pay_tile.dart @@ -3,8 +3,8 @@ import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; import 'package:flutter/material.dart'; import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart'; -class IoniaTile extends StatelessWidget { - const IoniaTile({ +class CakePayTile extends StatelessWidget { + const CakePayTile({ Key? key, required this.title, required this.subTitle, diff --git a/lib/src/screens/cake_pay/widgets/card_item.dart b/lib/src/screens/cake_pay/widgets/card_item.dart new file mode 100644 index 000000000..ce804adc2 --- /dev/null +++ b/lib/src/screens/cake_pay/widgets/card_item.dart @@ -0,0 +1,104 @@ +import 'package:flutter/material.dart'; + +import 'image_placeholder.dart'; + +class CardItem extends StatelessWidget { + CardItem({ + required this.title, + required this.subTitle, + required this.backgroundColor, + required this.titleColor, + required this.subtitleColor, + this.hideBorder = false, + this.discount = 0.0, + this.isAmount = false, + this.discountBackground, + this.onTap, + this.logoUrl, + }); + + final VoidCallback? onTap; + final String title; + final String subTitle; + final String? logoUrl; + final double discount; + final bool isAmount; + final bool hideBorder; + final Color backgroundColor; + final Color titleColor; + final Color subtitleColor; + final AssetImage? discountBackground; + + @override + Widget build(BuildContext context) { + return Theme( + data: ThemeData( + splashColor: Colors.transparent, + highlightColor: Colors.transparent, + ), + child: InkWell( + onTap: onTap, + child: Container( + decoration: BoxDecoration( + color: backgroundColor, + borderRadius: BorderRadius.circular(10), + border: hideBorder + ? Border.all(color: Colors.transparent) + : Border.all(color: Colors.white.withOpacity(0.20)), + ), + child: Row( + children: [ + if (logoUrl != null) + AspectRatio( + aspectRatio: 1.8, + child: ClipRRect( + borderRadius: BorderRadius.all(Radius.circular(10)), + child: Image.network( + logoUrl!, + fit: BoxFit.cover, + loadingBuilder: + (BuildContext context, Widget child, ImageChunkEvent? loadingProgress) { + if (loadingProgress == null) return child; + return Center(child: CircularProgressIndicator()); + }, + errorBuilder: (context, error, stackTrace) => CakePayCardImagePlaceholder(), + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + title, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: titleColor, + fontSize: 18, + fontWeight: FontWeight.w700, + ), + ), + Text( + subTitle, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: TextStyle( + color: titleColor, + fontSize: 10, + fontWeight: FontWeight.w700, + ), + ), + ], + ), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/src/screens/ionia/widgets/card_menu.dart b/lib/src/screens/cake_pay/widgets/card_menu.dart similarity index 100% rename from lib/src/screens/ionia/widgets/card_menu.dart rename to lib/src/screens/cake_pay/widgets/card_menu.dart diff --git a/lib/src/screens/cake_pay/widgets/image_placeholder.dart b/lib/src/screens/cake_pay/widgets/image_placeholder.dart new file mode 100644 index 000000000..e389bab07 --- /dev/null +++ b/lib/src/screens/cake_pay/widgets/image_placeholder.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; + +class CakePayCardImagePlaceholder extends StatelessWidget { + const CakePayCardImagePlaceholder({this.text}); + + final String? text; + + @override + Widget build(BuildContext context) { + return AspectRatio( + aspectRatio: 1.8, + child: Container( + child: Center( + child: Text( + text ?? 'Image not found!', + style: TextStyle( + color: Colors.black, + fontSize: 12, + fontWeight: FontWeight.w900, + ), + ), + ), + decoration: BoxDecoration( + color: Colors.white, + ), + ), + ); + } +} diff --git a/lib/src/screens/cake_pay/widgets/link_extractor.dart b/lib/src/screens/cake_pay/widgets/link_extractor.dart new file mode 100644 index 000000000..43b4a3e52 --- /dev/null +++ b/lib/src/screens/cake_pay/widgets/link_extractor.dart @@ -0,0 +1,66 @@ +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class ClickableLinksText extends StatelessWidget { + const ClickableLinksText({ + required this.text, + required this.textStyle, + this.linkStyle, + }); + + final String text; + final TextStyle textStyle; + final TextStyle? linkStyle; + + @override + Widget build(BuildContext context) { + List spans = []; + RegExp linkRegExp = RegExp(r'(https?://[^\s]+)'); + Iterable matches = linkRegExp.allMatches(text); + + int previousEnd = 0; + matches.forEach((match) { + if (match.start > previousEnd) { + spans.add(TextSpan(text: text.substring(previousEnd, match.start), style: textStyle)); + } + String url = text.substring(match.start, match.end); + if (url.toLowerCase().endsWith('.md')) { + spans.add( + TextSpan( + text: url, + style: TextStyle( + color: Colors.blue, + fontSize: 18, + fontWeight: FontWeight.w400, + ), + recognizer: TapGestureRecognizer() + ..onTap = () async { + if (await canLaunchUrl(Uri.parse(url))) { + await launchUrl(Uri.parse(url), mode: LaunchMode.externalApplication); + } + }, + ), + ); + } else { + spans.add( + TextSpan( + text: url, + style: linkStyle, + recognizer: TapGestureRecognizer() + ..onTap = () { + launchUrl(Uri.parse(url)); + }, + ), + ); + } + previousEnd = match.end; + }); + + if (previousEnd < text.length) { + spans.add(TextSpan(text: text.substring(previousEnd), style: textStyle)); + } + + return RichText(text: TextSpan(children: spans)); + } +} diff --git a/lib/src/screens/ionia/widgets/rounded_checkbox.dart b/lib/src/screens/cake_pay/widgets/rounded_checkbox.dart similarity index 100% rename from lib/src/screens/ionia/widgets/rounded_checkbox.dart rename to lib/src/screens/cake_pay/widgets/rounded_checkbox.dart diff --git a/lib/src/screens/ionia/widgets/text_icon_button.dart b/lib/src/screens/cake_pay/widgets/text_icon_button.dart similarity index 100% rename from lib/src/screens/ionia/widgets/text_icon_button.dart rename to lib/src/screens/cake_pay/widgets/text_icon_button.dart diff --git a/lib/src/screens/dashboard/pages/cake_features_page.dart b/lib/src/screens/dashboard/pages/cake_features_page.dart index 9ccb7833c..b034fb799 100644 --- a/lib/src/screens/dashboard/pages/cake_features_page.dart +++ b/lib/src/screens/dashboard/pages/cake_features_page.dart @@ -1,17 +1,18 @@ +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/routes.dart'; +import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/dashboard_card_widget.dart'; +import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart'; +import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; +import 'package:cw_core/wallet_type.dart'; import 'package:cake_wallet/view_model/dashboard/cake_features_view_model.dart'; import 'package:flutter/material.dart'; -import 'package:cake_wallet/generated/i18n.dart'; import 'package:url_launcher/url_launcher.dart'; -import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart'; import 'package:flutter_svg/flutter_svg.dart'; class CakeFeaturesPage extends StatelessWidget { - CakeFeaturesPage({ - required this.dashboardViewModel, - required this.cakeFeaturesViewModel, - }); + CakeFeaturesPage({required this.dashboardViewModel, required this.cakeFeaturesViewModel}); final DashboardViewModel dashboardViewModel; final CakeFeaturesViewModel cakeFeaturesViewModel; @@ -45,20 +46,11 @@ class CakeFeaturesPage extends StatelessWidget { child: ListView( controller: _scrollController, children: [ - // SizedBox(height: 20), - // DashBoardRoundedCardWidget( - // onTap: () => launchUrl( - // Uri.parse("https://cakelabs.com/news/cake-pay-mobile-to-shut-down/"), - // mode: LaunchMode.externalApplication, - // ), - // title: S.of(context).cake_pay_title, - // subTitle: S.of(context).cake_pay_subtitle, - // ), SizedBox(height: 20), DashBoardRoundedCardWidget( - onTap: () => _launchUrl("buy.cakepay.com"), - title: S.of(context).cake_pay_web_cards_title, - subTitle: S.of(context).cake_pay_web_cards_subtitle, + onTap: () => _navigatorToGiftCardsPage(context), + title: 'Cake Pay', + subTitle: S.of(context).cake_pay_subtitle, svgPicture: SvgPicture.asset( 'assets/images/cards.svg', height: 125, @@ -88,6 +80,28 @@ class CakeFeaturesPage extends StatelessWidget { Uri.https(url), mode: LaunchMode.externalApplication, ); - } catch (_) {} + } catch (e) { + print(e); + } + } + + void _navigatorToGiftCardsPage(BuildContext context) { + final walletType = dashboardViewModel.type; + + switch (walletType) { + case WalletType.haven: + showPopUp( + context: context, + builder: (BuildContext context) { + return AlertWithOneAction( + alertTitle: S.of(context).error, + alertContent: S.of(context).gift_cards_unavailable, + buttonText: S.of(context).ok, + buttonAction: () => Navigator.of(context).pop()); + }); + break; + default: + Navigator.pushNamed(context, Routes.cakePayCardsPage); + } } } diff --git a/lib/src/screens/dashboard/widgets/filter_widget.dart b/lib/src/screens/dashboard/widgets/filter_widget.dart index ec867ae49..eaf00a1de 100644 --- a/lib/src/screens/dashboard/widgets/filter_widget.dart +++ b/lib/src/screens/dashboard/widgets/filter_widget.dart @@ -3,18 +3,21 @@ import 'package:cake_wallet/src/screens/dashboard/widgets/filter_tile.dart'; import 'package:cake_wallet/src/widgets/section_divider.dart'; import 'package:cake_wallet/src/widgets/standard_checkbox.dart'; import 'package:cake_wallet/themes/extensions/menu_theme.dart'; -import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart'; +import 'package:cake_wallet/view_model/dashboard/dropdown_filter_item.dart'; +import 'package:cake_wallet/view_model/dashboard/dropdown_filter_item_widget.dart'; +import 'package:cake_wallet/view_model/dashboard/filter_item.dart'; import 'package:flutter/material.dart'; import 'package:cake_wallet/src/widgets/picker_wrapper_widget.dart'; import 'package:cake_wallet/generated/i18n.dart'; import 'package:flutter_mobx/flutter_mobx.dart'; + //import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker; import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart'; class FilterWidget extends StatelessWidget { - FilterWidget({required this.dashboardViewModel}); + FilterWidget({required this.filterItems}); - final DashboardViewModel dashboardViewModel; + final Map> filterItems; @override Widget build(BuildContext context) { @@ -27,75 +30,90 @@ class FilterWidget extends StatelessWidget { borderRadius: BorderRadius.all(Radius.circular(24)), child: Container( color: Theme.of(context).extension()!.backgroundColor, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.all(24.0), - child: Text( - S.of(context).filter_by, - style: TextStyle( - color: Theme.of(context).extension()!.detailsTitlesColor, - fontSize: 16, - fontFamily: 'Lato', - decoration: TextDecoration.none, + child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Padding( + padding: EdgeInsets.all(24.0), + child: Text( + S.of(context).filter_by, + style: TextStyle( + color: + Theme.of(context).extension()!.detailsTitlesColor, + fontSize: 16, + fontFamily: 'Lato', + decoration: TextDecoration.none, + ), + ), + ), + sectionDivider, + ListView.separated( + padding: EdgeInsets.zero, + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: filterItems.length, + separatorBuilder: (context, _) => sectionDivider, + itemBuilder: (_, index1) { + final title = filterItems.keys.elementAt(index1); + final section = filterItems.values.elementAt(index1); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: EdgeInsets.only(top: 20, left: 24, right: 24), + child: Text( + title, + style: TextStyle( + color: Theme.of(context).extension()!.titleColor, + fontSize: 16, + fontFamily: 'Lato', + fontWeight: FontWeight.bold, + decoration: TextDecoration.none), + ), ), - ), - ), - sectionDivider, - ListView.separated( - padding: EdgeInsets.zero, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: dashboardViewModel.filterItems.length, - separatorBuilder: (context, _) => sectionDivider, - itemBuilder: (_, index1) { - final title = dashboardViewModel.filterItems.keys - .elementAt(index1); - final section = dashboardViewModel.filterItems.values - .elementAt(index1); - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: - EdgeInsets.only(top: 20, left: 24, right: 24), - child: Text( - title, - style: TextStyle( - color: Theme.of(context).extension()!.titleColor, - fontSize: 16, - fontFamily: 'Lato', - fontWeight: FontWeight.bold, - decoration: TextDecoration.none), - ), - ), - ListView.builder( - padding: EdgeInsets.symmetric(vertical: 8.0), - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: section.length, - itemBuilder: (_, index2) { - final item = section[index2]; - final content = Observer( - builder: (_) => StandardCheckbox( - value: item.value(), - caption: item.caption, - gradientBackground: true, - borderColor: - Theme.of(context).dividerColor, - iconColor: Colors.white, - onChanged: (value) => - item.onChanged(), - )); - return FilterTile(child: content); - }, - ) - ], - ); - }, - ), - ]), + ListView.builder( + padding: EdgeInsets.symmetric(horizontal: 28.0), + shrinkWrap: true, + physics: const NeverScrollableScrollPhysics(), + itemCount: section.length, + itemBuilder: (_, index2) { + final item = section[index2]; + + if (item is DropdownFilterItem) { + return Padding( + padding: EdgeInsets.fromLTRB(8, 0, 8, 16), + child: Container( + decoration: BoxDecoration( + border: Border( + bottom: BorderSide( + width: 1.0, + color: Theme.of(context).extension()!.secondaryTextColor), + ), + ), + child: DropdownFilterList( + items: item.items, + caption: item.caption, + selectedItem: item.selectedItem, + onItemSelected: item.onItemSelected, + ), + ), + ); + } + final content = Observer( + builder: (_) => StandardCheckbox( + value: item.value(), + caption: item.caption, + gradientBackground: true, + borderColor: Theme.of(context).dividerColor, + iconColor: Colors.white, + onChanged: (value) => item.onChanged(), + )); + return FilterTile(child: content); + }, + ) + ], + ); + }, + ), + ]), ), ), ) diff --git a/lib/src/screens/dashboard/widgets/header_row.dart b/lib/src/screens/dashboard/widgets/header_row.dart index 2093a238f..cb4f67fc2 100644 --- a/lib/src/screens/dashboard/widgets/header_row.dart +++ b/lib/src/screens/dashboard/widgets/header_row.dart @@ -37,7 +37,7 @@ class HeaderRow extends StatelessWidget { onTap: () { showPopUp( context: context, - builder: (context) => FilterWidget(dashboardViewModel: dashboardViewModel), + builder: (context) => FilterWidget(filterItems: dashboardViewModel.filterItems), ); }, child: Semantics( diff --git a/lib/src/screens/dashboard/widgets/present_receive_option_picker.dart b/lib/src/screens/dashboard/widgets/present_receive_option_picker.dart index bebb58107..3abcbbfeb 100644 --- a/lib/src/screens/dashboard/widgets/present_receive_option_picker.dart +++ b/lib/src/screens/dashboard/widgets/present_receive_option_picker.dart @@ -1,6 +1,6 @@ import 'package:cake_wallet/src/widgets/alert_close_button.dart'; import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; -import 'package:cake_wallet/src/screens/ionia/widgets/rounded_checkbox.dart'; +import 'package:cake_wallet/src/screens/cake_pay/widgets/rounded_checkbox.dart'; import 'package:cake_wallet/src/widgets/alert_background.dart'; import 'package:cake_wallet/typography.dart'; import 'package:cake_wallet/utils/show_pop_up.dart'; diff --git a/lib/src/screens/ionia/auth/ionia_create_account_page.dart b/lib/src/screens/ionia/auth/ionia_create_account_page.dart deleted file mode 100644 index e6dc83c3c..000000000 --- a/lib/src/screens/ionia/auth/ionia_create_account_page.dart +++ /dev/null @@ -1,159 +0,0 @@ -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; -import 'package:cake_wallet/core/email_validator.dart'; -import 'package:cake_wallet/ionia/ionia_create_state.dart'; -import 'package:cake_wallet/routes.dart'; -import 'package:cake_wallet/src/screens/base_page.dart'; -import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; -import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; -import 'package:cake_wallet/src/widgets/primary_button.dart'; -import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; -import 'package:cake_wallet/typography.dart'; -import 'package:cake_wallet/utils/show_pop_up.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_auth_view_model.dart'; -import 'package:flutter/gestures.dart'; -import 'package:flutter/material.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:mobx/mobx.dart'; -import 'package:url_launcher/url_launcher.dart'; - -class IoniaCreateAccountPage extends BasePage { - IoniaCreateAccountPage(this._authViewModel) - : _emailFocus = FocusNode(), - _emailController = TextEditingController(), - _formKey = GlobalKey() { - _emailController.text = _authViewModel.email; - _emailController.addListener(() => _authViewModel.email = _emailController.text); - } - - final IoniaAuthViewModel _authViewModel; - - final GlobalKey _formKey; - - final FocusNode _emailFocus; - final TextEditingController _emailController; - - static const privacyPolicyUrl = 'https://ionia.docsend.com/view/jhjvdn7qq7k3ukwt'; - static const termsAndConditionsUrl = 'https://ionia.docsend.com/view/uceirymz2ijacq5g'; - - @override - Widget middle(BuildContext context) { - return Text( - S.current.sign_up, - style: textMediumSemiBold( - color: Theme.of(context).extension()!.titleColor, - ), - ); - } - - @override - Widget body(BuildContext context) { - reaction((_) => _authViewModel.createUserState, (IoniaCreateAccountState state) { - if (state is IoniaCreateStateFailure) { - _onCreateUserFailure(context, state.error); - } - if (state is IoniaCreateStateSuccess) { - _onCreateSuccessful(context, _authViewModel); - } - }); - - return ScrollableWithBottomSection( - contentPadding: EdgeInsets.all(24), - content: Form( - key: _formKey, - child: BaseTextFormField( - hintText: S.of(context).email_address, - focusNode: _emailFocus, - validator: EmailValidator(), - keyboardType: TextInputType.emailAddress, - controller: _emailController, - onSubmit: (_) => _createAccount(), - ), - ), - bottomSectionPadding: EdgeInsets.symmetric(vertical: 36, horizontal: 24), - bottomSection: Column( - children: [ - Column( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Observer( - builder: (_) => LoadingPrimaryButton( - text: S.of(context).create_account, - onPressed: _createAccount, - isLoading: - _authViewModel.createUserState is IoniaCreateStateLoading, - color: Theme.of(context).primaryColor, - textColor: Colors.white, - ), - ), - SizedBox( - height: 20, - ), - RichText( - textAlign: TextAlign.center, - text: TextSpan( - text: S.of(context).agree_to, - style: TextStyle( - color: Color(0xff7A93BA), - fontSize: 12, - fontFamily: 'Lato', - ), - children: [ - TextSpan( - text: S.of(context).settings_terms_and_conditions, - style: TextStyle( - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.w700, - ), - recognizer: TapGestureRecognizer() - ..onTap = () async { - if (await canLaunch(termsAndConditionsUrl)) await launch(termsAndConditionsUrl); - }, - ), - TextSpan(text: ' ${S.of(context).and} '), - TextSpan( - text: S.of(context).privacy_policy, - style: TextStyle( - color: Theme.of(context).primaryColor, - fontWeight: FontWeight.w700, - ), - recognizer: TapGestureRecognizer() - ..onTap = () async { - if (await canLaunch(privacyPolicyUrl)) await launch(privacyPolicyUrl); - }), - TextSpan(text: ' ${S.of(context).by_cake_pay}'), - ], - ), - ), - ], - ), - ], - ), - ); - } - - void _onCreateUserFailure(BuildContext context, String error) { - showPopUp( - context: context, - builder: (BuildContext context) { - return AlertWithOneAction( - alertTitle: S.current.create_account, - alertContent: error, - buttonText: S.of(context).ok, - buttonAction: () => Navigator.of(context).pop()); - }); - } - - void _onCreateSuccessful(BuildContext context, IoniaAuthViewModel authViewModel) => Navigator.pushNamed( - context, - Routes.ioniaVerifyIoniaOtpPage, - arguments: [authViewModel.email, false], - ); - - void _createAccount() async { - if (_formKey.currentState != null && !_formKey.currentState!.validate()) { - return; - } - await _authViewModel.createUser(_emailController.text); - } -} diff --git a/lib/src/screens/ionia/auth/ionia_welcome_page.dart b/lib/src/screens/ionia/auth/ionia_welcome_page.dart deleted file mode 100644 index e44e3a26d..000000000 --- a/lib/src/screens/ionia/auth/ionia_welcome_page.dart +++ /dev/null @@ -1,95 +0,0 @@ -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; -import 'package:cake_wallet/palette.dart'; -import 'package:cake_wallet/routes.dart'; -import 'package:cake_wallet/src/screens/base_page.dart'; -import 'package:cake_wallet/src/widgets/primary_button.dart'; -import 'package:cake_wallet/typography.dart'; -import 'package:flutter/material.dart'; -import 'package:cake_wallet/generated/i18n.dart'; - -class IoniaWelcomePage extends BasePage { - IoniaWelcomePage(); - - @override - Widget middle(BuildContext context) { - return Text( - S.current.welcome_to_cakepay, - style: textMediumSemiBold( - color: Theme.of(context).extension()!.titleColor, - ), - ); - } - - @override - Widget body(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(24.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - children: [ - SizedBox(height: 90), - Text( - S.of(context).about_cake_pay, - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w400, - fontFamily: 'Lato', - color: Theme.of(context).extension()!.titleColor, - ), - ), - SizedBox(height: 20), - Text( - S.of(context).cake_pay_account_note, - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w400, - fontFamily: 'Lato', - color: Theme.of(context).extension()!.titleColor, - ), - ), - ], - ), - Column( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - PrimaryButton( - text: S.of(context).create_account, - onPressed: () => Navigator.of(context).pushNamed(Routes.ioniaCreateAccountPage), - color: Theme.of(context).primaryColor, - textColor: Colors.white, - ), - SizedBox( - height: 16, - ), - Text( - S.of(context).already_have_account, - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.w500, - fontFamily: 'Lato', - color: Theme.of(context).extension()!.titleColor, - ), - ), - SizedBox(height: 8), - InkWell( - onTap: () => Navigator.of(context).pushNamed(Routes.ioniaLoginPage), - child: Text( - S.of(context).login, - style: TextStyle( - color: Palette.blueCraiola, - fontSize: 18, - letterSpacing: 1.5, - fontWeight: FontWeight.w900, - ), - ), - ), - SizedBox(height: 20) - ], - ) - ], - ), - ); - } -} diff --git a/lib/src/screens/ionia/cards/ionia_account_cards_page.dart b/lib/src/screens/ionia/cards/ionia_account_cards_page.dart deleted file mode 100644 index b96249b69..000000000 --- a/lib/src/screens/ionia/cards/ionia_account_cards_page.dart +++ /dev/null @@ -1,204 +0,0 @@ - -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; -import 'package:cake_wallet/ionia/ionia_create_state.dart'; -import 'package:cake_wallet/ionia/ionia_gift_card.dart'; -import 'package:cake_wallet/routes.dart'; -import 'package:cake_wallet/src/screens/base_page.dart'; -import 'package:cake_wallet/src/screens/ionia/widgets/card_item.dart'; -import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart'; -import 'package:cake_wallet/themes/extensions/order_theme.dart'; -import 'package:cake_wallet/typography.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_account_view_model.dart'; -import 'package:flutter/material.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart'; -import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart'; - -class IoniaAccountCardsPage extends BasePage { - IoniaAccountCardsPage(this.ioniaAccountViewModel); - - final IoniaAccountViewModel ioniaAccountViewModel; - - @override - Widget middle(BuildContext context) { - return Text( - S.of(context).cards, - style: textLargeSemiBold( - color: Theme.of(context).extension()!.titleColor, - ), - ); - } - - @override - Widget body(BuildContext context) { - return _IoniaCardTabs(ioniaAccountViewModel); - } -} - -class _IoniaCardTabs extends StatefulWidget { - _IoniaCardTabs(this.ioniaAccountViewModel); - - final IoniaAccountViewModel ioniaAccountViewModel; - - @override - _IoniaCardTabsState createState() => _IoniaCardTabsState(); -} - -class _IoniaCardTabsState extends State<_IoniaCardTabs> with SingleTickerProviderStateMixin { - _IoniaCardTabsState(); - - TabController? _tabController; - - @override - void initState() { - _tabController = TabController(length: 2, vsync: this); - super.initState(); - } - - @override - void dispose() { - super.dispose(); - _tabController?.dispose(); - } - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(24.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - height: 45, - width: 230, - padding: EdgeInsets.all(5), - decoration: BoxDecoration( - color: Theme.of(context).extension()!.titleColor - .withOpacity(0.1), - borderRadius: BorderRadius.circular( - 25.0, - ), - ), - child: Theme( - data: ThemeData(primaryTextTheme: TextTheme(bodyLarge: TextStyle(backgroundColor: Colors.transparent))), - child: TabBar( - controller: _tabController, - indicator: BoxDecoration( - borderRadius: BorderRadius.circular( - 25.0, - ), - color: Theme.of(context).primaryColor, - ), - labelColor: Theme.of(context).extension()!.iconColor, - unselectedLabelColor: - Theme.of(context).extension()!.titleColor, - tabs: [ - Tab( - text: S.of(context).active, - ), - Tab( - text: S.of(context).redeemed, - ), - ], - ), - ), - ), - SizedBox(height: 16), - Expanded( - child: Observer(builder: (_) { - final viewModel = widget.ioniaAccountViewModel; - return TabBarView( - controller: _tabController, - children: [ - _IoniaCardListView( - emptyText: S.of(context).gift_card_balance_note, - merchList: viewModel.activeMechs, - isLoading: viewModel.merchantState is IoniaLoadingMerchantState, - onTap: (giftCard) { - Navigator.pushNamed( - context, - Routes.ioniaGiftCardDetailPage, - arguments: [giftCard]) - .then((_) => viewModel.updateUserGiftCards()); - }), - _IoniaCardListView( - emptyText: S.of(context).gift_card_redeemed_note, - merchList: viewModel.redeemedMerchs, - isLoading: viewModel.merchantState is IoniaLoadingMerchantState, - onTap: (giftCard) { - Navigator.pushNamed( - context, - Routes.ioniaGiftCardDetailPage, - arguments: [giftCard]) - .then((_) => viewModel.updateUserGiftCards()); - }), - ], - ); - }), - ), - ], - ), - ); - } -} - -class _IoniaCardListView extends StatelessWidget { - _IoniaCardListView({ - Key? key, - required this.emptyText, - required this.merchList, - required this.onTap, - this.isLoading = false, - }) : super(key: key); - - final String emptyText; - final List merchList; - final void Function(IoniaGiftCard giftCard) onTap; - final bool isLoading; - - @override - Widget build(BuildContext context) { - if(isLoading){ - return Center( - child: CircularProgressIndicator( - backgroundColor: Theme.of(context).extension()!.textColor, - valueColor: AlwaysStoppedAnimation( - Theme.of(context).extension()!.firstGradientBottomPanelColor), - ), - ); - } - return merchList.isEmpty - ? Center( - child: Text( - emptyText, - textAlign: TextAlign.center, - style: textSmall( - color: Theme.of(context).extension()!.detailsTitlesColor, - ), - ), - ) - : ListView.builder( - itemCount: merchList.length, - itemBuilder: (context, index) { - final merchant = merchList[index]; - return Padding( - padding: const EdgeInsets.only(bottom: 16), - child: CardItem( - onTap: () => onTap?.call(merchant), - title: merchant.legalName, - backgroundColor: Theme.of(context).extension()!.titleColor - .withOpacity(0.1), - discount: 0, - hideBorder: true, - discountBackground: AssetImage('assets/images/red_badge_discount.png'), - titleColor: Theme.of(context).extension()!.titleColor, - subtitleColor: Theme.of(context).hintColor, - subTitle: '', - logoUrl: merchant.logoUrl, - ), - ); - }, - ); - } -} diff --git a/lib/src/screens/ionia/cards/ionia_account_page.dart b/lib/src/screens/ionia/cards/ionia_account_page.dart deleted file mode 100644 index 8fddc507a..000000000 --- a/lib/src/screens/ionia/cards/ionia_account_page.dart +++ /dev/null @@ -1,178 +0,0 @@ -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; -import 'package:cake_wallet/routes.dart'; -import 'package:cake_wallet/src/screens/base_page.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/src/screens/ionia/widgets/ionia_tile.dart'; -import 'package:cake_wallet/src/widgets/primary_button.dart'; -import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; -import 'package:cake_wallet/typography.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_account_view_model.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:cake_wallet/themes/extensions/send_page_theme.dart'; - -class IoniaAccountPage extends BasePage { - IoniaAccountPage(this.ioniaAccountViewModel); - - final IoniaAccountViewModel ioniaAccountViewModel; - - @override - Widget middle(BuildContext context) { - return Text( - S.current.account, - style: textMediumSemiBold( - color: Theme.of(context).extension()!.titleColor, - ), - ); - } - - @override - Widget body(BuildContext context) { - return ScrollableWithBottomSection( - contentPadding: EdgeInsets.all(24), - content: Column( - children: [ - _GradiantContainer( - content: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Observer( - builder: (_) => RichText( - text: TextSpan( - text: '${ioniaAccountViewModel.countOfMerch}', - style: textLargeSemiBold(), - children: [ - TextSpan( - text: ' ${S.of(context).active_cards}', - style: textSmall(color: Colors.white.withOpacity(0.7))), - ], - ), - )), - InkWell( - onTap: () { - Navigator.pushNamed(context, Routes.ioniaAccountCardsPage) - .then((_) => ioniaAccountViewModel.updateUserGiftCards()); - }, - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - S.of(context).view_all, - style: textSmallSemiBold(), - ), - ), - ) - ], - ), - ), - SizedBox(height: 8), - //Row( - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - // children: [ - // _GradiantContainer( - // padding: EdgeInsets.all(16), - // width: deviceWidth * 0.28, - // content: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // S.of(context).total_saving, - // style: textSmall(), - // ), - // SizedBox(height: 8), - // Text( - // '\$100', - // style: textMediumSemiBold(), - // ), - // ], - // ), - // ), - // _GradiantContainer( - // padding: EdgeInsets.all(16), - // width: deviceWidth * 0.28, - // content: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // S.of(context).last_30_days, - // style: textSmall(), - // ), - // SizedBox(height: 8), - // Text( - // '\$100', - // style: textMediumSemiBold(), - // ), - // ], - // ), - // ), - // _GradiantContainer( - // padding: EdgeInsets.all(16), - // width: deviceWidth * 0.28, - // content: Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // Text( - // S.of(context).avg_savings, - // style: textSmall(), - // ), - // SizedBox(height: 8), - // Text( - // '10%', - // style: textMediumSemiBold(), - // ), - // ], - // ), - // ), - // ], - //), - SizedBox(height: 40), - Observer( - builder: (_) => IoniaTile(title: S.of(context).email_address, subTitle: ioniaAccountViewModel.email ?? ''), - ), - Divider() - ], - ), - bottomSectionPadding: EdgeInsets.all(30), - bottomSection: Column( - children: [ - PrimaryButton( - color: Theme.of(context).primaryColor, - textColor: Colors.white, - text: S.of(context).logout, - onPressed: () { - ioniaAccountViewModel.logout(); - Navigator.pushNamedAndRemoveUntil(context, Routes.dashboard, (route) => false); - }, - ), - ], - ), - ); - } -} - -class _GradiantContainer extends StatelessWidget { - const _GradiantContainer({ - Key? key, - required this.content, - }) : super(key: key); - - final Widget content; - - @override - Widget build(BuildContext context) { - return Container( - child: content, - padding: EdgeInsets.all(24), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(15), - gradient: LinearGradient( - colors: [ - Theme.of(context).extension()!.secondGradientColor, - Theme.of(context).extension()!.firstGradientColor, - ], - begin: Alignment.topRight, - end: Alignment.bottomLeft, - ), - ), - ); - } -} diff --git a/lib/src/screens/ionia/cards/ionia_activate_debit_card_page.dart b/lib/src/screens/ionia/cards/ionia_activate_debit_card_page.dart deleted file mode 100644 index f0e641c42..000000000 --- a/lib/src/screens/ionia/cards/ionia_activate_debit_card_page.dart +++ /dev/null @@ -1,115 +0,0 @@ -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; -import 'package:cake_wallet/ionia/ionia_create_state.dart'; -import 'package:cake_wallet/routes.dart'; -import 'package:cake_wallet/src/screens/base_page.dart'; -import 'package:cake_wallet/src/screens/ionia/widgets/text_icon_button.dart'; -import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; -import 'package:cake_wallet/src/widgets/primary_button.dart'; -import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; -import 'package:cake_wallet/typography.dart'; -import 'package:cake_wallet/utils/show_pop_up.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_gift_cards_list_view_model.dart'; -import 'package:flutter/material.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:mobx/mobx.dart'; - -class IoniaActivateDebitCardPage extends BasePage { - - IoniaActivateDebitCardPage(this._cardsListViewModel); - - final IoniaGiftCardsListViewModel _cardsListViewModel; - - @override - Widget middle(BuildContext context) { - return Text( - S.current.debit_card, - style: textMediumSemiBold( - color: Theme.of(context).extension()!.titleColor, - ), - ); - } - - @override - Widget body(BuildContext context) { - reaction((_) => _cardsListViewModel.createCardState, (IoniaCreateCardState state) { - if (state is IoniaCreateCardFailure) { - _onCreateCardFailure(context, state.error); - } - if (state is IoniaCreateCardSuccess) { - _onCreateCardSuccess(context); - } - }); - return ScrollableWithBottomSection( - contentPadding: EdgeInsets.zero, - content: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - children: [ - SizedBox(height: 16), - Text(S.of(context).debit_card_terms), - SizedBox(height: 24), - Text(S.of(context).please_reference_document), - SizedBox(height: 40), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Column( - children: [ - TextIconButton( - label: S.current.cardholder_agreement, - onTap: () {}, - ), - SizedBox( - height: 24, - ), - TextIconButton( - label: S.current.e_sign_consent, - onTap: () {}, - ), - ], - ), - ), - ], - ), - ), - bottomSection: LoadingPrimaryButton( - onPressed: () { - _cardsListViewModel.createCard(); - }, - isLoading: _cardsListViewModel.createCardState is IoniaCreateCardLoading, - text: S.of(context).agree_and_continue, - color: Theme.of(context).primaryColor, - textColor: Colors.white, - ), - ); - } - - void _onCreateCardFailure(BuildContext context, String errorMessage) { - showPopUp( - context: context, - builder: (BuildContext context) { - return AlertWithOneAction( - alertTitle: S.current.error, - alertContent: errorMessage, - buttonText: S.of(context).ok, - buttonAction: () => Navigator.of(context).pop()); - }); - } - - void _onCreateCardSuccess(BuildContext context) { - Navigator.pushNamed( - context, - Routes.ioniaDebitCardPage, - ); - showPopUp( - context: context, - builder: (BuildContext context) { - return AlertWithOneAction( - alertTitle: S.of(context).congratulations, - alertContent: S.of(context).you_now_have_debit_card, - buttonText: S.of(context).ok, - buttonAction: () => Navigator.of(context).pop(), - ); - }, - ); - } -} diff --git a/lib/src/screens/ionia/cards/ionia_buy_card_detail_page.dart b/lib/src/screens/ionia/cards/ionia_buy_card_detail_page.dart deleted file mode 100644 index 917c1d8fd..000000000 --- a/lib/src/screens/ionia/cards/ionia_buy_card_detail_page.dart +++ /dev/null @@ -1,478 +0,0 @@ -import 'package:cake_wallet/core/execution_state.dart'; -import 'package:cake_wallet/themes/extensions/receive_page_theme.dart'; -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; -import 'package:cake_wallet/ionia/ionia_merchant.dart'; -import 'package:cake_wallet/ionia/ionia_tip.dart'; -import 'package:cake_wallet/palette.dart'; -import 'package:cake_wallet/routes.dart'; -import 'package:cake_wallet/src/screens/ionia/widgets/ionia_alert_model.dart'; -import 'package:cake_wallet/src/screens/ionia/widgets/text_icon_button.dart'; -import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; -import 'package:cake_wallet/src/widgets/discount_badge.dart'; -import 'package:cake_wallet/src/widgets/primary_button.dart'; -import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; -import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart'; -import 'package:cake_wallet/typography.dart'; -import 'package:cake_wallet/utils/show_pop_up.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_purchase_merch_view_model.dart'; -import 'package:flutter/material.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:mobx/mobx.dart'; -import 'package:cake_wallet/src/screens/base_page.dart'; -import 'package:cake_wallet/src/screens/send/widgets/confirm_sending_alert.dart'; -import 'package:cake_wallet/themes/extensions/send_page_theme.dart'; -import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart'; - -class IoniaBuyGiftCardDetailPage extends BasePage { - IoniaBuyGiftCardDetailPage(this.ioniaPurchaseViewModel); - - final IoniaMerchPurchaseViewModel ioniaPurchaseViewModel; - - @override - Widget middle(BuildContext context) { - return Text( - ioniaPurchaseViewModel.ioniaMerchant.legalName, - style: textMediumSemiBold(color: Theme.of(context).extension()!.titleColor), - ); - } - - @override - Widget? trailing(BuildContext context) - => ioniaPurchaseViewModel.ioniaMerchant.discount > 0 - ? DiscountBadge(percentage: ioniaPurchaseViewModel.ioniaMerchant.discount) - : null; - - @override - Widget body(BuildContext context) { - reaction((_) => ioniaPurchaseViewModel.invoiceCreationState, (ExecutionState state) { - if (state is FailureState) { - WidgetsBinding.instance.addPostFrameCallback((_) { - showPopUp( - context: context, - builder: (BuildContext context) { - return AlertWithOneAction( - alertTitle: S.of(context).error, - alertContent: state.error, - buttonText: S.of(context).ok, - buttonAction: () => Navigator.of(context).pop()); - }); - }); - } - }); - - reaction((_) => ioniaPurchaseViewModel.invoiceCommittingState, (ExecutionState state) { - if (state is FailureState) { - WidgetsBinding.instance.addPostFrameCallback((_) { - showPopUp( - context: context, - builder: (BuildContext context) { - return AlertWithOneAction( - alertTitle: S.of(context).error, - alertContent: state.error, - buttonText: S.of(context).ok, - buttonAction: () => Navigator.of(context).pop()); - }); - }); - } - - if (state is ExecutedSuccessfullyState) { - WidgetsBinding.instance.addPostFrameCallback((_) { - Navigator.of(context).pushReplacementNamed( - Routes.ioniaPaymentStatusPage, - arguments: [ - ioniaPurchaseViewModel.paymentInfo, - ioniaPurchaseViewModel.committedInfo]); - }); - } - }); - - return ScrollableWithBottomSection( - contentPadding: EdgeInsets.zero, - content: Observer(builder: (_) { - final tipAmount = ioniaPurchaseViewModel.tipAmount; - return Column( - children: [ - SizedBox(height: 36), - Container( - padding: EdgeInsets.symmetric(vertical: 24), - margin: EdgeInsets.symmetric(horizontal: 16), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - gradient: LinearGradient( - colors: [ - Theme.of(context).extension()!.firstGradientColor, - Theme.of(context).extension()!.secondGradientColor, - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ), - child: Column( - children: [ - Text( - S.of(context).gift_card_amount, - style: textSmall(), - ), - SizedBox(height: 4), - Text( - '\$${ioniaPurchaseViewModel.giftCardAmount.toStringAsFixed(2)}', - style: textXLargeSemiBold(), - ), - SizedBox(height: 24), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 24.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - S.of(context).bill_amount, - style: textSmall(), - ), - SizedBox(height: 4), - Text( - '\$${ioniaPurchaseViewModel.billAmount.toStringAsFixed(2)}', - style: textLargeSemiBold(), - ), - ], - ), - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text( - S.of(context).tip, - style: textSmall(), - ), - SizedBox(height: 4), - Text( - '\$${tipAmount.toStringAsFixed(2)}', - style: textLargeSemiBold(), - ), - ], - ), - ], - ), - ), - ], - ), - ), - if(ioniaPurchaseViewModel.ioniaMerchant.acceptsTips) - Padding( - padding: const EdgeInsets.fromLTRB(24.0, 24.0, 0, 24.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - S.of(context).tip, - style: TextStyle( - color: Theme.of(context).extension()!.titleColor, - fontWeight: FontWeight.w700, - fontSize: 14, - ), - ), - SizedBox(height: 4), - Observer( - builder: (_) => TipButtonGroup( - selectedTip: ioniaPurchaseViewModel.selectedTip!.percentage, - tipsList: ioniaPurchaseViewModel.tips, - onSelect: (value) => ioniaPurchaseViewModel.addTip(value), - amount: ioniaPurchaseViewModel.amount, - merchant: ioniaPurchaseViewModel.ioniaMerchant, - ), - ) - ], - ), - ), - SizedBox(height: 20), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 24.0), - child: TextIconButton( - label: S.of(context).how_to_use_card, - onTap: () => _showHowToUseCard(context, ioniaPurchaseViewModel.ioniaMerchant), - ), - ), - ], - ); - }), - bottomSection: Column( - children: [ - Padding( - padding: EdgeInsets.only(bottom: 12), - child: Observer(builder: (_) { - return LoadingPrimaryButton( - isLoading: ioniaPurchaseViewModel.invoiceCreationState is IsExecutingState || - ioniaPurchaseViewModel.invoiceCommittingState is IsExecutingState, - onPressed: () => purchaseCard(context), - text: S.of(context).purchase_gift_card, - color: Theme.of(context).primaryColor, - textColor: Colors.white, - ); - }), - ), - SizedBox(height: 8), - InkWell( - onTap: () => _showTermsAndCondition(context), - child: Text(S.of(context).settings_terms_and_conditions, - style: textMediumSemiBold( - color: Theme.of(context).extension()!.firstGradientBottomPanelColor, - ).copyWith(fontSize: 12)), - ), - SizedBox(height: 16) - ], - ), - ); - } - - void _showTermsAndCondition(BuildContext context) { - showPopUp( - context: context, - builder: (BuildContext context) { - return IoniaAlertModal( - title: S.of(context).settings_terms_and_conditions, - content: Align( - alignment: Alignment.bottomLeft, - child: Text( - ioniaPurchaseViewModel.ioniaMerchant.termsAndConditions, - style: textMedium( - color: Theme.of(context).extension()!.tilesTextColor, - ), - ), - ), - actionTitle: S.of(context).agree, - showCloseButton: false, - heightFactor: 0.6, - ); - }); - } - - Future purchaseCard(BuildContext context) async { - await ioniaPurchaseViewModel.createInvoice(); - - if (ioniaPurchaseViewModel.invoiceCreationState is ExecutedSuccessfullyState) { - await _presentSuccessfulInvoiceCreationPopup(context); - } - } - - void _showHowToUseCard( - BuildContext context, - IoniaMerchant merchant, - ) { - showPopUp( - context: context, - builder: (BuildContext context) { - return IoniaAlertModal( - title: S.of(context).how_to_use_card, - content: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: merchant.instructions - .map((instruction) { - return [ - Padding( - padding: EdgeInsets.all(10), - child: Text( - instruction.header, - style: textLargeSemiBold( - color: Theme.of(context).extension()!.tilesTextColor, - ), - )), - Text( - instruction.body, - style: textMedium( - color: Theme.of(context).extension()!.tilesTextColor, - ), - ) - ]; - }) - .expand((e) => e) - .toList()), - actionTitle: S.current.got_it, - ); - }); - } - - Future _presentSuccessfulInvoiceCreationPopup(BuildContext context) async { - if (ioniaPurchaseViewModel.invoice == null) { - return; - } - - final amount = ioniaPurchaseViewModel.invoice!.totalAmount; - final addresses = ioniaPurchaseViewModel.invoice!.outAddresses; - ioniaPurchaseViewModel.sendViewModel.outputs.first.setCryptoAmount(amount); - ioniaPurchaseViewModel.sendViewModel.outputs.first.address = addresses.first; - - await showPopUp( - context: context, - builder: (_) { - return ConfirmSendingAlert( - alertTitle: S.of(context).confirm_sending, - paymentId: S.of(context).payment_id, - paymentIdValue: ioniaPurchaseViewModel.invoice!.paymentId, - amount: S.of(context).send_amount, - amountValue: '$amount ${ioniaPurchaseViewModel.invoice!.chain}', - fiatAmountValue: - '~ ${ioniaPurchaseViewModel.sendViewModel.outputs.first.fiatAmount} ' - '${ioniaPurchaseViewModel.sendViewModel.fiat.title}', - fee: S.of(context).send_fee, - feeValue: - '${ioniaPurchaseViewModel.sendViewModel.outputs.first.estimatedFee} ' - '${ioniaPurchaseViewModel.invoice!.chain}', - feeFiatAmount: - '${ioniaPurchaseViewModel.sendViewModel.outputs.first.estimatedFeeFiatAmount} ' - '${ioniaPurchaseViewModel.sendViewModel.fiat.title}', - outputs: ioniaPurchaseViewModel.sendViewModel.outputs, - rightButtonText: S.of(context).ok, - leftButtonText: S.of(context).cancel, - alertLeftActionButtonTextColor: Colors.white, - alertRightActionButtonTextColor: Colors.white, - alertLeftActionButtonColor: Palette.brightOrange, - alertRightActionButtonColor: Theme.of(context).primaryColor, - actionRightButton: () async { - Navigator.of(context).pop(); - await ioniaPurchaseViewModel.commitPaymentInvoice(); - }, - actionLeftButton: () => Navigator.of(context).pop()); - }, - ); - } -} - -class TipButtonGroup extends StatelessWidget { - const TipButtonGroup({ - Key? key, - required this.selectedTip, - required this.onSelect, - required this.tipsList, - required this.amount, - required this.merchant, - }) : super(key: key); - - final Function(IoniaTip) onSelect; - final double selectedTip; - final List tipsList; - final double amount; - final IoniaMerchant merchant; - - bool _isSelected(double value) => selectedTip == value; - Set get filter => tipsList.map((e) => e.percentage).toSet(); - bool get _isCustomSelected => !filter.contains(selectedTip); - - @override - Widget build(BuildContext context) { - return Container( - height: 50, - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: tipsList.length, - itemBuilder: (BuildContext context, int index) { - final tip = tipsList[index]; - return Padding( - padding: EdgeInsets.only(right: 5), - child: TipButton( - isSelected: tip.isCustom ? _isCustomSelected : _isSelected(tip.percentage), - onTap: () async { - IoniaTip ioniaTip = tip; - if(tip.isCustom){ - final customTip = await Navigator.pushNamed(context, Routes.ioniaCustomTipPage, arguments: [amount, merchant, tip]) as IoniaTip?; - ioniaTip = customTip ?? tip; - } - onSelect(ioniaTip); - }, - caption: tip.isCustom ? S.of(context).custom : '${tip.percentage.toStringAsFixed(0)}%', - subTitle: tip.isCustom ? null : '\$${tip.additionalAmount.toStringAsFixed(2)}', - )); - })); - } -} - -class TipButton extends StatelessWidget { - const TipButton({ - required this.caption, - required this.onTap, - this.subTitle, - this.isSelected = false, - }); - - final String caption; - final String? subTitle; - final bool isSelected; - final void Function() onTap; - - bool isDark(BuildContext context) => Theme.of(context).brightness == Brightness.dark; - - Color captionTextColor(BuildContext context) { - if (isDark(context)) { - return Theme.of(context).extension()!.titleColor; - } - - return isSelected - ? Theme.of(context).dialogTheme.backgroundColor! - : Theme.of(context).extension()!.titleColor; - } - - Color subTitleTextColor(BuildContext context) { - if (isDark(context)) { - return Theme.of(context).extension()!.titleColor; - } - - return isSelected - ? Theme.of(context).dialogTheme.backgroundColor! - : Theme.of(context).extension()!.detailsTitlesColor; - } - - Color? backgroundColor(BuildContext context) { - if (isDark(context)) { - return isSelected - ? null - : Theme.of(context).extension()!.titleColor.withOpacity(0.01); - } - - return isSelected - ? null - : Theme.of(context).extension()!.titleColor.withOpacity(0.1); - } - - @override - Widget build(BuildContext context) { - return InkWell( - onTap: onTap, - child: Container( - height: 49, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text(caption, - style: textSmallSemiBold( - color: captionTextColor(context))), - if (subTitle != null) ...[ - SizedBox(height: 4), - Text( - subTitle!, - style: textXxSmallSemiBold( - color: subTitleTextColor(context), - ), - ), - ] - ], - ), - padding: EdgeInsets.symmetric(horizontal: 18, vertical: 8), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: backgroundColor(context), - gradient: isSelected - ? LinearGradient( - colors: [ - Theme.of(context).extension()!.firstGradientColor, - Theme.of(context).extension()!.secondGradientColor, - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ) - : null, - ), - ), - ); - } -} diff --git a/lib/src/screens/ionia/cards/ionia_buy_gift_card.dart b/lib/src/screens/ionia/cards/ionia_buy_gift_card.dart deleted file mode 100644 index ba5b4fbbd..000000000 --- a/lib/src/screens/ionia/cards/ionia_buy_gift_card.dart +++ /dev/null @@ -1,186 +0,0 @@ -import 'package:cake_wallet/themes/extensions/keyboard_theme.dart'; -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; -import 'package:cake_wallet/routes.dart'; -import 'package:cake_wallet/src/screens/base_page.dart'; -import 'package:cake_wallet/src/screens/ionia/widgets/card_item.dart'; -import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; -import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; -import 'package:cake_wallet/src/widgets/primary_button.dart'; -import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; -import 'package:cake_wallet/themes/theme_base.dart'; -import 'package:cake_wallet/utils/responsive_layout_util.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_buy_card_view_model.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:keyboard_actions/keyboard_actions.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/themes/extensions/send_page_theme.dart'; - -class IoniaBuyGiftCardPage extends BasePage { - IoniaBuyGiftCardPage( - this.ioniaBuyCardViewModel, - ) : _amountFieldFocus = FocusNode(), - _amountController = TextEditingController() { - _amountController.addListener(() { - ioniaBuyCardViewModel.onAmountChanged(_amountController.text); - }); - } - - final IoniaBuyCardViewModel ioniaBuyCardViewModel; - - @override - String get title => S.current.enter_amount; - - @override - bool get extendBodyBehindAppBar => true; - - @override - AppBarStyle get appBarStyle => AppBarStyle.transparent; - - Color get textColor => currentTheme.type == ThemeType.dark ? Colors.white : Color(0xff393939); - - final TextEditingController _amountController; - final FocusNode _amountFieldFocus; - - @override - Widget body(BuildContext context) { - final merchant = ioniaBuyCardViewModel.ioniaMerchant; - return KeyboardActions( - disableScroll: true, - config: KeyboardActionsConfig( - keyboardActionsPlatform: KeyboardActionsPlatform.IOS, - keyboardBarColor: Theme.of(context).extension()!.keyboardBarColor, - nextFocus: false, - actions: [ - KeyboardActionsItem( - focusNode: _amountFieldFocus, - toolbarButtons: [(_) => KeyboardDoneButton()], - ), - ]), - child: Container( - color: Theme.of(context).colorScheme.background, - child: ScrollableWithBottomSection( - contentPadding: EdgeInsets.zero, - content: Column( - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 25), - decoration: BoxDecoration( - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(24), - bottomRight: Radius.circular(24), - ), - gradient: LinearGradient(colors: [ - Theme.of(context).extension()!.firstGradientColor, - Theme.of(context).extension()!.secondGradientColor, - ], begin: Alignment.topLeft, end: Alignment.bottomRight), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox(height: 150), - SizedBox( - width: 200, - child: BaseTextFormField( - controller: _amountController, - focusNode: _amountFieldFocus, - keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true), - inputFormatters: [ - FilteringTextInputFormatter.deny(RegExp('[\-|\ ]')), - FilteringTextInputFormatter.allow( - RegExp(r'^\d+(\.|\,)?\d{0,2}'), - ), - ], - hintText: '1000', - placeholderTextStyle: TextStyle( - color: Theme.of(context).extension()!.textFieldBorderColor, - fontWeight: FontWeight.w600, - fontSize: 36, - ), - prefixIcon: Text( - 'USD: ', - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.w600, - fontSize: 36, - ), - ), - textColor: Colors.white, - textStyle: TextStyle( - color: Colors.white, - fontSize: 36, - ), - ), - ), - Divider( - color: Theme.of(context).extension()!.textFieldBorderColor, - height: 1, - ), - SizedBox(height: 8), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - S.of(context).min_amount(merchant.minimumCardPurchase.toStringAsFixed(2)), - style: TextStyle( - color: Theme.of(context).extension()!.textFieldBorderColor, - ), - ), - Text( - S.of(context).max_amount(merchant.maximumCardPurchase.toStringAsFixed(2)), - style: TextStyle( - color: Theme.of(context).extension()!.textFieldBorderColor, - ), - ), - ], - ), - SizedBox(height: 24), - ], - ), - ), - Padding( - padding: const EdgeInsets.all(24.0), - child: CardItem( - title: merchant.legalName, - backgroundColor: Theme.of(context).extension()!.titleColor - .withOpacity(0.1), - discount: merchant.discount, - titleColor: Theme.of(context).extension()!.titleColor, - subtitleColor: Theme.of(context).hintColor, - subTitle: merchant.avaibilityStatus, - logoUrl: merchant.logoUrl, - ), - ) - ], - ), - bottomSection: Column( - children: [ - Observer(builder: (_) { - return Padding( - padding: EdgeInsets.only(bottom: 12), - child: PrimaryButton( - onPressed: () => Navigator.of(context).pushNamed( - Routes.ioniaBuyGiftCardDetailPage, - arguments: [ - ioniaBuyCardViewModel.amount, - ioniaBuyCardViewModel.ioniaMerchant, - ], - ), - text: S.of(context).continue_text, - isDisabled: !ioniaBuyCardViewModel.isEnablePurchase, - color: Theme.of(context).primaryColor, - textColor: Colors.white, - ), - ); - }), - SizedBox(height: 30), - ], - ), - ), - ), - ); - } -} diff --git a/lib/src/screens/ionia/cards/ionia_custom_redeem_page.dart b/lib/src/screens/ionia/cards/ionia_custom_redeem_page.dart deleted file mode 100644 index 7cc4d1f0c..000000000 --- a/lib/src/screens/ionia/cards/ionia_custom_redeem_page.dart +++ /dev/null @@ -1,175 +0,0 @@ -import 'package:cake_wallet/themes/extensions/keyboard_theme.dart'; -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; -import 'package:cake_wallet/core/execution_state.dart'; -import 'package:cake_wallet/src/screens/base_page.dart'; -import 'package:cake_wallet/src/screens/ionia/widgets/card_item.dart'; -import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; -import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; -import 'package:cake_wallet/src/widgets/primary_button.dart'; -import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; -import 'package:cake_wallet/themes/theme_base.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_custom_redeem_view_model.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:keyboard_actions/keyboard_actions.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/themes/extensions/send_page_theme.dart'; - -class IoniaCustomRedeemPage extends BasePage { - IoniaCustomRedeemPage( - this.ioniaCustomRedeemViewModel, - ) : _amountFieldFocus = FocusNode(), - _amountController = TextEditingController() { - _amountController.addListener(() { - ioniaCustomRedeemViewModel.updateAmount(_amountController.text); - }); - } - - final IoniaCustomRedeemViewModel ioniaCustomRedeemViewModel; - - @override - String get title => S.current.custom_redeem_amount; - - @override - bool get extendBodyBehindAppBar => true; - - @override - AppBarStyle get appBarStyle => AppBarStyle.transparent; - - Color get textColor => currentTheme.type == ThemeType.dark ? Colors.white : Color(0xff393939); - - final TextEditingController _amountController; - final FocusNode _amountFieldFocus; - - @override - Widget body(BuildContext context) { - final _width = MediaQuery.of(context).size.width; - final giftCard = ioniaCustomRedeemViewModel.giftCard; - return KeyboardActions( - disableScroll: true, - config: KeyboardActionsConfig( - keyboardActionsPlatform: KeyboardActionsPlatform.IOS, - keyboardBarColor: Theme.of(context).extension()!.keyboardBarColor, - nextFocus: false, - actions: [ - KeyboardActionsItem( - focusNode: _amountFieldFocus, - toolbarButtons: [(_) => KeyboardDoneButton()], - ), - ]), - child: Container( - color: Theme.of(context).colorScheme.background, - child: ScrollableWithBottomSection( - contentPadding: EdgeInsets.zero, - content: Column( - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 25), - decoration: BoxDecoration( - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)), - gradient: LinearGradient(colors: [ - Theme.of(context).extension()!.firstGradientColor, - Theme.of(context).extension()!.secondGradientColor, - ], begin: Alignment.topLeft, end: Alignment.bottomRight), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - SizedBox(height: 150), - BaseTextFormField( - controller: _amountController, - focusNode: _amountFieldFocus, - keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true), - inputFormatters: [FilteringTextInputFormatter.deny(RegExp('[\-|\ ]'))], - hintText: '1000', - placeholderTextStyle: TextStyle( - color: Theme.of(context).extension()!.textFieldBorderColor, - fontWeight: FontWeight.w500, - fontSize: 36, - ), - borderColor: Theme.of(context).extension()!.textFieldBorderColor, - textColor: Colors.white, - textStyle: TextStyle( - color: Colors.white, - fontSize: 36, - ), - suffixIcon: SizedBox( - width: _width / 6, - ), - prefixIcon: Padding( - padding: EdgeInsets.only( - top: 5.0, - left: _width / 4, - ), - child: Text( - 'USD: ', - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.w900, - fontSize: 36, - ), - ), - ), - ), - SizedBox(height: 8), - Observer( - builder: (_) => !ioniaCustomRedeemViewModel.disableRedeem - ? Center( - child: Text( - '\$${giftCard.remainingAmount} - \$${ioniaCustomRedeemViewModel.amount} = \$${ioniaCustomRedeemViewModel.formattedRemaining} ${S.of(context).remaining}', - style: TextStyle( - color: Theme.of(context).extension()!.textFieldBorderColor, - ), - ), - ) - : SizedBox.shrink(), - ), - SizedBox(height: 24), - ], - ), - ), - Padding( - padding: const EdgeInsets.all(24.0), - child: CardItem( - title: giftCard.legalName, - backgroundColor: Theme.of(context).extension()!.titleColor - .withOpacity(0.1), - discount: giftCard.remainingAmount, - isAmount: true, - discountBackground: AssetImage('assets/images/red_badge_discount.png'), - titleColor: Theme.of(context).extension()!.titleColor, - subtitleColor: Theme.of(context).hintColor, - subTitle: S.of(context).online, - logoUrl: giftCard.logoUrl, - ), - ), - ], - ), - bottomSection: Column( - children: [ - Observer( - builder: (_) => Padding( - padding: EdgeInsets.only(bottom: 12), - child: LoadingPrimaryButton( - isLoading: ioniaCustomRedeemViewModel.redeemState is IsExecutingState, - isDisabled: ioniaCustomRedeemViewModel.disableRedeem, - text: S.of(context).add_custom_redemption, - color: Theme.of(context).primaryColor, - textColor: Colors.white, - onPressed: () => ioniaCustomRedeemViewModel.addCustomRedeem().then((value) { - Navigator.of(context).pop(ioniaCustomRedeemViewModel.remaining.toString()); - }), - ), - ), - ), - SizedBox(height: 30), - ], - ), - ), - ), - ); - } -} diff --git a/lib/src/screens/ionia/cards/ionia_custom_tip_page.dart b/lib/src/screens/ionia/cards/ionia_custom_tip_page.dart deleted file mode 100644 index eced01e96..000000000 --- a/lib/src/screens/ionia/cards/ionia_custom_tip_page.dart +++ /dev/null @@ -1,177 +0,0 @@ -import 'package:cake_wallet/themes/extensions/keyboard_theme.dart'; -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; -import 'package:cake_wallet/ionia/ionia_merchant.dart'; -import 'package:cake_wallet/src/screens/base_page.dart'; -import 'package:cake_wallet/src/screens/ionia/widgets/card_item.dart'; -import 'package:cake_wallet/src/widgets/base_text_form_field.dart'; -import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; -import 'package:cake_wallet/src/widgets/primary_button.dart'; -import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; -import 'package:cake_wallet/themes/theme_base.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_custom_tip_view_model.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:keyboard_actions/keyboard_actions.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/themes/extensions/send_page_theme.dart'; - -class IoniaCustomTipPage extends BasePage { - IoniaCustomTipPage( - this.customTipViewModel, - ) : _amountFieldFocus = FocusNode(), - _amountController = TextEditingController() { - _amountController.addListener(() { - customTipViewModel.onTipChanged(_amountController.text); - }); - } - - final IoniaCustomTipViewModel customTipViewModel; - - - @override - String get title => S.current.enter_amount; - - @override - bool get extendBodyBehindAppBar => true; - - @override - AppBarStyle get appBarStyle => AppBarStyle.transparent; - - Color get textColor => currentTheme.type == ThemeType.dark ? Colors.white : Color(0xff393939); - - final TextEditingController _amountController; - final FocusNode _amountFieldFocus; - - @override - Widget body(BuildContext context) { - final _width = MediaQuery.of(context).size.width; - final merchant = customTipViewModel.ioniaMerchant; - return KeyboardActions( - disableScroll: true, - config: KeyboardActionsConfig( - keyboardActionsPlatform: KeyboardActionsPlatform.IOS, - keyboardBarColor: Theme.of(context).extension()!.keyboardBarColor, - nextFocus: false, - actions: [ - KeyboardActionsItem( - focusNode: _amountFieldFocus, - toolbarButtons: [(_) => KeyboardDoneButton()], - ), - ]), - child: Container( - color: Theme.of(context).colorScheme.background, - child: ScrollableWithBottomSection( - contentPadding: EdgeInsets.zero, - content: Column( - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 25), - decoration: BoxDecoration( - borderRadius: BorderRadius.only(bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)), - gradient: LinearGradient(colors: [ - Theme.of(context).extension()!.firstGradientColor, - Theme.of(context).extension()!.secondGradientColor, - ], begin: Alignment.topLeft, end: Alignment.bottomRight), - ), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - SizedBox(height: 150), - BaseTextFormField( - controller: _amountController, - focusNode: _amountFieldFocus, - keyboardType: TextInputType.numberWithOptions(signed: false, decimal: true), - inputFormatters: [FilteringTextInputFormatter.deny(RegExp('[\-|\ ]'))], - hintText: '1000', - placeholderTextStyle: TextStyle( - color: Theme.of(context).extension()!.textFieldBorderColor, - fontWeight: FontWeight.w500, - fontSize: 36, - ), - borderColor: Theme.of(context).extension()!.textFieldBorderColor, - textColor: Colors.white, - textStyle: TextStyle( - color: Colors.white, - fontSize: 36, - ), - suffixIcon: SizedBox( - width: _width / 6, - ), - prefixIcon: Padding( - padding: EdgeInsets.only( - top: 5.0, - left: _width / 4, - ), - child: Text( - 'USD: ', - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.w900, - fontSize: 36, - ), - ), - ), - ), - SizedBox(height: 8), - Observer(builder: (_) { - if (customTipViewModel.percentage == 0.0) { - return SizedBox.shrink(); - } - - return RichText( - textAlign: TextAlign.center, - text: TextSpan( - text: '\$${_amountController.text}', - style: TextStyle( - color: Theme.of(context).extension()!.textFieldBorderColor, - ), - children: [ - TextSpan(text: ' ${S.of(context).is_percentage} '), - TextSpan(text: '${customTipViewModel.percentage.toStringAsFixed(2)}%'), - TextSpan(text: ' ${S.of(context).percentageOf(customTipViewModel.amount.toStringAsFixed(2))} '), - ], - ), - ); - }), - SizedBox(height: 24), - ], - ), - ), - Padding( - padding: const EdgeInsets.all(24.0), - child: CardItem( - title: merchant.legalName, - backgroundColor: Theme.of(context).extension()!.titleColor - .withOpacity(0.1), - discount: 0.0, - titleColor: Theme.of(context).extension()!.titleColor, - subtitleColor: Theme.of(context).hintColor, - subTitle: merchant.isOnline ? S.of(context).online : S.of(context).offline, - logoUrl: merchant.logoUrl, - ), - ) - ], - ), - bottomSection: Column( - children: [ - Padding( - padding: EdgeInsets.only(bottom: 12), - child: PrimaryButton( - onPressed: () { - Navigator.of(context).pop(customTipViewModel.customTip); - }, - text: S.of(context).add_tip, - color: Theme.of(context).primaryColor, - textColor: Colors.white, - ), - ), - SizedBox(height: 30), - ], - ), - ), - ), - ); - } -} diff --git a/lib/src/screens/ionia/cards/ionia_debit_card_page.dart b/lib/src/screens/ionia/cards/ionia_debit_card_page.dart deleted file mode 100644 index 7e6a43253..000000000 --- a/lib/src/screens/ionia/cards/ionia_debit_card_page.dart +++ /dev/null @@ -1,393 +0,0 @@ -import 'package:cake_wallet/ionia/ionia_create_state.dart'; -import 'package:cake_wallet/themes/extensions/receive_page_theme.dart'; -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; -import 'package:cake_wallet/ionia/ionia_virtual_card.dart'; -import 'package:cake_wallet/routes.dart'; -import 'package:cake_wallet/src/screens/base_page.dart'; -import 'package:cake_wallet/src/screens/ionia/widgets/text_icon_button.dart'; -import 'package:cake_wallet/src/widgets/alert_background.dart'; -import 'package:cake_wallet/src/widgets/primary_button.dart'; -import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; -import 'package:cake_wallet/themes/extensions/cake_scrollbar_theme.dart'; -import 'package:cake_wallet/typography.dart'; -import 'package:cake_wallet/utils/show_pop_up.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_gift_cards_list_view_model.dart'; -import 'package:flutter/material.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:cake_wallet/themes/extensions/send_page_theme.dart'; - -class IoniaDebitCardPage extends BasePage { - final IoniaGiftCardsListViewModel _cardsListViewModel; - - IoniaDebitCardPage(this._cardsListViewModel); - - @override - Widget middle(BuildContext context) { - return Text( - S.current.debit_card, - style: textMediumSemiBold( - color: Theme.of(context).extension()!.titleColor, - ), - ); - } - - @override - Widget body(BuildContext context) { - return Observer( - builder: (_) { - final cardState = _cardsListViewModel.cardState; - if (cardState is IoniaFetchingCard) { - return Center(child: CircularProgressIndicator()); - } - if (cardState is IoniaCardSuccess) { - return ScrollableWithBottomSection( - contentPadding: EdgeInsets.zero, - content: Padding( - padding: const EdgeInsets.all(16.0), - child: _IoniaDebitCard( - cardInfo: cardState.card, - ), - ), - bottomSection: Column( - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20.0), - child: Text( - S.of(context).billing_address_info, - style: textSmall( - color: Theme.of(context).extension()!.iconsColor), - textAlign: TextAlign.center, - ), - ), - SizedBox(height: 24), - PrimaryButton( - text: S.of(context).order_physical_card, - onPressed: () {}, - color: Color(0xffE9F2FC), - textColor: Theme.of(context).extension()!.tilesTextColor, - ), - SizedBox(height: 8), - PrimaryButton( - text: S.of(context).add_value, - onPressed: () {}, - color: Theme.of(context).primaryColor, - textColor: Colors.white, - ), - SizedBox(height: 16) - ], - ), - ); - } - return ScrollableWithBottomSection( - contentPadding: EdgeInsets.zero, - content: Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - children: [ - _IoniaDebitCard(isCardSample: true), - SizedBox(height: 40), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: Column( - children: [ - TextIconButton( - label: S.current.how_to_use_card, - onTap: () => _showHowToUseCard(context), - ), - SizedBox( - height: 24, - ), - TextIconButton( - label: S.current.frequently_asked_questions, - onTap: () {}, - ), - ], - ), - ), - SizedBox(height: 50), - Container( - padding: EdgeInsets.all(20), - margin: EdgeInsets.all(8), - width: double.infinity, - decoration: BoxDecoration( - color: Color.fromRGBO(233, 242, 252, 1), - borderRadius: BorderRadius.circular(20), - ), - child: RichText( - text: TextSpan( - text: S.of(context).get_a, - style: textMedium( - color: - Theme.of(context).extension()!.tilesTextColor), - children: [ - TextSpan( - text: S.of(context).digital_and_physical_card, - style: textMediumBold( - color: Theme.of(context).extension()!.tilesTextColor), - ), - TextSpan( - text: S.of(context).get_card_note, - ) - ], - )), - ), - ], - ), - ), - bottomSectionPadding: EdgeInsets.symmetric( - horizontal: 16, - vertical: 32, - ), - bottomSection: PrimaryButton( - text: S.of(context).activate, - onPressed: () => _showHowToUseCard(context, activate: true), - color: Theme.of(context).primaryColor, - textColor: Colors.white, - ), - ); - }, - ); - } - - void _showHowToUseCard(BuildContext context, {bool activate = false}) { - showPopUp( - context: context, - builder: (BuildContext context) { - return AlertBackground( - child: Material( - color: Colors.transparent, - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - SizedBox(height: 10), - Container( - padding: EdgeInsets.only(top: 24, left: 24, right: 24), - margin: EdgeInsets.all(24), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.background, - borderRadius: BorderRadius.circular(30), - ), - child: Column( - children: [ - Text( - S.of(context).how_to_use_card, - style: textLargeSemiBold( - color: - Theme.of(context).extension()!.thumbColor, - ), - ), - SizedBox(height: 24), - Align( - alignment: Alignment.bottomLeft, - child: Text( - S.of(context).signup_for_card_accept_terms, - style: textSmallSemiBold( - color: Theme.of(context).extension()!.tilesTextColor, - ), - ), - ), - SizedBox(height: 24), - _TitleSubtitleTile( - title: S.of(context).add_fund_to_card('1000'), - subtitle: S.of(context).use_card_info_two, - ), - SizedBox(height: 21), - _TitleSubtitleTile( - title: S.of(context).use_card_info_three, - subtitle: S.of(context).optionally_order_card, - ), - SizedBox(height: 35), - PrimaryButton( - onPressed: () => activate - ? Navigator.pushNamed(context, Routes.ioniaActivateDebitCardPage) - : Navigator.pop(context), - text: S.of(context).got_it, - color: Color.fromRGBO(233, 242, 252, 1), - textColor: - Theme.of(context).extension()!.tilesTextColor, - ), - SizedBox(height: 21), - ], - ), - ), - InkWell( - onTap: () => Navigator.pop(context), - child: Container( - margin: EdgeInsets.only(bottom: 40), - child: CircleAvatar( - child: Icon( - Icons.close, - color: Colors.black, - ), - backgroundColor: Colors.white, - ), - ), - ) - ], - ), - ), - ); - }); - } -} - -class _IoniaDebitCard extends StatefulWidget { - const _IoniaDebitCard({ - Key? key, - this.cardInfo, - this.isCardSample = false, - }) : super(key: key); - - final bool isCardSample; - final IoniaVirtualCard? cardInfo; - - @override - _IoniaDebitCardState createState() => _IoniaDebitCardState(); -} - -class _IoniaDebitCardState extends State<_IoniaDebitCard> { - bool _showDetails = false; - void _toggleVisibility() { - setState(() => _showDetails = !_showDetails); - } - - String _formatPan(String pan) { - if (pan == null) return ''; - return pan.replaceAllMapped(RegExp(r'.{4}'), (match) => '${match.group(0)} '); - } - - String get _getLast4 => widget.isCardSample ? '0000' : widget.cardInfo!.pan.substring(widget.cardInfo!.pan.length - 5); - - String get _getSpendLimit => widget.isCardSample ? '10000' : widget.cardInfo!.spendLimit.toStringAsFixed(2); - - @override - Widget build(BuildContext context) { - return Container( - padding: EdgeInsets.symmetric(horizontal: 24, vertical: 19), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(24), - gradient: LinearGradient( - colors: [ - Theme.of(context).extension()!.firstGradientColor, - Theme.of(context).extension()!.secondGradientColor, - ], - begin: Alignment.topLeft, - end: Alignment.bottomRight, - ), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - SizedBox(height: 16), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - S.current.cakepay_prepaid_card, - style: textSmall(), - ), - Image.asset( - 'assets/images/mastercard.png', - width: 54, - ), - ], - ), - Text( - widget.isCardSample ? S.of(context).upto(_getSpendLimit) : '\$$_getSpendLimit', - style: textXLargeSemiBold(), - ), - SizedBox(height: 16), - Text( - _showDetails ? _formatPan(widget.cardInfo?.pan ?? '') : '**** **** **** $_getLast4', - style: textMediumSemiBold(), - ), - SizedBox(height: 32), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - if (widget.isCardSample) - Text( - S.current.no_id_needed, - style: textMediumBold(), - ) - else ...[ - Column( - children: [ - Text( - 'CVV', - style: textXSmallSemiBold(), - ), - SizedBox(height: 4), - Text( - _showDetails ? widget.cardInfo!.cvv : '***', - style: textMediumSemiBold(), - ) - ], - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - S.of(context).expires, - style: textXSmallSemiBold(), - ), - SizedBox(height: 4), - Text( - '${widget.cardInfo?.expirationMonth ?? S.of(context).mm}/${widget.cardInfo?.expirationYear ?? S.of(context).yy}', - style: textMediumSemiBold(), - ) - ], - ), - ] - ], - ), - if (!widget.isCardSample) ...[ - SizedBox(height: 8), - Center( - child: InkWell( - onTap: () => _toggleVisibility(), - child: Text( - _showDetails ? S.of(context).hide_details : S.of(context).show_details, - style: textSmall(), - ), - ), - ), - ], - ], - ), - ); - } -} - -class _TitleSubtitleTile extends StatelessWidget { - const _TitleSubtitleTile({ - Key? key, - required this.title, - required this.subtitle, - }) : super(key: key); - - final String title; - final String subtitle; - - @override - Widget build(BuildContext context) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: textSmallSemiBold( - color: Theme.of(context).extension()!.tilesTextColor), - ), - SizedBox(height: 4), - Text( - subtitle, - style: textSmall( - color: Theme.of(context).extension()!.tilesTextColor), - ), - ], - ); - } -} diff --git a/lib/src/screens/ionia/cards/ionia_gift_card_detail_page.dart b/lib/src/screens/ionia/cards/ionia_gift_card_detail_page.dart deleted file mode 100644 index dcd1d54b4..000000000 --- a/lib/src/screens/ionia/cards/ionia_gift_card_detail_page.dart +++ /dev/null @@ -1,215 +0,0 @@ -import 'package:cake_wallet/core/execution_state.dart'; -import 'package:cake_wallet/themes/extensions/receive_page_theme.dart'; -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; -import 'package:cake_wallet/ionia/ionia_gift_card.dart'; -import 'package:cake_wallet/routes.dart'; -import 'package:cake_wallet/src/screens/base_page.dart'; -import 'package:cake_wallet/src/screens/ionia/widgets/ionia_alert_model.dart'; -import 'package:cake_wallet/src/screens/ionia/widgets/ionia_tile.dart'; -import 'package:cake_wallet/src/screens/ionia/widgets/text_icon_button.dart'; -import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; -import 'package:cake_wallet/src/widgets/primary_button.dart'; -import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; -import 'package:cake_wallet/typography.dart'; -import 'package:cake_wallet/utils/show_bar.dart'; -import 'package:cake_wallet/utils/show_pop_up.dart'; -import 'package:cake_wallet/utils/route_aware.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_gift_card_details_view_model.dart'; -import 'package:device_display_brightness/device_display_brightness.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:mobx/mobx.dart'; - -class IoniaGiftCardDetailPage extends BasePage { - IoniaGiftCardDetailPage(this.viewModel); - - final IoniaGiftCardDetailsViewModel viewModel; - - @override - Widget? leading(BuildContext context) { - if (ModalRoute.of(context)!.isFirst) { - return null; - } - - final _backButton = Icon( - Icons.arrow_back_ios, - color: Theme.of(context).extension()!.titleColor, - size: 16, - ); - return Padding( - padding: const EdgeInsets.only(left: 10.0), - child: SizedBox( - height: 37, - width: 37, - child: ButtonTheme( - minWidth: double.minPositive, - child: TextButton( - // FIX-ME: Style - //highlightColor: Colors.transparent, - //splashColor: Colors.transparent, - //padding: EdgeInsets.all(0), - onPressed: ()=> onClose(context), - child: _backButton), - ), - ), - ); - } - - @override - Widget middle(BuildContext context) { - return Text( - viewModel.giftCard.legalName, - style: textMediumSemiBold( - color: Theme.of(context).extension()!.titleColor), - ); - } - - @override - Widget body(BuildContext context) { - reaction((_) => viewModel.redeemState, (ExecutionState state) { - if (state is FailureState) { - WidgetsBinding.instance.addPostFrameCallback((_) { - showPopUp( - context: context, - builder: (BuildContext context) { - return AlertWithOneAction( - alertTitle: S.of(context).error, - alertContent: state.error, - buttonText: S.of(context).ok, - buttonAction: () => Navigator.of(context).pop()); - }); - }); - } - }); - - return ScrollableWithBottomSection( - contentPadding: EdgeInsets.all(24), - content: Column( - children: [ - if (viewModel.giftCard.barcodeUrl != null && viewModel.giftCard.barcodeUrl.isNotEmpty) - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 24.0, - vertical: 24, - ), - child: Image.network(viewModel.giftCard.barcodeUrl), - ), - SizedBox(height: 24), - buildIoniaTile( - context, - title: S.of(context).gift_card_number, - subTitle: viewModel.giftCard.cardNumber, - ), - if (viewModel.giftCard.cardPin.isNotEmpty) ...[ - Divider(height: 30), - buildIoniaTile( - context, - title: S.of(context).pin_number, - subTitle: viewModel.giftCard.cardPin, - ) - ], - Divider(height: 30), - Observer( - builder: (_) => buildIoniaTile( - context, - title: S.of(context).amount, - subTitle: viewModel.remainingAmount.toStringAsFixed(2), - )), - Divider(height: 50), - TextIconButton( - label: S.of(context).how_to_use_card, - onTap: () => _showHowToUseCard(context, viewModel.giftCard), - ), - ], - ), - bottomSection: Padding( - padding: EdgeInsets.only(bottom: 12), - child: Observer( - builder: (_) { - if (!viewModel.giftCard.isEmpty) { - return Column( - children: [ - PrimaryButton( - onPressed: () async { - await Navigator.of(context).pushNamed( - Routes.ioniaMoreOptionsPage, - arguments: [viewModel.giftCard]) as String?; - viewModel.refeshCard(); - }, - text: S.of(context).more_options, - color: Theme.of(context).cardColor, - textColor: Theme.of(context).extension()!.titleColor, - ), - SizedBox(height: 12), - LoadingPrimaryButton( - isLoading: viewModel.redeemState is IsExecutingState, - onPressed: () => viewModel.redeem().then( - (_) { - Navigator.of(context).pushNamedAndRemoveUntil( - Routes.ioniaManageCardsPage, (route) => route.isFirst); - }, - ), - text: S.of(context).mark_as_redeemed, - color: Theme.of(context).primaryColor, - textColor: Colors.white, - ), - ], - ); - } - - return Container(); - }, - ), - ), - ); - } - - Widget buildIoniaTile(BuildContext context, {required String title, required String subTitle}) { - return IoniaTile( - title: title, - subTitle: subTitle, - onTap: () { - Clipboard.setData(ClipboardData(text: subTitle)); - showBar(context, S.of(context).transaction_details_copied(title)); - }); - } - - void _showHowToUseCard( - BuildContext context, - IoniaGiftCard merchant, - ) { - showPopUp( - context: context, - builder: (BuildContext context) { - return IoniaAlertModal( - title: S.of(context).how_to_use_card, - content: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: viewModel.giftCard.instructions - .map((instruction) { - return [ - Padding( - padding: EdgeInsets.all(10), - child: Text( - instruction.header, - style: textLargeSemiBold( - color: Theme.of(context).extension()!.tilesTextColor, - ), - )), - Text( - instruction.body, - style: textMedium( - color: Theme.of(context).extension()!.tilesTextColor, - ), - ) - ]; - }) - .expand((e) => e) - .toList()), - actionTitle: S.of(context).got_it, - ); - }); - } -} diff --git a/lib/src/screens/ionia/cards/ionia_more_options_page.dart b/lib/src/screens/ionia/cards/ionia_more_options_page.dart deleted file mode 100644 index eb6ed8860..000000000 --- a/lib/src/screens/ionia/cards/ionia_more_options_page.dart +++ /dev/null @@ -1,91 +0,0 @@ -import 'package:cake_wallet/ionia/ionia_gift_card.dart'; -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; -import 'package:cake_wallet/routes.dart'; -import 'package:cake_wallet/src/screens/base_page.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart'; -import 'package:cake_wallet/typography.dart'; -import 'package:flutter/material.dart'; - -class IoniaMoreOptionsPage extends BasePage { - IoniaMoreOptionsPage(this.giftCard); - - final IoniaGiftCard giftCard; - - @override - Widget middle(BuildContext context) { - return Text( - S.current.more_options, - style: textMediumSemiBold( - color: Theme.of(context).extension()!.titleColor, - ), - ); - } - - @override - Widget body(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - SizedBox( - height: 10, - ), - Center( - child: Text( - S.of(context).choose_from_available_options, - style: textMedium( - color: Theme.of(context).extension()!.titleColor, - ), - ), - ), - SizedBox(height: 40), - InkWell( - onTap: () async { - final amount = await Navigator.of(context) - .pushNamed(Routes.ioniaCustomRedeemPage, arguments: [giftCard]) as String?; - if (amount != null && amount.isNotEmpty) { - Navigator.pop(context); - } - }, - child: _GradiantContainer( - content: Padding( - padding: const EdgeInsets.only(top: 24, left: 20, right: 24, bottom: 50), - child: Text( - S.of(context).custom_redeem_amount, - style: textXLargeSemiBold(), - ), - ), - ), - ) - ], - ), - ); - } -} - -class _GradiantContainer extends StatelessWidget { - const _GradiantContainer({Key? key, required this.content}) : super(key: key); - - final Widget content; - - @override - Widget build(BuildContext context) { - return Container( - child: content, - padding: EdgeInsets.all(24), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(15), - gradient: LinearGradient( - colors: [ - Theme.of(context).extension()!.secondGradientBackgroundColor, - Theme.of(context).extension()!.firstGradientBackgroundColor, - ], - begin: Alignment.topRight, - end: Alignment.bottomLeft, - ), - ), - ); - } -} diff --git a/lib/src/screens/ionia/cards/ionia_payment_status_page.dart b/lib/src/screens/ionia/cards/ionia_payment_status_page.dart deleted file mode 100644 index dce976444..000000000 --- a/lib/src/screens/ionia/cards/ionia_payment_status_page.dart +++ /dev/null @@ -1,222 +0,0 @@ -import 'package:cake_wallet/ionia/ionia_gift_card.dart'; -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; -import 'package:cake_wallet/routes.dart'; -import 'package:cake_wallet/src/screens/base_page.dart'; -import 'package:cake_wallet/src/widgets/primary_button.dart'; -import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; -import 'package:cake_wallet/typography.dart'; -import 'package:cake_wallet/utils/show_bar.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_payment_status_view_model.dart'; -import 'package:flutter/material.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:mobx/mobx.dart'; -import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart'; - -class IoniaPaymentStatusPage extends BasePage { - IoniaPaymentStatusPage(this.viewModel); - - final IoniaPaymentStatusViewModel viewModel; - - @override - Widget middle(BuildContext context) { - return Text( - S.of(context).generating_gift_card, - textAlign: TextAlign.center, - style: textMediumSemiBold( - color: Theme.of(context).extension()!.titleColor)); - } - - @override - Widget body(BuildContext context) { - return _IoniaPaymentStatusPageBody(viewModel); - } -} - -class _IoniaPaymentStatusPageBody extends StatefulWidget { - _IoniaPaymentStatusPageBody(this.viewModel); - - final IoniaPaymentStatusViewModel viewModel; - - @override - _IoniaPaymentStatusPageBodyBodyState createState() => _IoniaPaymentStatusPageBodyBodyState(); -} - -class _IoniaPaymentStatusPageBodyBodyState extends State<_IoniaPaymentStatusPageBody> { - ReactionDisposer? _onGiftCardReaction; - - @override - void initState() { - if (widget.viewModel.giftCard != null) { - WidgetsBinding.instance.addPostFrameCallback((_) { - Navigator.of(context) - .pushReplacementNamed(Routes.ioniaGiftCardDetailPage, arguments: [widget.viewModel.giftCard]); - }); - } - - _onGiftCardReaction = reaction((_) => widget.viewModel.giftCard, (IoniaGiftCard? giftCard) { - WidgetsBinding.instance.addPostFrameCallback((_) { - Navigator.of(context) - .pushReplacementNamed(Routes.ioniaGiftCardDetailPage, arguments: [giftCard]); - }); - }); - - super.initState(); - } - - @override - void dispose() { - _onGiftCardReaction?.reaction.dispose(); - widget.viewModel.timer?.cancel(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return ScrollableWithBottomSection( - contentPadding: EdgeInsets.all(24), - content: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Row(children: [ - Padding( - padding: EdgeInsets.only(right: 10), - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: Colors.green), - height: 10, - width: 10)), - Text( - S.of(context).awaiting_payment_confirmation, - style: textLargeSemiBold( - color: Theme.of(context).extension()!.titleColor)) - ]), - SizedBox(height: 40), - Row(children: [ - SizedBox(width: 20), - Expanded(child: - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - ...widget.viewModel - .committedInfo - .transactions - .map((transaction) => buildDescriptionTileWithCopy(context, S.of(context).transaction_details_transaction_id, transaction.id)), - if (widget.viewModel.paymentInfo.ioniaOrder.id != null) - ...[Divider(height: 30), - buildDescriptionTileWithCopy(context, S.of(context).order_id, widget.viewModel.paymentInfo.ioniaOrder.id)], - if (widget.viewModel.paymentInfo.ioniaOrder.paymentId != null) - ...[Divider(height: 30), - buildDescriptionTileWithCopy(context, S.of(context).payment_id, widget.viewModel.paymentInfo.ioniaOrder.paymentId)], - ])) - ]), - SizedBox(height: 40), - Observer(builder: (_) { - if (widget.viewModel.giftCard != null) { - return Container( - padding: EdgeInsets.only(top: 40), - child: Row(children: [ - Padding( - padding: EdgeInsets.only(right: 10,), - child: Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: Colors.green), - height: 10, - width: 10)), - Text( - S.of(context).gift_card_is_generated, - style: textLargeSemiBold( - color: Theme.of(context).extension()!.titleColor)) - ])); - } - - return Row(children: [ - Padding( - padding: EdgeInsets.only(right: 10), - child: Observer(builder: (_) { - return Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(10), - color: widget.viewModel.giftCard == null ? Colors.grey : Colors.green), - height: 10, - width: 10); - })), - Text( - S.of(context).generating_gift_card, - style: textLargeSemiBold( - color: Theme.of(context).extension()!.titleColor))]); - }), - ], - ), - bottomSection: Padding( - padding: EdgeInsets.only(bottom: 12), - child: Column(children: [ - Container( - padding: EdgeInsets.only(left: 40, right: 40, bottom: 20), - child: Text( - widget.viewModel.payingByBitcoin ? S.of(context).bitcoin_payments_require_1_confirmation - : S.of(context).proceed_after_one_minute, - style: textMedium( - color: Theme.of(context).extension()!.titleColor, - ).copyWith(fontWeight: FontWeight.w500), - textAlign: TextAlign.center, - )), - Observer(builder: (_) { - if (widget.viewModel.giftCard != null) { - return PrimaryButton( - onPressed: () => Navigator.of(context) - .pushReplacementNamed( - Routes.ioniaGiftCardDetailPage, - arguments: [widget.viewModel.giftCard]), - text: S.of(context).open_gift_card, - color: Theme.of(context).primaryColor, - textColor: Colors.white); - } - - return PrimaryButton( - onPressed: () => Navigator.of(context).pushNamed(Routes.support), - text: S.of(context).contact_support, - color: Theme.of(context).cardColor, - textColor: Theme.of(context).extension()!.titleColor); - }) - ]) - ), - ); - } - - Widget buildDescriptionTile(BuildContext context, String title, String subtitle, VoidCallback onTap) { - return GestureDetector( - onTap: () => onTap(), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - title, - style: textXSmall( - color: Theme.of(context).extension()!.detailsTitlesColor, - ), - ), - SizedBox(height: 8), - Text( - subtitle, - style: textMedium( - color: Theme.of(context).extension()!.titleColor, - ), - ), - ], - )); - } - - Widget buildDescriptionTileWithCopy(BuildContext context, String title, String subtitle) { - return buildDescriptionTile(context, title, subtitle, () { - Clipboard.setData(ClipboardData(text: subtitle)); - showBar(context, - S.of(context).transaction_details_copied(title)); - }); - } -} \ No newline at end of file diff --git a/lib/src/screens/ionia/ionia.dart b/lib/src/screens/ionia/ionia.dart deleted file mode 100644 index bdc2065a9..000000000 --- a/lib/src/screens/ionia/ionia.dart +++ /dev/null @@ -1,9 +0,0 @@ -export 'auth/ionia_welcome_page.dart'; -export 'auth/ionia_create_account_page.dart'; -export 'auth/ionia_login_page.dart'; -export 'auth/ionia_verify_otp_page.dart'; -export 'cards/ionia_activate_debit_card_page.dart'; -export 'cards/ionia_buy_card_detail_page.dart'; -export 'cards/ionia_manage_cards_page.dart'; -export 'cards/ionia_debit_card_page.dart'; -export 'cards/ionia_buy_gift_card.dart'; diff --git a/lib/src/screens/ionia/widgets/card_item.dart b/lib/src/screens/ionia/widgets/card_item.dart deleted file mode 100644 index 405de5adc..000000000 --- a/lib/src/screens/ionia/widgets/card_item.dart +++ /dev/null @@ -1,144 +0,0 @@ -import 'package:cake_wallet/src/widgets/discount_badge.dart'; -import 'package:flutter/material.dart'; - -class CardItem extends StatelessWidget { - CardItem({ - required this.title, - required this.subTitle, - required this.backgroundColor, - required this.titleColor, - required this.subtitleColor, - this.hideBorder = false, - this.discount = 0.0, - this.isAmount = false, - this.discountBackground, - this.onTap, - this.logoUrl, - }); - - final VoidCallback? onTap; - final String title; - final String subTitle; - final String? logoUrl; - final double discount; - final bool isAmount; - final bool hideBorder; - final Color backgroundColor; - final Color titleColor; - final Color subtitleColor; - final AssetImage? discountBackground; - - @override - Widget build(BuildContext context) { - return InkWell( - onTap: onTap, - child: Stack( - children: [ - Container( - padding: EdgeInsets.all(12), - width: double.infinity, - decoration: BoxDecoration( - color: backgroundColor, - borderRadius: BorderRadius.circular(20), - border: hideBorder ? Border.symmetric(horizontal: BorderSide.none, vertical: BorderSide.none) : Border.all( - color: Colors.white.withOpacity(0.20), - ), - ), - child: Row( - children: [ - if (logoUrl != null) ...[ - ClipOval( - child: Image.network( - logoUrl!, - width: 40.0, - height: 40.0, - fit: BoxFit.cover, - loadingBuilder: (BuildContext _, Widget child, ImageChunkEvent? loadingProgress) { - if (loadingProgress == null) { - return child; - } else { - return _PlaceholderContainer(text: 'Logo'); - } - }, - errorBuilder: (_, __, ___) => _PlaceholderContainer(text: '!'), - ), - ), - SizedBox(width: 5), - ], - Column( - crossAxisAlignment: (subTitle?.isEmpty ?? false) - ? CrossAxisAlignment.center - : CrossAxisAlignment.start, - children: [ - SizedBox( - width: 200, - child: Text( - title, - overflow: TextOverflow.ellipsis, - style: TextStyle( - color: titleColor, - fontSize: 20, - fontWeight: FontWeight.w900, - ), - ), - ), - if (subTitle?.isNotEmpty ?? false) - Padding( - padding: EdgeInsets.only(top: 5), - child: Text( - subTitle, - style: TextStyle( - color: subtitleColor, - fontWeight: FontWeight.w500, - fontFamily: 'Lato')), - ) - ], - ), - ], - ), - ), - if (discount != 0.0) - Align( - alignment: Alignment.topRight, - child: Padding( - padding: const EdgeInsets.only(top: 20.0), - child: DiscountBadge( - percentage: discount, - isAmount: isAmount, - discountBackground: discountBackground, - ), - ), - ), - ], - ), - ); - } -} - -class _PlaceholderContainer extends StatelessWidget { - const _PlaceholderContainer({required this.text}); - - final String text; - - @override - Widget build(BuildContext context) { - return Container( - height: 42, - width: 42, - child: Center( - child: Text( - text, - style: TextStyle( - color: Colors.black, - fontSize: 12, - fontWeight: FontWeight.w900, - ), - ), - ), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(100), - ), - ); - } -} diff --git a/lib/src/screens/ionia/widgets/ionia_filter_modal.dart b/lib/src/screens/ionia/widgets/ionia_filter_modal.dart deleted file mode 100644 index 8a6820fcd..000000000 --- a/lib/src/screens/ionia/widgets/ionia_filter_modal.dart +++ /dev/null @@ -1,132 +0,0 @@ -import 'package:cake_wallet/src/screens/ionia/widgets/rounded_checkbox.dart'; -import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; -import 'package:cake_wallet/src/widgets/alert_background.dart'; -import 'package:cake_wallet/typography.dart'; -import 'package:cake_wallet/generated/i18n.dart'; -import 'package:cake_wallet/view_model/ionia/ionia_gift_cards_list_view_model.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_mobx/flutter_mobx.dart'; -import 'package:cake_wallet/palette.dart'; -import 'package:cake_wallet/themes/extensions/menu_theme.dart'; - -class IoniaFilterModal extends StatelessWidget { - IoniaFilterModal({required this.ioniaGiftCardsListViewModel}){ - ioniaGiftCardsListViewModel.resetIoniaCategories(); - } - - final IoniaGiftCardsListViewModel ioniaGiftCardsListViewModel; - - @override - Widget build(BuildContext context) { - final searchIcon = Padding( - padding: EdgeInsets.all(10), - child: Image.asset( - 'assets/images/mini_search_icon.png', - color: Theme.of(context).primaryColor, - ), - ); - return Scaffold( - resizeToAvoidBottomInset: false, - body: AlertBackground( - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - SizedBox(height: 10), - Container( - padding: EdgeInsets.only(top: 24, bottom: 20), - margin: EdgeInsets.all(24), - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.background, - borderRadius: BorderRadius.circular(30), - ), - child: Column( - children: [ - SizedBox( - height: 40, - child: Padding( - padding: const EdgeInsets.only(left: 24, right: 24), - child: TextField( - onChanged: ioniaGiftCardsListViewModel.onSearchFilter, - style: textMedium( - color: Theme.of(context).extension()!.titleColor, - ), - decoration: InputDecoration( - filled: true, - prefixIcon: searchIcon, - hintText: S.of(context).search_category, - contentPadding: EdgeInsets.only(bottom: 5), - fillColor: Theme.of(context).extension()!.dividerColor.withOpacity(0.5), - border: OutlineInputBorder( - borderSide: BorderSide.none, - borderRadius: BorderRadius.circular(8), - ), - ), - ), - ), - ), - SizedBox(height: 10), - Divider(thickness: 2), - SizedBox(height: 24), - Observer(builder: (_) { - return ListView.builder( - padding: EdgeInsets.zero, - shrinkWrap: true, - itemCount: ioniaGiftCardsListViewModel.ioniaCategories.length, - itemBuilder: (_, index) { - final category = ioniaGiftCardsListViewModel.ioniaCategories[index]; - return Padding( - padding: const EdgeInsets.only(left: 24, right: 24, bottom: 24), - child: InkWell( - onTap: () => ioniaGiftCardsListViewModel.setSelectedFilter(category), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Image.asset( - category.iconPath, - color: Theme.of(context).extension()!.titleColor, - ), - SizedBox(width: 10), - Text(category.title, - style: textSmall( - color: Theme.of(context).extension()!.titleColor, - ).copyWith(fontWeight: FontWeight.w500)), - ], - ), - Observer(builder: (_) { - final value = ioniaGiftCardsListViewModel.selectedIndices; - return RoundedCheckbox( - value: value.contains(category), - ); - }), - ], - ), - ), - ); - }, - ); - }), - ], - ), - ), - InkWell( - onTap: () => Navigator.pop(context), - child: Container( - margin: EdgeInsets.only(bottom: 40), - child: CircleAvatar( - child: Icon( - Icons.close, - color: Palette.darkBlueCraiola, - ), - backgroundColor: Colors.white, - ), - ), - ) - ], - ), - ), - ); - } -} diff --git a/lib/src/screens/send/widgets/confirm_sending_alert.dart b/lib/src/screens/send/widgets/confirm_sending_alert.dart index ce711ce8b..3af1c3f8c 100644 --- a/lib/src/screens/send/widgets/confirm_sending_alert.dart +++ b/lib/src/screens/send/widgets/confirm_sending_alert.dart @@ -12,6 +12,7 @@ class ConfirmSendingAlert extends BaseAlertDialog { {required this.alertTitle, this.paymentId, this.paymentIdValue, + this.expirationTime, required this.amount, required this.amountValue, required this.fiatAmountValue, @@ -28,11 +29,13 @@ class ConfirmSendingAlert extends BaseAlertDialog { this.alertLeftActionButtonTextColor, this.alertRightActionButtonTextColor, this.alertLeftActionButtonColor, - this.alertRightActionButtonColor}); + this.alertRightActionButtonColor, + this.onDispose}); final String alertTitle; final String? paymentId; final String? paymentIdValue; + final String? expirationTime; final String amount; final String amountValue; final String fiatAmountValue; @@ -50,6 +53,7 @@ class ConfirmSendingAlert extends BaseAlertDialog { final Color? alertRightActionButtonTextColor; final Color? alertLeftActionButtonColor; final Color? alertRightActionButtonColor; + final Function? onDispose; @override String get titleText => alertTitle; @@ -88,6 +92,7 @@ class ConfirmSendingAlert extends BaseAlertDialog { Widget content(BuildContext context) => ConfirmSendingAlertContent( paymentId: paymentId, paymentIdValue: paymentIdValue, + expirationTime: expirationTime, amount: amount, amountValue: amountValue, fiatAmountValue: fiatAmountValue, @@ -95,13 +100,15 @@ class ConfirmSendingAlert extends BaseAlertDialog { feeRate: feeRate, feeValue: feeValue, feeFiatAmount: feeFiatAmount, - outputs: outputs); + outputs: outputs, + onDispose: onDispose); } class ConfirmSendingAlertContent extends StatefulWidget { ConfirmSendingAlertContent( {this.paymentId, this.paymentIdValue, + this.expirationTime, required this.amount, required this.amountValue, required this.fiatAmountValue, @@ -109,10 +116,12 @@ class ConfirmSendingAlertContent extends StatefulWidget { this.feeRate, required this.feeValue, required this.feeFiatAmount, - required this.outputs}); + required this.outputs, + required this.onDispose}) {} final String? paymentId; final String? paymentIdValue; + final String? expirationTime; final String amount; final String amountValue; final String fiatAmountValue; @@ -121,11 +130,13 @@ class ConfirmSendingAlertContent extends StatefulWidget { final String feeValue; final String feeFiatAmount; final List outputs; + final Function? onDispose; @override ConfirmSendingAlertContentState createState() => ConfirmSendingAlertContentState( paymentId: paymentId, paymentIdValue: paymentIdValue, + expirationTime: expirationTime, amount: amount, amountValue: amountValue, fiatAmountValue: fiatAmountValue, @@ -133,13 +144,15 @@ class ConfirmSendingAlertContent extends StatefulWidget { feeRate: feeRate, feeValue: feeValue, feeFiatAmount: feeFiatAmount, - outputs: outputs); + outputs: outputs, + onDispose: onDispose); } class ConfirmSendingAlertContentState extends State { ConfirmSendingAlertContentState( {this.paymentId, this.paymentIdValue, + this.expirationTime, required this.amount, required this.amountValue, required this.fiatAmountValue, @@ -147,7 +160,8 @@ class ConfirmSendingAlertContentState extends State this.feeRate, required this.feeValue, required this.feeFiatAmount, - required this.outputs}) + required this.outputs, + this.onDispose}) : recipientTitle = '' { recipientTitle = outputs.length > 1 ? S.current.transaction_details_recipient_address @@ -156,6 +170,7 @@ class ConfirmSendingAlertContentState extends State final String? paymentId; final String? paymentIdValue; + final String? expirationTime; final String amount; final String amountValue; final String fiatAmountValue; @@ -164,6 +179,7 @@ class ConfirmSendingAlertContentState extends State final String feeValue; final String feeFiatAmount; final List outputs; + final Function? onDispose; final double backgroundHeight = 160; final double thumbHeight = 72; @@ -172,6 +188,12 @@ class ConfirmSendingAlertContentState extends State String recipientTitle; bool showScrollbar = false; + @override + void dispose() { + if (onDispose != null) onDispose!(); + super.dispose(); + } + @override Widget build(BuildContext context) { controller.addListener(() { @@ -217,14 +239,18 @@ class ConfirmSendingAlertContentState extends State Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ - Text( - paymentIdValue!, - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - fontFamily: 'Lato', - color: Theme.of(context).extension()!.titleColor, - decoration: TextDecoration.none, + Container( + width: 160, + child: Text( + paymentIdValue!, + textAlign: TextAlign.right, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + fontFamily: 'Lato', + color: Theme.of(context).extension()!.titleColor, + decoration: TextDecoration.none, + ), ), ), ], @@ -232,6 +258,8 @@ class ConfirmSendingAlertContentState extends State ], ), ), + if (widget.expirationTime != null) + ExpirationTimeWidget(expirationTime: widget.expirationTime!), Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -468,3 +496,46 @@ class ConfirmSendingAlertContentState extends State ]); } } + +class ExpirationTimeWidget extends StatelessWidget { + const ExpirationTimeWidget({ + required this.expirationTime, + }); + + final String expirationTime; + + @override + Widget build(BuildContext context) { + return Padding( + padding: EdgeInsets.only(bottom: 32), + child: Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + S.current.offer_expires_in, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.normal, + fontFamily: 'Lato', + color: Theme.of(context).extension()!.titleColor, + decoration: TextDecoration.none, + ), + ), + Text( + expirationTime, + textAlign: TextAlign.right, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.w600, + fontFamily: 'Lato', + color: Theme.of(context).extension()!.titleColor, + decoration: TextDecoration.none, + ), + ) + ], + ), + ); + } +} diff --git a/lib/src/widgets/number_text_fild_widget.dart b/lib/src/widgets/number_text_fild_widget.dart new file mode 100644 index 000000000..52e7e23cf --- /dev/null +++ b/lib/src/widgets/number_text_fild_widget.dart @@ -0,0 +1,145 @@ +import 'package:cake_wallet/themes/extensions/cake_text_theme.dart'; +import 'package:cake_wallet/typography.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; + +class NumberTextField extends StatefulWidget { + final TextEditingController? controller; + final FocusNode? focusNode; + final int min; + final int max; + final int step; + final double arrowsWidth; + final double arrowsHeight; + final EdgeInsets contentPadding; + final double borderWidth; + final ValueChanged? onChanged; + + const NumberTextField({ + Key? key, + this.controller, + this.focusNode, + this.min = 0, + this.max = 999, + this.step = 1, + this.arrowsWidth = 24, + this.arrowsHeight = kMinInteractiveDimension, + this.contentPadding = const EdgeInsets.symmetric(horizontal: 8), + this.borderWidth = 2, + this.onChanged, + }) : super(key: key); + + @override + State createState() => _NumberTextFieldState(); +} + +class _NumberTextFieldState extends State { + late TextEditingController _controller; + late FocusNode _focusNode; + bool _canGoUp = false; + bool _canGoDown = false; + + @override + void initState() { + super.initState(); + _controller = widget.controller ?? TextEditingController(); + _focusNode = widget.focusNode ?? FocusNode(); + _updateArrows(int.tryParse(_controller.text)); + } + + @override + void didUpdateWidget(covariant NumberTextField oldWidget) { + super.didUpdateWidget(oldWidget); + _controller = widget.controller ?? _controller; + _focusNode = widget.focusNode ?? _focusNode; + _updateArrows(int.tryParse(_controller.text)); + } + + @override + Widget build(BuildContext context) => TextField( + style: textMediumSemiBold(color: Theme.of(context).extension()!.titleColor), + enableInteractiveSelection: false, + textAlign: TextAlign.center, + textAlignVertical: TextAlignVertical.bottom, + controller: _controller, + focusNode: _focusNode, + textInputAction: TextInputAction.done, + keyboardType: TextInputType.number, + maxLength: widget.max.toString().length + (widget.min.isNegative ? 1 : 0), + decoration: InputDecoration( + border: InputBorder.none, + contentPadding: EdgeInsets.all(0), + fillColor: Colors.transparent, + counterText: '', + isDense: true, + filled: true, + suffixIconConstraints: BoxConstraints( + maxHeight: widget.arrowsHeight, + maxWidth: widget.arrowsWidth + widget.contentPadding.right), + prefixIconConstraints: BoxConstraints( + maxHeight: widget.arrowsHeight, + maxWidth: widget.arrowsWidth + widget.contentPadding.left), + prefixIcon: Material( + type: MaterialType.transparency, + child: InkWell( + child: Container( + width: widget.arrowsWidth, + alignment: Alignment.bottomCenter, + child: Icon(Icons.arrow_left_outlined, size: widget.arrowsWidth)), + onTap: _canGoDown ? () => _update(false) : null)), + suffixIcon: Material( + type: MaterialType.transparency, + child: InkWell( + child: Container( + width: widget.arrowsWidth, + alignment: Alignment.bottomCenter, + child: Icon(Icons.arrow_right_outlined, size: widget.arrowsWidth)), + onTap: _canGoUp ? () => _update(true) : null))), + maxLines: 1, + onChanged: (value) { + final intValue = int.tryParse(value); + widget.onChanged?.call(intValue); + _updateArrows(intValue); + }, + inputFormatters: [_NumberTextInputFormatter(widget.min, widget.max)]); + + void _update(bool up) { + var intValue = int.tryParse(_controller.text); + intValue == null ? intValue = widget.min : intValue += up ? widget.step : -widget.step; + intValue = intValue.clamp(widget.min, widget.max); // Ensure intValue is within range + _controller.text = intValue.toString(); + + // Manually call the onChanged callback after updating the controller's text + widget.onChanged?.call(intValue); + + _updateArrows(intValue); + _focusNode.requestFocus(); + } + + void _updateArrows(int? value) { + final canGoUp = value == null || value < widget.max; + final canGoDown = value == null || value > widget.min; + if (_canGoUp != canGoUp || _canGoDown != canGoDown) + setState(() { + _canGoUp = canGoUp; + _canGoDown = canGoDown; + }); + } +} + +class _NumberTextInputFormatter extends TextInputFormatter { + final int min; + final int max; + + _NumberTextInputFormatter(this.min, this.max); + + @override + TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) { + if (const ['-', ''].contains(newValue.text)) return newValue; + final intValue = int.tryParse(newValue.text); + if (intValue == null) return oldValue; + if (intValue < min) return newValue.copyWith(text: min.toString()); + if (intValue > max) return newValue.copyWith(text: max.toString()); + return newValue.copyWith(text: intValue.toString()); + } +} diff --git a/lib/view_model/cake_pay/cake_pay_account_view_model.dart b/lib/view_model/cake_pay/cake_pay_account_view_model.dart new file mode 100644 index 000000000..85c68c9fb --- /dev/null +++ b/lib/view_model/cake_pay/cake_pay_account_view_model.dart @@ -0,0 +1,20 @@ +import 'package:cake_wallet/cake_pay/cake_pay_service.dart'; +import 'package:mobx/mobx.dart'; + +part 'cake_pay_account_view_model.g.dart'; + +class CakePayAccountViewModel = CakePayAccountViewModelBase with _$CakePayAccountViewModel; + +abstract class CakePayAccountViewModelBase with Store { + CakePayAccountViewModelBase({required this.cakePayService}) : email = '' { + cakePayService.getUserEmail().then((email) => this.email = email ?? ''); + } + + final CakePayService cakePayService; + + @observable + String email; + + @action + Future logout() async => cakePayService.logout(email); +} diff --git a/lib/view_model/cake_pay/cake_pay_auth_view_model.dart b/lib/view_model/cake_pay/cake_pay_auth_view_model.dart new file mode 100644 index 000000000..f23d43f1f --- /dev/null +++ b/lib/view_model/cake_pay/cake_pay_auth_view_model.dart @@ -0,0 +1,51 @@ +import 'package:cake_wallet/cake_pay/cake_pay_states.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_service.dart'; +import 'package:mobx/mobx.dart'; + +part 'cake_pay_auth_view_model.g.dart'; + +class CakePayAuthViewModel = CakePayAuthViewModelBase with _$CakePayAuthViewModel; + +abstract class CakePayAuthViewModelBase with Store { + CakePayAuthViewModelBase({required this.cakePayService}) + : userVerificationState = CakePayUserVerificationStateInitial(), + otpState = CakePayOtpSendDisabled(), + email = '', + otp = ''; + + final CakePayService cakePayService; + + @observable + CakePayUserVerificationState userVerificationState; + + @observable + CakePayOtpState otpState; + + @observable + String email; + + @observable + String otp; + + @action + Future verifyEmail(String code) async { + try { + otpState = CakePayOtpValidating(); + await cakePayService.verifyEmail(code); + otpState = CakePayOtpSuccess(); + } catch (_) { + otpState = CakePayOtpFailure(error: 'Invalid OTP. Try again'); + } + } + + @action + Future logIn(String email) async { + try { + userVerificationState = CakePayUserVerificationStateLoading(); + await cakePayService.logIn(email); + userVerificationState = CakePayUserVerificationStateSuccess(); + } catch (e) { + userVerificationState = CakePayUserVerificationStateFailure(error: e.toString()); + } + } +} diff --git a/lib/view_model/cake_pay/cake_pay_buy_card_view_model.dart b/lib/view_model/cake_pay/cake_pay_buy_card_view_model.dart new file mode 100644 index 000000000..4fd97213d --- /dev/null +++ b/lib/view_model/cake_pay/cake_pay_buy_card_view_model.dart @@ -0,0 +1,48 @@ +import 'package:cake_wallet/cake_pay/cake_pay_card.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_vendor.dart'; +import 'package:mobx/mobx.dart'; + +part 'cake_pay_buy_card_view_model.g.dart'; + +class CakePayBuyCardViewModel = CakePayBuyCardViewModelBase with _$CakePayBuyCardViewModel; + +abstract class CakePayBuyCardViewModelBase with Store { + CakePayBuyCardViewModelBase({required this.vendor}) + : amount = vendor.card!.denominations.isNotEmpty + ? double.parse(vendor.card!.denominations.first) + : 0, + quantity = 1, + min = double.parse(vendor.card!.minValue ?? '0'), + max = double.parse(vendor.card!.maxValue ?? '0'), + card = vendor.card!; + + final CakePayVendor vendor; + final CakePayCard card; + + final double min; + final double max; + + bool get isDenominationSelected => card.denominations.isNotEmpty; + + @observable + double amount; + + @observable + int quantity; + + @computed + bool get isEnablePurchase => + (amount >= min && amount <= max) || (isDenominationSelected && quantity > 0); + + @computed + double get totalAmount => amount * quantity; + + @action + void onQuantityChanged(int? input) => quantity = input ?? 1; + + @action + void onAmountChanged(String input) { + if (input.isEmpty) return; + amount = double.parse(input.replaceAll(',', '.')); + } +} diff --git a/lib/view_model/cake_pay/cake_pay_cards_list_view_model.dart b/lib/view_model/cake_pay/cake_pay_cards_list_view_model.dart new file mode 100644 index 000000000..d0483596e --- /dev/null +++ b/lib/view_model/cake_pay/cake_pay_cards_list_view_model.dart @@ -0,0 +1,221 @@ +import 'package:cake_wallet/cake_pay/cake_pay_service.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_states.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_vendor.dart'; +import 'package:cake_wallet/generated/i18n.dart'; +import 'package:cake_wallet/view_model/dashboard/dropdown_filter_item.dart'; +import 'package:cake_wallet/view_model/dashboard/filter_item.dart'; +import 'package:mobx/mobx.dart'; + +part 'cake_pay_cards_list_view_model.g.dart'; + +class CakePayCardsListViewModel = CakePayCardsListViewModelBase with _$CakePayCardsListViewModel; + +abstract class CakePayCardsListViewModelBase with Store { + CakePayCardsListViewModelBase({ + required this.cakePayService, + }) : cardState = CakePayCardsStateNoCards(), + cakePayVendors = [], + availableCountries = [], + page = 1, + selectedCountry = 'USA', + displayPrepaidCards = true, + displayGiftCards = true, + displayDenominationsCards = true, + displayCustomValueCards = true, + scrollOffsetFromTop = 0.0, + vendorsState = InitialCakePayVendorLoadingState(), + createCardState = CakePayCreateCardState(), + searchString = '', + CakePayVendorList = [] { + initialization(); + } + + void initialization() async { + await getCountries(); + selectedCountry = availableCountries.first; + getVendors(); + } + + final CakePayService cakePayService; + + List CakePayVendorList; + + Map> get createFilterItems => { + S.current.filter_by: [ + FilterItem( + value: () => displayPrepaidCards, + caption: S.current.prepaid_cards, + onChanged: togglePrepaidCards), + FilterItem( + value: () => displayGiftCards, + caption: S.current.gift_cards, + onChanged: toggleGiftCards), + ], + S.current.value_type: [ + FilterItem( + value: () => displayDenominationsCards, + caption: S.current.denominations, + onChanged: toggleDenominationsCards), + FilterItem( + value: () => displayCustomValueCards, + caption: S.current.custom_value, + onChanged: toggleCustomValueCards), + ], + S.current.countries: [ + DropdownFilterItem( + items: availableCountries, + caption: '', + selectedItem: selectedCountry, + onItemSelected: (String value) => setSelectedCountry(value), + ), + ] + }; + + String searchString; + + int page; + + late String _initialSelectedCountry; + + late bool _initialDisplayPrepaidCards; + + late bool _initialDisplayGiftCards; + + late bool _initialDisplayDenominationsCards; + + late bool _initialDisplayCustomValueCards; + + @observable + double scrollOffsetFromTop; + + @observable + CakePayCreateCardState createCardState; + + @observable + CakePayCardsState cardState; + + @observable + CakePayVendorState vendorsState; + + @observable + bool hasMoreDataToFetch = true; + + @observable + bool isLoadingNextPage = false; + + @observable + List cakePayVendors; + + @observable + List availableCountries; + + @observable + bool displayPrepaidCards; + + @observable + bool displayGiftCards; + + @observable + bool displayDenominationsCards; + + @observable + bool displayCustomValueCards; + + @observable + String selectedCountry; + + bool get hasFiltersChanged => + selectedCountry != _initialSelectedCountry || + displayPrepaidCards != _initialDisplayPrepaidCards || + displayGiftCards != _initialDisplayGiftCards || + displayDenominationsCards != _initialDisplayDenominationsCards || + displayCustomValueCards != _initialDisplayCustomValueCards; + + Future getCountries() async { + availableCountries = await cakePayService.getCountries(); + } + + @action + Future getVendors({ + String? text, + int? currentPage, + }) async { + vendorsState = CakePayVendorLoadingState(); + searchString = text ?? ''; + var newVendors = await cakePayService.getVendors( + country: selectedCountry, + page: currentPage ?? page, + search: searchString, + giftCards: displayGiftCards, + prepaidCards: displayPrepaidCards, + custom: displayCustomValueCards, + onDemand: displayDenominationsCards); + + cakePayVendors = CakePayVendorList = newVendors; + + vendorsState = CakePayVendorLoadedState(); + } + + @action + Future fetchNextPage() async { + if (vendorsState is CakePayVendorLoadingState || !hasMoreDataToFetch || isLoadingNextPage) + return; + + isLoadingNextPage = true; + page++; + try { + var newVendors = await cakePayService.getVendors( + country: selectedCountry, + page: page, + search: searchString, + giftCards: displayGiftCards, + prepaidCards: displayPrepaidCards, + custom: displayCustomValueCards, + onDemand: displayDenominationsCards); + + cakePayVendors.addAll(newVendors); + } catch (error) { + if (error.toString().contains('detail":"Invalid page."')) { + hasMoreDataToFetch = false; + } + } finally { + isLoadingNextPage = false; + } + } + + Future isCakePayUserAuthenticated() async { + return await cakePayService.isLogged(); + } + + void resetLoadingNextPageState() { + hasMoreDataToFetch = true; + page = 1; + } + + void storeInitialFilterStates() { + _initialSelectedCountry = selectedCountry; + _initialDisplayPrepaidCards = displayPrepaidCards; + _initialDisplayGiftCards = displayGiftCards; + _initialDisplayDenominationsCards = displayDenominationsCards; + _initialDisplayCustomValueCards = displayCustomValueCards; + } + + @action + void setSelectedCountry(String country) => selectedCountry = country; + + @action + void togglePrepaidCards() => displayPrepaidCards = !displayPrepaidCards; + + @action + void toggleGiftCards() => displayGiftCards = !displayGiftCards; + + @action + void toggleDenominationsCards() => displayDenominationsCards = !displayDenominationsCards; + + @action + void toggleCustomValueCards() => displayCustomValueCards = !displayCustomValueCards; + + void setScrollOffsetFromTop(double scrollOffset) { + scrollOffsetFromTop = scrollOffset; + } +} diff --git a/lib/view_model/cake_pay/cake_pay_purchase_view_model.dart b/lib/view_model/cake_pay/cake_pay_purchase_view_model.dart new file mode 100644 index 000000000..a580db054 --- /dev/null +++ b/lib/view_model/cake_pay/cake_pay_purchase_view_model.dart @@ -0,0 +1,162 @@ +import 'dart:async'; + +import 'package:cake_wallet/cake_pay/cake_pay_card.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_order.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_payment_credantials.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_service.dart'; +import 'package:cake_wallet/core/execution_state.dart'; +import 'package:cake_wallet/view_model/send/send_view_model.dart'; +import 'package:cw_core/wallet_type.dart'; +import 'package:mobx/mobx.dart'; + +part 'cake_pay_purchase_view_model.g.dart'; + +class CakePayPurchaseViewModel = CakePayPurchaseViewModelBase with _$CakePayPurchaseViewModel; + +abstract class CakePayPurchaseViewModelBase with Store { + CakePayPurchaseViewModelBase({ + required this.cakePayService, + required this.paymentCredential, + required this.card, + required this.sendViewModel, + }) : walletType = sendViewModel.walletType; + + final WalletType walletType; + + final PaymentCredential paymentCredential; + + final CakePayCard card; + + final SendViewModel sendViewModel; + + final CakePayService cakePayService; + + CakePayOrder? order; + + Timer? _timer; + + DateTime? expirationTime; + + Duration? remainingTime; + + String? get userName => paymentCredential.userName; + + double get amount => paymentCredential.amount; + + int get quantity => paymentCredential.quantity; + + double get totalAmount => paymentCredential.totalAmount; + + String get fiatCurrency => paymentCredential.fiatCurrency; + + CryptoPaymentData? get cryptoPaymentData { + if (order == null) return null; + + if (WalletType.monero == walletType) { + return order!.paymentData.xmr; + } + + if (WalletType.bitcoin == walletType) { + final paymentUrls = order!.paymentData.btc.paymentUrls!.bip21; + + final uri = Uri.parse(paymentUrls!); + + final address = uri.path; + final price = uri.queryParameters['amount']; + + return CryptoPaymentData( + address: address, + price: price ?? '0', + ); + } + + return null; + } + + @observable + bool isOrderExpired = false; + + @observable + String formattedRemainingTime = ''; + + @action + Future createOrder() async { + if (walletType != WalletType.bitcoin && walletType != WalletType.monero) { + sendViewModel.state = FailureState('Unsupported wallet type, please use Bitcoin or Monero.'); + } + try { + order = await cakePayService.createOrder( + cardId: card.id, + price: paymentCredential.amount.toString(), + quantity: paymentCredential.quantity); + await confirmSending(); + expirationTime = order!.paymentData.expirationTime; + updateRemainingTime(); + _startExpirationTimer(); + } catch (e) { + sendViewModel.state = FailureState( + sendViewModel.translateErrorMessage(e, walletType, sendViewModel.wallet.currency)); + } + } + + @action + Future confirmSending() async { + final cryptoPaymentData = this.cryptoPaymentData; + try { + if (order == null || cryptoPaymentData == null) return; + + sendViewModel.clearOutputs(); + final output = sendViewModel.outputs.first; + output.address = cryptoPaymentData.address; + output.setCryptoAmount(cryptoPaymentData.price); + + await sendViewModel.createTransaction(); + } catch (e) { + throw e; + } + } + + @action + void updateRemainingTime() { + if (expirationTime == null) { + formattedRemainingTime = ''; + return; + } + + remainingTime = expirationTime!.difference(DateTime.now()); + + isOrderExpired = remainingTime!.isNegative; + + if (isOrderExpired) { + disposeExpirationTimer(); + sendViewModel.state = FailureState('Order has expired.'); + } else { + formattedRemainingTime = formatDuration(remainingTime!); + } + } + + void _startExpirationTimer() { + _timer?.cancel(); + _timer = Timer.periodic(Duration(seconds: 1), (_) { + updateRemainingTime(); + }); + } + + String formatDuration(Duration duration) { + final hours = duration.inHours; + final minutes = duration.inMinutes.remainder(60); + final seconds = duration.inSeconds.remainder(60); + return '${hours.toString().padLeft(2, '0')}:${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}'; + } + + void disposeExpirationTimer() { + _timer?.cancel(); + remainingTime = null; + formattedRemainingTime = ''; + expirationTime = null; + } + + void dispose() { + disposeExpirationTimer(); + } +} diff --git a/lib/view_model/dashboard/cake_features_view_model.dart b/lib/view_model/dashboard/cake_features_view_model.dart index 0a8fbc640..45f80bf80 100644 --- a/lib/view_model/dashboard/cake_features_view_model.dart +++ b/lib/view_model/dashboard/cake_features_view_model.dart @@ -1,4 +1,4 @@ -import 'package:cake_wallet/ionia/ionia_service.dart'; +import 'package:cake_wallet/cake_pay/cake_pay_service.dart'; import 'package:mobx/mobx.dart'; part 'cake_features_view_model.g.dart'; @@ -6,11 +6,11 @@ part 'cake_features_view_model.g.dart'; class CakeFeaturesViewModel = CakeFeaturesViewModelBase with _$CakeFeaturesViewModel; abstract class CakeFeaturesViewModelBase with Store { - final IoniaService _ioniaService; + final CakePayService _cakePayService; - CakeFeaturesViewModelBase(this._ioniaService); + CakeFeaturesViewModelBase(this._cakePayService); Future isIoniaUserAuthenticated() async { - return await _ioniaService.isLogined(); + return await _cakePayService.isLogged(); } } diff --git a/lib/view_model/dashboard/dropdown_filter_item.dart b/lib/view_model/dashboard/dropdown_filter_item.dart new file mode 100644 index 000000000..f7f8e593f --- /dev/null +++ b/lib/view_model/dashboard/dropdown_filter_item.dart @@ -0,0 +1,19 @@ +import 'package:cake_wallet/view_model/dashboard/filter_item.dart'; + +class DropdownFilterItem extends FilterItem { + DropdownFilterItem({ + required this.items, + required this.caption, + required this.selectedItem, + required this.onItemSelected, + }) : super( + value: () => false, + caption: caption, + onChanged: (_) {}, + ); + + final List items; + final String caption; + final String selectedItem; + final Function(String) onItemSelected; +} diff --git a/lib/view_model/dashboard/dropdown_filter_item_widget.dart b/lib/view_model/dashboard/dropdown_filter_item_widget.dart new file mode 100644 index 000000000..20bf54887 --- /dev/null +++ b/lib/view_model/dashboard/dropdown_filter_item_widget.dart @@ -0,0 +1,68 @@ +import 'package:auto_size_text/auto_size_text.dart'; +import 'package:cake_wallet/themes/extensions/picker_theme.dart'; +import 'package:flutter/material.dart'; + +class DropdownFilterList extends StatefulWidget { + DropdownFilterList({ + Key? key, + required this.items, + this.itemPrefix, + this.textStyle, + required this.caption, + required this.selectedItem, + required this.onItemSelected, + }) : super(key: key); + + final List items; + final String? itemPrefix; + final TextStyle? textStyle; + final String caption; + final String selectedItem; + final Function(String) onItemSelected; + + @override + _DropdownFilterListState createState() => _DropdownFilterListState(); +} + +class _DropdownFilterListState extends State { + String? selectedValue; + + @override + void initState() { + super.initState(); + selectedValue = widget.selectedItem; + } + + @override + Widget build(BuildContext context) { + return DropdownButtonHideUnderline( + child: Container( + child: DropdownButton( + isExpanded: true, + icon: Container( + child: Column( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Icon(Icons.arrow_drop_down, color: Theme.of(context).extension()!.searchIconColor), + ], + ), + ), + dropdownColor: Theme.of(context).extension()!.searchBackgroundFillColor, + borderRadius: BorderRadius.circular(10), + items: widget.items + .map((item) => DropdownMenuItem( + alignment: Alignment.bottomCenter, + value: item, + child: AutoSizeText('${widget.itemPrefix ?? ''} $item', style: widget.textStyle), + )) + .toList(), + value: selectedValue, + onChanged: (newValue) { + setState(() => selectedValue = newValue); + widget.onItemSelected(newValue!); + }, + ), + ), + ); + } +} diff --git a/lib/view_model/ionia/ionia_account_view_model.dart b/lib/view_model/ionia/ionia_account_view_model.dart deleted file mode 100644 index 384b75801..000000000 --- a/lib/view_model/ionia/ionia_account_view_model.dart +++ /dev/null @@ -1,50 +0,0 @@ -import 'package:cake_wallet/ionia/ionia_create_state.dart'; -import 'package:cake_wallet/ionia/ionia_service.dart'; -import 'package:mobx/mobx.dart'; -import 'package:cake_wallet/ionia/ionia_gift_card.dart'; - -part 'ionia_account_view_model.g.dart'; - -class IoniaAccountViewModel = IoniaAccountViewModelBase with _$IoniaAccountViewModel; - -abstract class IoniaAccountViewModelBase with Store { - IoniaAccountViewModelBase({required this.ioniaService}) - : email = '', - giftCards = [], - merchantState = InitialIoniaMerchantLoadingState() { - ioniaService.getUserEmail().then((email) => this.email = email); - updateUserGiftCards(); - } - - final IoniaService ioniaService; - - @observable - String email; - - @observable - List giftCards; - - @observable - IoniaMerchantState merchantState; - - @computed - int get countOfMerch => giftCards.where((giftCard) => !giftCard.isEmpty).length; - - @computed - List get activeMechs => giftCards.where((giftCard) => !giftCard.isEmpty).toList(); - - @computed - List get redeemedMerchs => giftCards.where((giftCard) => giftCard.isEmpty).toList(); - - @action - void logout() { - ioniaService.logout(); - } - - @action - Future updateUserGiftCards() async { - merchantState = IoniaLoadingMerchantState(); - giftCards = await ioniaService.getCurrentUserGiftCardSummaries(); - merchantState = IoniaLoadedMerchantState(); - } -} diff --git a/lib/view_model/ionia/ionia_auth_view_model.dart b/lib/view_model/ionia/ionia_auth_view_model.dart deleted file mode 100644 index a0c3ef6e8..000000000 --- a/lib/view_model/ionia/ionia_auth_view_model.dart +++ /dev/null @@ -1,69 +0,0 @@ -import 'package:cake_wallet/ionia/ionia_create_state.dart'; -import 'package:cake_wallet/ionia/ionia_service.dart'; -import 'package:mobx/mobx.dart'; - -part 'ionia_auth_view_model.g.dart'; - -class IoniaAuthViewModel = IoniaAuthViewModelBase with _$IoniaAuthViewModel; - -abstract class IoniaAuthViewModelBase with Store { - - IoniaAuthViewModelBase({required this.ioniaService}): - createUserState = IoniaInitialCreateState(), - signInState = IoniaInitialCreateState(), - otpState = IoniaOtpSendDisabled(), - email = '', - otp = ''; - - final IoniaService ioniaService; - - @observable - IoniaCreateAccountState createUserState; - - @observable - IoniaCreateAccountState signInState; - - @observable - IoniaOtpState otpState; - - @observable - String email; - - @observable - String otp; - - @action - Future verifyEmail(String code) async { - try { - otpState = IoniaOtpValidating(); - await ioniaService.verifyEmail(code); - otpState = IoniaOtpSuccess(); - } catch (_) { - otpState = IoniaOtpFailure(error: 'Invalid OTP. Try again'); - } - } - - @action - Future createUser(String email) async { - try { - createUserState = IoniaCreateStateLoading(); - await ioniaService.createUser(email); - createUserState = IoniaCreateStateSuccess(); - } catch (e) { - createUserState = IoniaCreateStateFailure(error: e.toString()); - } - } - - - @action - Future signIn(String email) async { - try { - signInState = IoniaCreateStateLoading(); - await ioniaService.signIn(email); - signInState = IoniaCreateStateSuccess(); - } catch (e) { - signInState = IoniaCreateStateFailure(error: e.toString()); - } - } - -} \ No newline at end of file diff --git a/lib/view_model/ionia/ionia_buy_card_view_model.dart b/lib/view_model/ionia/ionia_buy_card_view_model.dart deleted file mode 100644 index 4f5fb566c..000000000 --- a/lib/view_model/ionia/ionia_buy_card_view_model.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'package:cake_wallet/ionia/ionia_merchant.dart'; -import 'package:mobx/mobx.dart'; - -part 'ionia_buy_card_view_model.g.dart'; - -class IoniaBuyCardViewModel = IoniaBuyCardViewModelBase with _$IoniaBuyCardViewModel; - -abstract class IoniaBuyCardViewModelBase with Store { - IoniaBuyCardViewModelBase({required this.ioniaMerchant}) - : isEnablePurchase = false, - amount = 0; - - final IoniaMerchant ioniaMerchant; - - @observable - double amount; - - @observable - bool isEnablePurchase; - - @action - void onAmountChanged(String input) { - if (input.isEmpty) return; - amount = double.parse(input.replaceAll(',', '.')); - final min = ioniaMerchant.minimumCardPurchase; - final max = ioniaMerchant.maximumCardPurchase; - - isEnablePurchase = amount >= min && amount <= max; - } -} diff --git a/lib/view_model/ionia/ionia_custom_redeem_view_model.dart b/lib/view_model/ionia/ionia_custom_redeem_view_model.dart deleted file mode 100644 index 5776443ee..000000000 --- a/lib/view_model/ionia/ionia_custom_redeem_view_model.dart +++ /dev/null @@ -1,51 +0,0 @@ -import 'package:cake_wallet/core/execution_state.dart'; -import 'package:cake_wallet/ionia/ionia_gift_card.dart'; -import 'package:cake_wallet/ionia/ionia_service.dart'; -import 'package:mobx/mobx.dart'; -part 'ionia_custom_redeem_view_model.g.dart'; - -class IoniaCustomRedeemViewModel = IoniaCustomRedeemViewModelBase with _$IoniaCustomRedeemViewModel; - -abstract class IoniaCustomRedeemViewModelBase with Store { - IoniaCustomRedeemViewModelBase({ - required this.giftCard, - required this.ioniaService, - }) : amount = 0, - redeemState = InitialExecutionState(); - - final IoniaGiftCard giftCard; - - final IoniaService ioniaService; - - @observable - ExecutionState redeemState; - - @observable - double amount; - - @computed - double get remaining => - amount <= giftCard.remainingAmount ? giftCard.remainingAmount - amount : 0; - - @computed - String get formattedRemaining => remaining.toStringAsFixed(2); - - @computed - bool get disableRedeem => amount > giftCard.remainingAmount; - - @action - void updateAmount(String text) { - amount = double.tryParse(text.replaceAll(',', '.')) ?? 0; - } - - @action - Future addCustomRedeem() async { - try { - redeemState = IsExecutingState(); - await ioniaService.redeem(giftCardId: giftCard.id, amount: amount); - redeemState = ExecutedSuccessfullyState(); - } catch (e) { - redeemState = FailureState(e.toString()); - } - } -} diff --git a/lib/view_model/ionia/ionia_custom_tip_view_model.dart b/lib/view_model/ionia/ionia_custom_tip_view_model.dart deleted file mode 100644 index 452144b24..000000000 --- a/lib/view_model/ionia/ionia_custom_tip_view_model.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'package:cake_wallet/ionia/ionia_merchant.dart'; -import 'package:cake_wallet/ionia/ionia_tip.dart'; -import 'package:mobx/mobx.dart'; - -part 'ionia_custom_tip_view_model.g.dart'; - -class IoniaCustomTipViewModel = IoniaCustomTipViewModelBase with _$IoniaCustomTipViewModel; - -abstract class IoniaCustomTipViewModelBase with Store { - IoniaCustomTipViewModelBase({ - required this.amount, - required this.tip, - required this.ioniaMerchant}) - : customTip = tip, - percentage = 0; - - final IoniaMerchant ioniaMerchant; - final double amount; - final IoniaTip tip; - - @observable - IoniaTip customTip; - - @observable - double percentage; - - @action - void onTipChanged(String value){ - - final _amount = value.isEmpty ? 0 : double.parse(value.replaceAll(',', '.')); - percentage = _amount/amount * 100; - customTip = IoniaTip(percentage: percentage, originalAmount: amount); - } -} \ No newline at end of file diff --git a/lib/view_model/ionia/ionia_gift_card_details_view_model.dart b/lib/view_model/ionia/ionia_gift_card_details_view_model.dart deleted file mode 100644 index cbf5ebc78..000000000 --- a/lib/view_model/ionia/ionia_gift_card_details_view_model.dart +++ /dev/null @@ -1,54 +0,0 @@ -import 'package:cake_wallet/core/execution_state.dart'; -import 'package:cake_wallet/ionia/ionia_service.dart'; -import 'package:cake_wallet/ionia/ionia_gift_card.dart'; -import 'package:mobx/mobx.dart'; -import 'package:device_display_brightness/device_display_brightness.dart'; - -part 'ionia_gift_card_details_view_model.g.dart'; - -class IoniaGiftCardDetailsViewModel = IoniaGiftCardDetailsViewModelBase - with _$IoniaGiftCardDetailsViewModel; - -abstract class IoniaGiftCardDetailsViewModelBase with Store { - IoniaGiftCardDetailsViewModelBase({required this.ioniaService, required this.giftCard}) - : redeemState = InitialExecutionState(), - remainingAmount = giftCard.remainingAmount, - brightness = 0; - - final IoniaService ioniaService; - - double brightness; - - @observable - IoniaGiftCard giftCard; - - @observable - double remainingAmount; - - @observable - ExecutionState redeemState; - - @action - Future redeem() async { - giftCard.remainingAmount = remainingAmount; - try { - redeemState = IsExecutingState(); - await ioniaService.redeem(giftCardId: giftCard.id, amount: giftCard.remainingAmount); - giftCard = await ioniaService.getGiftCard(id: giftCard.id); - redeemState = ExecutedSuccessfullyState(); - } catch (e) { - redeemState = FailureState(e.toString()); - } - } - - @action - Future refeshCard() async { - giftCard = await ioniaService.getGiftCard(id: giftCard.id); - remainingAmount = giftCard.remainingAmount; - } - - void increaseBrightness() async { - brightness = await DeviceDisplayBrightness.getBrightness(); - await DeviceDisplayBrightness.setBrightness(1.0); - } -} diff --git a/lib/view_model/ionia/ionia_gift_cards_list_view_model.dart b/lib/view_model/ionia/ionia_gift_cards_list_view_model.dart deleted file mode 100644 index b4974c420..000000000 --- a/lib/view_model/ionia/ionia_gift_cards_list_view_model.dart +++ /dev/null @@ -1,139 +0,0 @@ -import 'package:cake_wallet/ionia/ionia_category.dart'; -import 'package:cake_wallet/ionia/ionia_service.dart'; -import 'package:cake_wallet/ionia/ionia_create_state.dart'; -import 'package:cake_wallet/ionia/ionia_merchant.dart'; -import 'package:mobx/mobx.dart'; -part 'ionia_gift_cards_list_view_model.g.dart'; - -class IoniaGiftCardsListViewModel = IoniaGiftCardsListViewModelBase with _$IoniaGiftCardsListViewModel; - -abstract class IoniaGiftCardsListViewModelBase with Store { - IoniaGiftCardsListViewModelBase({ - required this.ioniaService, - }) : - cardState = IoniaNoCardState(), - ioniaMerchants = [], - ioniaCategories = IoniaCategory.allCategories, - selectedIndices = ObservableList.of([IoniaCategory.all]), - scrollOffsetFromTop = 0.0, - merchantState = InitialIoniaMerchantLoadingState(), - createCardState = IoniaCreateCardState(), - searchString = '', - ioniaMerchantList = [] { - } - - final IoniaService ioniaService; - - List ioniaMerchantList; - - String searchString; - - @observable - double scrollOffsetFromTop; - - @observable - IoniaCreateCardState createCardState; - - @observable - IoniaFetchCardState cardState; - - @observable - IoniaMerchantState merchantState; - - @observable - List ioniaMerchants; - - @observable - List ioniaCategories; - - @observable - ObservableList selectedIndices; - - @action - Future createCard() async { - try { - createCardState = IoniaCreateCardLoading(); - await ioniaService.createCard(); - createCardState = IoniaCreateCardSuccess(); - } catch (e) { - createCardState = IoniaCreateCardFailure(error: e.toString()); - } - } - - @action - void searchMerchant(String text) { - if (text.isEmpty) { - ioniaMerchants = ioniaMerchantList; - return; - } - searchString = text; - ioniaService.getMerchantsByFilter(search: searchString).then((value) { - ioniaMerchants = value; - }); - } - - Future _getCard() async { - cardState = IoniaFetchingCard(); - try { - final card = await ioniaService.getCard(); - - cardState = IoniaCardSuccess(card: card); - } catch (_) { - cardState = IoniaFetchCardFailure(); - } - } - - - void getMerchants() { - merchantState = IoniaLoadingMerchantState(); - ioniaService.getMerchantsByFilter(categories: selectedIndices).then((value) { - value.sort((a, b) => a.legalName.toLowerCase().compareTo(b.legalName.toLowerCase())); - ioniaMerchants = ioniaMerchantList = value; - merchantState = IoniaLoadedMerchantState(); - }); - - } - - @action - void setSelectedFilter(IoniaCategory category) { - if (category == IoniaCategory.all) { - selectedIndices.clear(); - selectedIndices.add(category); - return; - } - - if (category != IoniaCategory.all) { - selectedIndices.remove(IoniaCategory.all); - } - - if (selectedIndices.contains(category)) { - selectedIndices.remove(category); - - if (selectedIndices.isEmpty) { - selectedIndices.add(IoniaCategory.all); - } - return; - } - selectedIndices.add(category); - } - - @action - void onSearchFilter(String text) { - if (text.isEmpty) { - ioniaCategories = IoniaCategory.allCategories; - } else { - ioniaCategories = IoniaCategory.allCategories - .where((e) => e.title.toLowerCase().contains(text.toLowerCase()),) - .toList(); - } - } - - @action - void resetIoniaCategories() { - ioniaCategories = IoniaCategory.allCategories; - } - - void setScrollOffsetFromTop(double scrollOffset) { - scrollOffsetFromTop = scrollOffset; - } -} diff --git a/lib/view_model/ionia/ionia_payment_status_view_model.dart b/lib/view_model/ionia/ionia_payment_status_view_model.dart deleted file mode 100644 index 8f43e0244..000000000 --- a/lib/view_model/ionia/ionia_payment_status_view_model.dart +++ /dev/null @@ -1,62 +0,0 @@ -import 'dart:async'; -import 'package:cake_wallet/anypay/any_pay_chain.dart'; -import 'package:mobx/mobx.dart'; -import 'package:flutter/foundation.dart'; -import 'package:cake_wallet/ionia/ionia_service.dart'; -import 'package:cake_wallet/ionia/ionia_gift_card.dart'; -import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart'; -import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart'; - -part 'ionia_payment_status_view_model.g.dart'; - -class IoniaPaymentStatusViewModel = IoniaPaymentStatusViewModelBase with _$IoniaPaymentStatusViewModel; - -abstract class IoniaPaymentStatusViewModelBase with Store { - IoniaPaymentStatusViewModelBase( - this.ioniaService, { - required this.paymentInfo, - required this.committedInfo}) - : error = '' { - _timer = Timer.periodic(updateTime, (timer) async { - await updatePaymentStatus(); - - if (giftCard != null) { - timer?.cancel(); - } - }); - } - - static const updateTime = Duration(seconds: 3); - - final IoniaService ioniaService; - final IoniaAnyPayPaymentInfo paymentInfo; - final AnyPayPaymentCommittedInfo committedInfo; - - @observable - IoniaGiftCard? giftCard; - - @observable - String error; - - Timer? get timer => _timer; - - bool get payingByBitcoin => paymentInfo.anyPayPayment.chain == AnyPayChain.btc; - - Timer? _timer; - - @action - Future updatePaymentStatus() async { - try { - final giftCardId = await ioniaService.getPaymentStatus( - orderId: paymentInfo.ioniaOrder.id, - paymentId: paymentInfo.ioniaOrder.paymentId); - - if (giftCardId != null) { - giftCard = await ioniaService.getGiftCard(id: giftCardId); - } - - } catch (e) { - error = e.toString(); - } - } -} diff --git a/lib/view_model/ionia/ionia_purchase_merch_view_model.dart b/lib/view_model/ionia/ionia_purchase_merch_view_model.dart deleted file mode 100644 index df6a23718..000000000 --- a/lib/view_model/ionia/ionia_purchase_merch_view_model.dart +++ /dev/null @@ -1,104 +0,0 @@ -import 'package:flutter/foundation.dart'; -import 'package:mobx/mobx.dart'; -import 'package:cake_wallet/anypay/any_pay_payment.dart'; -import 'package:cake_wallet/anypay/any_pay_payment_committed_info.dart'; -import 'package:cake_wallet/core/execution_state.dart'; -import 'package:cake_wallet/ionia/ionia_anypay.dart'; -import 'package:cake_wallet/ionia/ionia_merchant.dart'; -import 'package:cake_wallet/ionia/ionia_tip.dart'; -import 'package:cake_wallet/ionia/ionia_any_pay_payment_info.dart'; -import 'package:cake_wallet/view_model/send/send_view_model.dart'; - -part 'ionia_purchase_merch_view_model.g.dart'; - -class IoniaMerchPurchaseViewModel = IoniaMerchPurchaseViewModelBase with _$IoniaMerchPurchaseViewModel; - -abstract class IoniaMerchPurchaseViewModelBase with Store { - IoniaMerchPurchaseViewModelBase({ - required this.ioniaAnyPayService, - required this.amount, - required this.ioniaMerchant, - required this.sendViewModel, - }) : tipAmount = 0.0, - percentage = 0.0, - invoiceCreationState = InitialExecutionState(), - invoiceCommittingState = InitialExecutionState(), - tips = [ - IoniaTip(percentage: 0, originalAmount: amount), - IoniaTip(percentage: 15, originalAmount: amount), - IoniaTip(percentage: 18, originalAmount: amount), - IoniaTip(percentage: 20, originalAmount: amount), - IoniaTip(percentage: 0, originalAmount: amount, isCustom: true), - ] { - selectedTip = tips.first; - } - - final double amount; - - List tips; - - @observable - IoniaTip? selectedTip; - - final IoniaMerchant ioniaMerchant; - - final SendViewModel sendViewModel; - - final IoniaAnyPay ioniaAnyPayService; - - IoniaAnyPayPaymentInfo? paymentInfo; - - AnyPayPayment? get invoice => paymentInfo?.anyPayPayment; - - AnyPayPaymentCommittedInfo? committedInfo; - - @observable - ExecutionState invoiceCreationState; - - @observable - ExecutionState invoiceCommittingState; - - @observable - double percentage; - - @computed - double get giftCardAmount => double.parse((amount + tipAmount).toStringAsFixed(2)); - - @computed - double get billAmount => double.parse((giftCardAmount * (1 - (ioniaMerchant.discount / 100))).toStringAsFixed(2)); - - @observable - double tipAmount; - - @action - void addTip(IoniaTip tip) { - tipAmount = tip.additionalAmount; - selectedTip = tip; - } - - @action - Future createInvoice() async { - try { - invoiceCreationState = IsExecutingState(); - paymentInfo = await ioniaAnyPayService.purchase(merchId: ioniaMerchant.id.toString(), amount: giftCardAmount); - invoiceCreationState = ExecutedSuccessfullyState(); - } catch (e) { - invoiceCreationState = FailureState(e.toString()); - } - } - - @action - Future commitPaymentInvoice() async { - try { - if (invoice == null) { - throw Exception('Invoice is created. Invoince is null'); - } - - invoiceCommittingState = IsExecutingState(); - committedInfo = await ioniaAnyPayService.commitInvoice(invoice!); - invoiceCommittingState = ExecutedSuccessfullyState(payload: committedInfo!); - } catch (e) { - invoiceCommittingState = FailureState(e.toString()); - } - } -} diff --git a/res/values/strings_ar.arb b/res/values/strings_ar.arb index b37345ca3..25d392d6a 100644 --- a/res/values/strings_ar.arb +++ b/res/values/strings_ar.arb @@ -87,6 +87,7 @@ "buy": "اشتري", "buy_alert_content": ".ﺎﻬﻴﻟﺇ ﻞﻳﺪﺒﺘﻟﺍ ﻭﺃ Monero ﻭﺃ Litecoin ﻭﺃ Ethereum ﻭﺃ Bitcoin ﺔﻈﻔﺤﻣ ءﺎﺸﻧﺇ ﻰﺟﺮﻳ .", "buy_bitcoin": "شراء Bitcoin", + "buy_now": "اشتري الآن", "buy_provider_unavailable": "مزود حاليا غير متوفر.", "buy_with": "اشتر بواسطة", "by_cake_pay": "عن طريق Cake Pay", @@ -94,8 +95,7 @@ "cake_dark_theme": "موضوع الكعكة الظلام", "cake_pay_account_note": "قم بالتسجيل باستخدام عنوان بريد إلكتروني فقط لمشاهدة البطاقات وشرائها. حتى أن بعضها متوفر بسعر مخفض!", "cake_pay_learn_more": "شراء واسترداد بطاقات الهدايا على الفور في التطبيق!\nاسحب من اليسار إلى اليمين لمعرفة المزيد.", - "cake_pay_subtitle": "شراء بطاقات هدايا مخفضة السعر (الولايات المتحدة فقط)", - "cake_pay_title": "بطاقات هدايا Cake Pay", + "cake_pay_subtitle": "شراء بطاقات مسبقة الدفع وبطاقات الهدايا في جميع أنحاء العالم", "cake_pay_web_cards_subtitle": "اشتري بطاقات مدفوعة مسبقا وبطاقات هدايا في جميع أنحاء العالم", "cake_pay_web_cards_title": "بطاقات Cake Pay Web", "cake_wallet": "Cake Wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "تغيير المحفظة الحالية", "choose_account": "اختر حساب", "choose_address": "\n\nالرجاء اختيار عنوان:", + "choose_card_value": "اختر قيمة بطاقة", "choose_derivation": "اختر اشتقاق المحفظة", "choose_from_available_options": "اختر من بين الخيارات المتاحة:", "choose_one": "اختر واحدة", @@ -166,6 +167,7 @@ "copy_address": "نسخ العنوان", "copy_id": "نسخ معرف العملية", "copyWalletConnectLink": "ﺎﻨﻫ ﻪﻘﺼﻟﺍﻭ dApp ﻦﻣ WalletConnect ﻂﺑﺍﺭ ﺦﺴﻧﺍ", + "countries": "بلدان", "create_account": "إنشاء حساب", "create_backup": "انشئ نسخة احتياطية", "create_donation_link": "إنشاء رابط التبرع", @@ -178,6 +180,7 @@ "custom": "مخصصة", "custom_drag": "مخصص (عقد وسحب)", "custom_redeem_amount": "مبلغ الاسترداد مخصص", + "custom_value": "القيمة الجمركية", "dark_theme": "داكن", "debit_card": "بطاقة ائتمان", "debit_card_terms": "يخضع تخزين واستخدام رقم بطاقة الدفع الخاصة بك (وبيانات الاعتماد المقابلة لرقم بطاقة الدفع الخاصة بك) في هذه المحفظة الرقمية لشروط وأحكام اتفاقية حامل البطاقة المعمول بها مع جهة إصدار بطاقة الدفع ، كما هو معمول به من وقت لآخر.", @@ -190,6 +193,7 @@ "delete_wallet": "حذف المحفظة", "delete_wallet_confirm_message": "هل أنت متأكد أنك تريد حذف محفظة ${wallet_name}؟", "deleteConnectionConfirmationPrompt": "ـﺑ ﻝﺎﺼﺗﻻﺍ ﻑﺬﺣ ﺪﻳﺮﺗ ﻚﻧﺃ ﺪﻛﺄﺘﻣ ﺖﻧﺃ ﻞﻫ", + "denominations": "الطوائف", "descending": "النزول", "description": "ﻒﺻﻭ", "destination_tag": "علامة الوجهة:", @@ -277,6 +281,7 @@ "expired": "منتهي الصلاحية", "expires": "تنتهي", "expiresOn": "ﻲﻓ ﻪﺘﻴﺣﻼﺻ ﻲﻬﺘﻨﺗ", + "expiry_and_validity": "انتهاء الصلاحية والصلاحية", "export_backup": "تصدير نسخة احتياطية", "extra_id": "معرف إضافي:", "extracted_address_content": "سوف ترسل الأموال إلى\n${recipient_name}", @@ -384,6 +389,7 @@ "new_template": "قالب جديد", "new_wallet": "إنشاء محفظة جديدة", "newConnection": "ﺪﻳﺪﺟ ﻝﺎﺼﺗﺍ", + "no_cards_found": "لم يتم العثور على بطاقات", "no_id_needed": "لا حاجة لID!", "no_id_required": "لا ID مطلوب. اشحن وانفق في أي مكان", "no_relay_on_domain": ".ﻡﺍﺪﺨﺘﺳﻼﻟ ﻊﺑﺎﺘﺘﻟﺍ ﺭﺎﻴﺘﺧﺍ ءﺎﺟﺮﻟﺍ .ﺡﺎﺘﻣ ﺮﻴﻏ ﻞﻴﺣﺮﺘﻟﺍ ﻥﺃ ﻭﺃ ﻡﺪﺨﺘﺴﻤﻟﺍ ﻝﺎﺠﻤﻟ ﻞﻴﺣﺮﺗ ﺪ", @@ -452,6 +458,7 @@ "pre_seed_button_text": "انا أفهم. أرني سييد الخاص بي", "pre_seed_description": "في الصفحة التالية ستشاهد سلسلة من الكلمات ${words}. هذه هي سييد الفريدة والخاصة بك وهي الطريقة الوحيدة لاسترداد محفظتك في حالة فقدها أو عطلها. تقع على عاتقك مسؤولية تدوينها وتخزينها في مكان آمن خارج تطبيق Cake Wallet.", "pre_seed_title": "مهم", + "prepaid_cards": "البطاقات المدفوعة مسبقا", "prevent_screenshots": "منع لقطات الشاشة وتسجيل الشاشة", "privacy": "خصوصية", "privacy_policy": "سياسة الخصوصية", @@ -467,6 +474,7 @@ "purple_dark_theme": "موضوع الظلام الأرجواني", "qr_fullscreen": "انقر لفتح ال QR بملء الشاشة", "qr_payment_amount": "يحتوي هذا ال QR على مبلغ الدفع. هل تريد تغير المبلغ فوق القيمة الحالية؟", + "quantity": "كمية", "question_to_disable_2fa": "هل أنت متأكد أنك تريد تعطيل Cake 2FA؟ لن تكون هناك حاجة إلى رمز 2FA للوصول إلى المحفظة ووظائف معينة.", "receivable_balance": "التوازن القادم", "receive": "استلام", @@ -708,6 +716,7 @@ "tokenID": "ﻒﻳﺮﻌﺗ ﺔﻗﺎﻄﺑ", "tor_connection": "ﺭﻮﺗ ﻝﺎﺼﺗﺍ", "tor_only": "Tor فقط", + "total": "المجموع", "total_saving": "إجمالي المدخرات", "totp_2fa_failure": "شفرة خاطئة. يرجى تجربة رمز مختلف أو إنشاء مفتاح سري جديد. استخدم تطبيق 2FA متوافقًا يدعم الرموز المكونة من 8 أرقام و SHA512.", "totp_2fa_success": "نجاح! تم تمكين Cake 2FA لهذه المحفظة. تذكر حفظ بذرة ذاكري في حالة فقد الوصول إلى المحفظة.", @@ -798,6 +807,8 @@ "use_ssl": "استخدم SSL", "use_suggested": "استخدام المقترح", "use_testnet": "استخدم testnet", + "value": "قيمة", + "value_type": "نوع القيمة", "variable_pair_not_supported": "هذا الزوج المتغير غير مدعوم في التبادلات المحددة", "verification": "تَحَقّق", "verify_with_2fa": "تحقق مع Cake 2FA", diff --git a/res/values/strings_bg.arb b/res/values/strings_bg.arb index 4b145d8fa..8f4717081 100644 --- a/res/values/strings_bg.arb +++ b/res/values/strings_bg.arb @@ -87,6 +87,7 @@ "buy": "Купуване", "buy_alert_content": "В момента поддържаме само закупуването на Bitcoin, Ethereum, Litecoin и Monero. Моля, създайте или превключете към своя портфейл Bitcoin, Ethereum, Litecoin или Monero.", "buy_bitcoin": "Купуване на Bitcoin", + "buy_now": "Купи сега", "buy_provider_unavailable": "Понастоящем доставчик не е наличен.", "buy_with": "Купуване чрез", "by_cake_pay": "от Cake Pay", @@ -94,8 +95,7 @@ "cake_dark_theme": "Торта тъмна тема", "cake_pay_account_note": "Регистрайте се само с един имейл, за да виждате и купувате карти. За някои има дори и отстъпка!", "cake_pay_learn_more": "Купете и използвайте гифткарти директно в приложението!\nПлъзнете отляво надясно, за да научите още.", - "cake_pay_subtitle": "Купете гифткарти на намалени цени (само за САЩ)", - "cake_pay_title": "Cake Pay Gift Карти", + "cake_pay_subtitle": "Купете предплатени карти и карти за подаръци в световен мащаб", "cake_pay_web_cards_subtitle": "Купете световно признати предплатени и гифт карти", "cake_pay_web_cards_title": "Cake Pay Онлайн Карти", "cake_wallet": "Cake Wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "Смяна на сегашния портфейл", "choose_account": "Избиране на профил", "choose_address": "\n\nМоля, изберете адреса:", + "choose_card_value": "Изберете стойност на картата", "choose_derivation": "Изберете производно на портфейла", "choose_from_available_options": "Изберете от следните опции:", "choose_one": "Изберете едно", @@ -166,6 +167,7 @@ "copy_address": "Copy Address", "copy_id": "Копиране на ID", "copyWalletConnectLink": "Копирайте връзката WalletConnect от dApp и я поставете тук", + "countries": "Държави", "create_account": "Създаване на профил", "create_backup": "Създаване на резервно копие", "create_donation_link": "Създайте връзка за дарение", @@ -178,6 +180,7 @@ "custom": "персонализирано", "custom_drag": "Персонализиране (задръжте и плъзнете)", "custom_redeem_amount": "Персонализирана сума за използване", + "custom_value": "Персонализирана стойност", "dark_theme": "Тъмно", "debit_card": "Дебитна карта", "debit_card_terms": "Съхранението и използването на данните от вашата платежна карта в този дигитален портфейл подлежат на условията на съответното съгласие за картодържец от издателя на картата.", @@ -190,6 +193,7 @@ "delete_wallet": "Изтриване на портфейл", "delete_wallet_confirm_message": "Сигурни ли сте, че искате да изтриете протфейла ${wallet_name}?", "deleteConnectionConfirmationPrompt": "Сигурни ли сте, че искате да изтриете връзката към", + "denominations": "Деноминации", "descending": "Низходящ", "description": "Описание", "destination_tag": "Destination tag:", @@ -277,6 +281,7 @@ "expired": "Изтекло", "expires": "Изтича", "expiresOn": "Изтича на", + "expiry_and_validity": "Изтичане и валидност", "export_backup": "Експортиране на резервно копие", "extra_id": "Допълнително ID:", "extracted_address_content": "Ще изпратите средства на \n${recipient_name}", @@ -308,7 +313,7 @@ "gift_card_is_generated": "Gift Card бе създадена", "gift_card_number": "Номер на Gift Card", "gift_card_redeemed_note": "Използваните гифткарти ще се покажат тук", - "gift_cards": "Gift Карти", + "gift_cards": "Карти за подаръци", "gift_cards_unavailable": "В момента гифткарти могат да бъдат закупени само с Monero, Bitcoin и Litecoin", "got_it": "Готово", "gross_balance": "Брутен баланс", @@ -384,6 +389,7 @@ "new_template": "Нов шаблон", "new_wallet": "Нов портфейл", "newConnection": "Нова връзка", + "no_cards_found": "Не са намерени карти", "no_id_needed": "Без нужда от документ за самоличност!", "no_id_required": "Без нужда от документ за самоличност. Използвайте навсякъде", "no_relay_on_domain": "Няма реле за домейна на потребителя или релето не е налично. Моля, изберете реле, което да използвате.", @@ -452,6 +458,7 @@ "pre_seed_button_text": "Разбирам. Покажи seed", "pre_seed_description": "На следващата страница ще видите поредица от ${words} думи. Това е вашият таен личен seed и е единственият начин да възстановите портфейла си. Отговорността за съхранението му на сигурно място извън приложението на Cake Wallet е изцяло ВАША.", "pre_seed_title": "ВАЖНО", + "prepaid_cards": "Предплатени карти", "prevent_screenshots": "Предотвратете екранни снимки и запис на екрана", "privacy": "Поверителност", "privacy_policy": "Политика за поверителността", @@ -467,6 +474,7 @@ "purple_dark_theme": "Лилава тъмна тема", "qr_fullscreen": "Натиснете, за да отворите QR кода на цял екран", "qr_payment_amount": "Този QR код съдържа сума за плащане. Искате ли да промените стойността?", + "quantity": "Количество", "question_to_disable_2fa": "Сигурни ли сте, че искате да деактивирате Cake 2FA? Вече няма да е необходим 2FA код за достъп до портфейла и определени функции.", "receivable_balance": "Баланс за вземания", "receive": "Получи", @@ -708,6 +716,7 @@ "tokenID": "документ за самоличност", "tor_connection": "Tor връзка", "tor_only": "Само чрез Tor", + "total": "Обща сума", "total_saving": "Общо спестявания", "totp_2fa_failure": "Грешен код. Моля, опитайте с различен код или генерирайте нов таен ключ. Използвайте съвместимо 2FA приложение, което поддържа 8-цифрени кодове и SHA512.", "totp_2fa_success": "Успех! Cake 2FA е активиран за този портфейл. Не забравяйте да запазите мнемоничното начало, в случай че загубите достъп до портфейла.", @@ -798,6 +807,8 @@ "use_ssl": "Използване на SSL", "use_suggested": "Използване на предложеното", "use_testnet": "Използвайте TestNet", + "value": "Стойност", + "value_type": "Тип стойност", "variable_pair_not_supported": "Този variable pair не се поддържа от избраната борса", "verification": "Потвърждаване", "verify_with_2fa": "Проверете с Cake 2FA", diff --git a/res/values/strings_cs.arb b/res/values/strings_cs.arb index 35a4966a0..297a737a2 100644 --- a/res/values/strings_cs.arb +++ b/res/values/strings_cs.arb @@ -87,6 +87,7 @@ "buy": "Koupit", "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.", "buy_bitcoin": "Nakoupit Bitcoin", + "buy_now": "Kup nyní", "buy_provider_unavailable": "Poskytovatel aktuálně nedostupný.", "buy_with": "Nakoupit pomocí", "by_cake_pay": "od Cake Pay", @@ -94,8 +95,7 @@ "cake_dark_theme": "Dort tmavé téma", "cake_pay_account_note": "Přihlaste se svou e-mailovou adresou pro zobrazení a nákup karet. Některé jsou dostupné ve slevě!", "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.", - "cake_pay_subtitle": "Kupte si zlevněné dárkové karty (pouze USA)", - "cake_pay_title": "Cake Pay dárkové karty", + "cake_pay_subtitle": "Kupte si celosvětové předplacené karty a dárkové karty", "cake_pay_web_cards_subtitle": "Kupte si celosvětové předplacené a dárkové karty", "cake_pay_web_cards_title": "Cake Pay webové karty", "cake_wallet": "Cake Wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "Přepnout peněženku", "choose_account": "Zvolte částku", "choose_address": "\n\nProsím vyberte adresu:", + "choose_card_value": "Vyberte hodnotu karty", "choose_derivation": "Vyberte derivaci peněženky", "choose_from_available_options": "Zvolte si z dostupných možností:", "choose_one": "Zvolte si", @@ -166,6 +167,7 @@ "copy_address": "Zkopírovat adresu", "copy_id": "Kopírovat ID", "copyWalletConnectLink": "Zkopírujte odkaz WalletConnect z dApp a vložte jej sem", + "countries": "Země", "create_account": "Vytvořit účet", "create_backup": "Vytvořit zálohu", "create_donation_link": "Vytvořit odkaz na darování", @@ -178,6 +180,7 @@ "custom": "vlastní", "custom_drag": "Custom (Hold and Drag)", "custom_redeem_amount": "Vlastní částka pro uplatnění", + "custom_value": "Vlastní hodnota", "dark_theme": "Tmavý", "debit_card": "Debetní karta", "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 @@ "delete_wallet": "Smazat peněženku", "delete_wallet_confirm_message": "Opravdu chcete smazat ${wallet_name} peněženku?", "deleteConnectionConfirmationPrompt": "Jste si jisti, že chcete smazat připojení k?", + "denominations": "Označení", "descending": "Klesající", "description": "Popis", "destination_tag": "Destination Tag:", @@ -277,6 +281,7 @@ "expired": "Vypršelo", "expires": "Vyprší", "expiresOn": "Vyprší dne", + "expiry_and_validity": "Vypršení a platnost", "export_backup": "Exportovat zálohu", "extra_id": "Extra ID:", "extracted_address_content": "Prostředky budete posílat na\n${recipient_name}", @@ -384,6 +389,7 @@ "new_template": "Nová šablona", "new_wallet": "Nová peněženka", "newConnection": "Nové připojení", + "no_cards_found": "Žádné karty nenalezeny", "no_id_needed": "Žádné ID není potřeba!", "no_id_required": "Žádní ID není potřeba. Dobijte si a utrácejte kdekoliv", "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 @@ "pre_seed_button_text": "Rozumím. Ukaž mi můj seed.", "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.", "pre_seed_title": "DŮLEŽITÉ", + "prepaid_cards": "Předplacené karty", "prevent_screenshots": "Zabránit vytváření snímků obrazovky a nahrávání obrazovky", "privacy": "Soukromí", "privacy_policy": "Zásady ochrany soukromí", @@ -467,6 +474,7 @@ "purple_dark_theme": "Fialové temné téma", "qr_fullscreen": "Poklepáním otevřete QR kód na celé obrazovce", "qr_payment_amount": "Tento QR kód obsahuje i částku. Chcete přepsat současnou hodnotu?", + "quantity": "Množství", "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.", "receivable_balance": "Zůstatek pohledávek", "receive": "Přijmout", @@ -708,6 +716,7 @@ "tokenID": "ID", "tor_connection": "Připojení Tor", "tor_only": "Pouze Tor", + "total": "Celkový", "total_saving": "Celkem ušetřeno", "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.", "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 @@ "use_ssl": "Použít SSL", "use_suggested": "Použít doporučený", "use_testnet": "Použijte testNet", + "value": "Hodnota", + "value_type": "Typ hodnoty", "variable_pair_not_supported": "Tento pár s tržním kurzem není ve zvolené směnárně podporován", "verification": "Ověření", "verify_with_2fa": "Ověřte pomocí Cake 2FA", diff --git a/res/values/strings_de.arb b/res/values/strings_de.arb index 1877c162a..2ccd1919c 100644 --- a/res/values/strings_de.arb +++ b/res/values/strings_de.arb @@ -87,6 +87,7 @@ "buy": "Kaufen", "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.", "buy_bitcoin": "Bitcoin kaufen", + "buy_now": "Kaufe jetzt", "buy_provider_unavailable": "Anbieter derzeit nicht verfügbar.", "buy_with": "Kaufen mit", "by_cake_pay": "von Cake Pay", @@ -94,8 +95,7 @@ "cake_dark_theme": "Cake Dark Thema", "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!", "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.", - "cake_pay_subtitle": "Kaufen Sie ermäßigte Geschenkkarten (nur USA)", - "cake_pay_title": "Cake Pay-Geschenkkarten", + "cake_pay_subtitle": "Kaufen Sie weltweite Prepaid -Karten und Geschenkkarten", "cake_pay_web_cards_subtitle": "Kaufen Sie weltweit Prepaid-Karten und Geschenkkarten", "cake_pay_web_cards_title": "Cake Pay-Webkarten", "cake_wallet": "Cake Wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "Aktuelle Wallet ändern", "choose_account": "Konto auswählen", "choose_address": "\n\nBitte wählen Sie die Adresse:", + "choose_card_value": "Wählen Sie einen Kartenwert", "choose_derivation": "Wählen Sie Wallet-Ableitung", "choose_from_available_options": "Wähle aus verfügbaren Optionen:", "choose_one": "Wähle ein", @@ -166,6 +167,7 @@ "copy_address": "Adresse kopieren", "copy_id": "ID kopieren", "copyWalletConnectLink": "Kopieren Sie den WalletConnect-Link von dApp und fügen Sie ihn hier ein", + "countries": "Länder", "create_account": "Konto erstellen", "create_backup": "Backup erstellen", "create_donation_link": "Spendenlink erstellen", @@ -178,6 +180,7 @@ "custom": "benutzerdefiniert", "custom_drag": "Custom (Hold and Drag)", "custom_redeem_amount": "Benutzerdefinierter Einlösungsbetrag", + "custom_value": "Benutzerdefinierten Wert", "dark_theme": "Dunkel", "debit_card": "Debitkarte", "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 @@ "delete_wallet": "Wallet löschen", "delete_wallet_confirm_message": "Sind Sie sicher, dass Sie das ${wallet_name} Wallet löschen möchten?", "deleteConnectionConfirmationPrompt": "Sind Sie sicher, dass Sie die Verbindung zu löschen möchten?", + "denominations": "Konfessionen", "descending": "Absteigend", "description": "Beschreibung", "destination_tag": "Ziel-Tag:", @@ -277,6 +281,7 @@ "expired": "Abgelaufen", "expires": "Läuft ab", "expiresOn": "Läuft aus am", + "expiry_and_validity": "Ablauf und Gültigkeit", "export_backup": "Sicherung exportieren", "extra_id": "Extra ID:", "extracted_address_content": "Sie senden Geld an\n${recipient_name}", @@ -384,6 +389,7 @@ "new_template": "neue Vorlage", "new_wallet": "Neue Wallet", "newConnection": "Neue Verbindung", + "no_cards_found": "Keine Karten gefunden", "no_id_needed": "Keine ID erforderlich!", "no_id_required": "Keine ID erforderlich. Upgraden und überall ausgeben", "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 @@ "placeholder_transactions": "Ihre Transaktionen werden hier angezeigt", "please_fill_totp": "Bitte geben Sie den 8-stelligen Code ein, der auf Ihrem anderen Gerät vorhanden ist", "please_make_selection": "Bitte treffen Sie unten eine Auswahl zum Erstellen oder Wiederherstellen Ihrer Wallet.", - "please_reference_document": "Bitte verweisen Sie auf die folgenden Dokumente, um weitere Informationen zu erhalten.", "Please_reference_document": "Weitere Informationen finden Sie in den Dokumenten unten.", + "please_reference_document": "Bitte verweisen Sie auf die folgenden Dokumente, um weitere Informationen zu erhalten.", "please_select": "Bitte auswählen:", "please_select_backup_file": "Bitte wählen Sie die Sicherungsdatei und geben Sie das Sicherungskennwort ein.", "please_try_to_connect_to_another_node": "Bitte versuchen Sie, sich mit einem anderen Knoten zu verbinden", @@ -453,6 +459,7 @@ "pre_seed_button_text": "Verstanden. Zeig mir meinen Seed", "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.", "pre_seed_title": "WICHTIG", + "prepaid_cards": "Karten mit Guthaben", "prevent_screenshots": "Verhindern Sie Screenshots und Bildschirmaufzeichnungen", "privacy": "Datenschutz", "privacy_policy": "Datenschutzrichtlinie", @@ -468,6 +475,7 @@ "purple_dark_theme": "Lila dunkle Thema", "qr_fullscreen": "Tippen Sie hier, um den QR-Code im Vollbildmodus zu öffnen", "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?", + "quantity": "Menge", "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.", "receivable_balance": "Forderungsbilanz", "receive": "Empfangen", @@ -709,6 +717,7 @@ "tokenID": "AUSWEIS", "tor_connection": "Tor-Verbindung", "tor_only": "Nur Tor", + "total": "Gesamt", "total_saving": "Gesamteinsparungen", "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.", "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 @@ "use_ssl": "SSL verwenden", "use_suggested": "Vorgeschlagen verwenden", "use_testnet": "TESTNET verwenden", + "value": "Wert", + "value_type": "Werttyp", "variable_pair_not_supported": "Dieses Variablenpaar wird von den ausgewählten Börsen nicht unterstützt", "verification": "Verifizierung", "verify_with_2fa": "Verifizieren Sie mit Cake 2FA", diff --git a/res/values/strings_en.arb b/res/values/strings_en.arb index 13408529a..9b8662bdb 100644 --- a/res/values/strings_en.arb +++ b/res/values/strings_en.arb @@ -87,6 +87,7 @@ "buy": "Buy", "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.", "buy_bitcoin": "Buy Bitcoin", + "buy_now": "Buy Now", "buy_provider_unavailable": "Provider currently unavailable.", "buy_with": "Buy with", "by_cake_pay": "by Cake Pay", @@ -94,8 +95,7 @@ "cake_dark_theme": "Cake Dark Theme", "cake_pay_account_note": "Sign up with just an email address to see and purchase cards. Some are even available at a discount!", "cake_pay_learn_more": "Instantly purchase and redeem gift cards in the app!\nSwipe left to right to learn more.", - "cake_pay_subtitle": "Buy discounted gift cards (USA only)", - "cake_pay_title": "Cake Pay Gift Cards", + "cake_pay_subtitle": "Buy worldwide prepaid cards and gift cards", "cake_pay_web_cards_subtitle": "Buy worldwide prepaid cards and gift cards", "cake_pay_web_cards_title": "Cake Pay Web Cards", "cake_wallet": "Cake Wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "Change current wallet", "choose_account": "Choose account", "choose_address": "\n\nPlease choose the address:", + "choose_card_value": "Choose a card value", "choose_derivation": "Choose Wallet Derivation", "choose_from_available_options": "Choose from the available options:", "choose_one": "Choose one", @@ -166,6 +167,7 @@ "copy_address": "Copy Address", "copy_id": "Copy ID", "copyWalletConnectLink": "Copy the WalletConnect link from dApp and paste here", + "countries": "Countries", "create_account": "Create Account", "create_backup": "Create backup", "create_donation_link": "Create donation link", @@ -178,6 +180,7 @@ "custom": "Custom", "custom_drag": "Custom (Hold and Drag)", "custom_redeem_amount": "Custom Redeem Amount", + "custom_value": "Custom Value", "dark_theme": "Dark", "debit_card": "Debit Card", "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 @@ "delete_wallet": "Delete wallet", "delete_wallet_confirm_message": "Are you sure that you want to delete ${wallet_name} wallet?", "deleteConnectionConfirmationPrompt": "Are you sure that you want to delete the connection to", + "denominations": "Denominations", "descending": "Descending", "description": "Description", "destination_tag": "Destination tag:", @@ -277,6 +281,7 @@ "expired": "Expired", "expires": "Expires", "expiresOn": "Expires on", + "expiry_and_validity": "Expiry and Validity", "export_backup": "Export backup", "extra_id": "Extra ID:", "extracted_address_content": "You will be sending funds to\n${recipient_name}", @@ -384,6 +389,7 @@ "new_template": "New Template", "new_wallet": "New Wallet", "newConnection": "New Connection", + "no_cards_found": "No cards found", "no_id_needed": "No ID needed!", "no_id_required": "No ID required. Top up and spend anywhere", "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 @@ "pre_seed_button_text": "I understand. Show me my seed", "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.", "pre_seed_title": "IMPORTANT", + "prepaid_cards": "Prepaid Cards", "prevent_screenshots": "Prevent screenshots and screen recording", "privacy": "Privacy", "privacy_policy": "Privacy Policy", @@ -467,6 +474,7 @@ "purple_dark_theme": "Purple Dark Theme", "qr_fullscreen": "Tap to open full screen QR code", "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?", + "quantity": "Quantity", "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.", "receivable_balance": "Receivable Balance", "receive": "Receive", @@ -708,6 +716,7 @@ "tokenID": "ID", "tor_connection": "Tor connection", "tor_only": "Tor only", + "total": "Total", "total_saving": "Total Savings", "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.", "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 @@ "use_ssl": "Use SSL", "use_suggested": "Use Suggested", "use_testnet": "Use Testnet", + "value": "Value", + "value_type": "Value Type", "variable_pair_not_supported": "This variable pair is not supported with the selected exchanges", "verification": "Verification", "verify_with_2fa": "Verify with Cake 2FA", diff --git a/res/values/strings_es.arb b/res/values/strings_es.arb index 50d48bb98..45da02030 100644 --- a/res/values/strings_es.arb +++ b/res/values/strings_es.arb @@ -87,6 +87,7 @@ "buy": "Comprar", "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.", "buy_bitcoin": "Comprar Bitcoin", + "buy_now": "Comprar ahora", "buy_provider_unavailable": "Proveedor actualmente no disponible.", "buy_with": "Compra con", "by_cake_pay": "por Cake Pay", @@ -94,8 +95,7 @@ "cake_dark_theme": "Tema oscuro del pastel", "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!", "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.", - "cake_pay_subtitle": "Compre tarjetas de regalo con descuento (solo EE. UU.)", - "cake_pay_title": "Tarjetas de regalo Cake Pay", + "cake_pay_subtitle": "Compre tarjetas prepagas y tarjetas de regalo en todo el mundo", "cake_pay_web_cards_subtitle": "Compre tarjetas de prepago y tarjetas de regalo en todo el mundo", "cake_pay_web_cards_title": "Tarjetas Web Cake Pay", "cake_wallet": "Cake Wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "Cambiar billetera actual", "choose_account": "Elegir cuenta", "choose_address": "\n\nPor favor elija la dirección:", + "choose_card_value": "Elija un valor de tarjeta", "choose_derivation": "Elija la derivación de la billetera", "choose_from_available_options": "Elija entre las opciones disponibles:", "choose_one": "Elige uno", @@ -166,6 +167,7 @@ "copy_address": "Copiar dirección ", "copy_id": "Copiar ID", "copyWalletConnectLink": "Copie el enlace de WalletConnect de dApp y péguelo aquí", + "countries": "Países", "create_account": "Crear Cuenta", "create_backup": "Crear copia de seguridad", "create_donation_link": "Crear enlace de donación", @@ -178,6 +180,7 @@ "custom": "Costumbre", "custom_drag": "Custom (mantenía y arrastre)", "custom_redeem_amount": "Cantidad de canje personalizada", + "custom_value": "Valor personalizado", "dark_theme": "Oscura", "debit_card": "Tarjeta de Débito", "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 @@ "delete_wallet": "Eliminar billetera", "delete_wallet_confirm_message": "¿Está seguro de que desea eliminar la billetera ${wallet_name}?", "deleteConnectionConfirmationPrompt": "¿Está seguro de que desea eliminar la conexión a", + "denominations": "Denominaciones", "descending": "Descendente", "description": "Descripción", "destination_tag": "Etiqueta de destino:", @@ -277,6 +281,7 @@ "expired": "Muerto", "expires": "Caduca", "expiresOn": "Expira el", + "expiry_and_validity": "Vencimiento y validez", "export_backup": "Exportar copia de seguridad", "extra_id": "ID adicional:", "extracted_address_content": "Enviará fondos a\n${recipient_name}", @@ -384,6 +389,7 @@ "new_template": "Nueva plantilla", "new_wallet": "Nueva billetera", "newConnection": "Nueva conexión", + "no_cards_found": "No se encuentran cartas", "no_id_needed": "¡No se necesita identificación!", "no_id_required": "No se requiere identificación. Recargue y gaste en cualquier lugar", "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 @@ "pre_seed_button_text": "Entiendo. Muéstrame mi semilla", "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.", "pre_seed_title": "IMPORTANTE", + "prepaid_cards": "Tajetas prepagadas", "prevent_screenshots": "Evitar capturas de pantalla y grabación de pantalla", "privacy": "Privacidad", "privacy_policy": "Política de privacidad", @@ -468,6 +475,7 @@ "purple_dark_theme": "Tema morado oscuro", "qr_fullscreen": "Toque para abrir el código QR en pantalla completa", "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?", + "quantity": "Cantidad", "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.", "receivable_balance": "Saldo de cuentas por cobrar", "receive": "Recibir", @@ -709,6 +717,7 @@ "tokenID": "IDENTIFICACIÓN", "tor_connection": "conexión tor", "tor_only": "solo Tor", + "total": "Total", "total_saving": "Ahorro Total", "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.", "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 @@ "use_ssl": "Utilice SSL", "use_suggested": "Usar sugerido", "use_testnet": "Use TestNet", + "value": "Valor", + "value_type": "Tipo de valor", "variable_pair_not_supported": "Este par de variables no es compatible con los intercambios seleccionados", "verification": "Verificación", "verify_with_2fa": "Verificar con Cake 2FA", diff --git a/res/values/strings_fr.arb b/res/values/strings_fr.arb index 411983e8d..119cb24e4 100644 --- a/res/values/strings_fr.arb +++ b/res/values/strings_fr.arb @@ -87,6 +87,7 @@ "buy": "Acheter", "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.", "buy_bitcoin": "Acheter du Bitcoin", + "buy_now": "Acheter maintenant", "buy_provider_unavailable": "Fournisseur actuellement indisponible.", "buy_with": "Acheter avec", "by_cake_pay": "par Cake Pay", @@ -94,8 +95,7 @@ "cake_dark_theme": "Thème sombre du gâteau", "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 !", "cake_pay_learn_more": "Achetez et utilisez instantanément des cartes-cadeaux dans l'application !\nBalayer de gauche à droite pour en savoir plus.", - "cake_pay_subtitle": "Achetez des cartes-cadeaux à prix réduit (États-Unis uniquement)", - "cake_pay_title": "Cartes cadeaux Cake Pay", + "cake_pay_subtitle": "Achetez des cartes et des cartes-cadeaux prépayées mondiales", "cake_pay_web_cards_subtitle": "Achetez des cartes prépayées et des cartes-cadeaux dans le monde entier", "cake_pay_web_cards_title": "Cartes Web Cake Pay", "cake_wallet": "Cake Wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "Changer le portefeuille (wallet) actuel", "choose_account": "Choisir le compte", "choose_address": "\n\nMerci de choisir l'adresse :", + "choose_card_value": "Choisissez une valeur de carte", "choose_derivation": "Choisissez le chemin de dérivation du portefeuille", "choose_from_available_options": "Choisissez parmi les options disponibles :", "choose_one": "Choisissez-en un", @@ -166,6 +167,7 @@ "copy_address": "Copier l'Adresse", "copy_id": "Copier l'ID", "copyWalletConnectLink": "Copiez le lien WalletConnect depuis l'application décentralisée (dApp) et collez-le ici", + "countries": "Des pays", "create_account": "Créer un compte", "create_backup": "Créer une sauvegarde", "create_donation_link": "Créer un lien de don", @@ -178,6 +180,7 @@ "custom": "personnalisé", "custom_drag": "Custom (maintenir et traîner)", "custom_redeem_amount": "Montant d'échange personnalisé", + "custom_value": "Valeur personnalisée", "dark_theme": "Sombre", "debit_card": "Carte de débit", "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 @@ "delete_wallet": "Supprimer le portefeuille (wallet)", "delete_wallet_confirm_message": "Êtes-vous sûr de vouloir supprimer le portefeuille (wallet) ${wallet_name}?", "deleteConnectionConfirmationPrompt": "Êtes-vous sûr de vouloir supprimer la connexion à", + "denominations": "Dénominations", "descending": "Descendant", "description": "Description", "destination_tag": "Tag de destination :", @@ -277,6 +281,7 @@ "expired": "Expirée", "expires": "Expire", "expiresOn": "Expire le", + "expiry_and_validity": "Expiration et validité", "export_backup": "Exporter la sauvegarde", "extra_id": "ID supplémentaire :", "extracted_address_content": "Vous allez envoyer des fonds à\n${recipient_name}", @@ -308,7 +313,7 @@ "gift_card_is_generated": "La carte-cadeau est générée", "gift_card_number": "Numéro de carte cadeau", "gift_card_redeemed_note": "Les cartes-cadeaux que vous avez utilisées apparaîtront ici", - "gift_cards": "Cartes-Cadeaux", + "gift_cards": "Cartes cadeaux", "gift_cards_unavailable": "Les cartes-cadeaux ne sont disponibles à l'achat que via Monero, Bitcoin et Litecoin pour le moment", "got_it": "Compris", "gross_balance": "Solde brut", @@ -384,6 +389,7 @@ "new_template": "Nouveau Modèle", "new_wallet": "Nouveau Portefeuille (Wallet)", "newConnection": "Nouvelle connexion", + "no_cards_found": "Pas de cartes trouvées", "no_id_needed": "Aucune pièce d'identité nécessaire !", "no_id_required": "Aucune pièce d'identité requise. Rechargez et dépensez n'importe où", "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 @@ "pre_seed_button_text": "J'ai compris. Montrez moi ma phrase secrète (seed)", "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.", "pre_seed_title": "IMPORTANT", + "prepaid_cards": "Cartes prépayées", "prevent_screenshots": "Empêcher les captures d'écran et l'enregistrement d'écran", "privacy": "Confidentialité", "privacy_policy": "Politique de confidentialité", @@ -467,6 +474,7 @@ "purple_dark_theme": "THÈME PURPLE DARK", "qr_fullscreen": "Appuyez pour ouvrir le QR code en mode plein écran", "qr_payment_amount": "Ce QR code contient un montant de paiement. Voulez-vous remplacer la valeur actuelle ?", + "quantity": "Quantité", "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.", "receivable_balance": "Solde de créances", "receive": "Recevoir", @@ -708,6 +716,7 @@ "tokenID": "IDENTIFIANT", "tor_connection": "Connexion Tor", "tor_only": "Tor uniquement", + "total": "Total", "total_saving": "Économies totales", "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.", "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 @@ "use_ssl": "Utiliser SSL", "use_suggested": "Suivre la suggestion", "use_testnet": "Utiliser TestNet", + "value": "Valeur", + "value_type": "Type de valeur", "variable_pair_not_supported": "Cette paire variable n'est pas prise en charge avec les échanges sélectionnés", "verification": "Vérification", "verify_with_2fa": "Vérifier avec Cake 2FA", diff --git a/res/values/strings_ha.arb b/res/values/strings_ha.arb index 5809f3d2e..dd3350131 100644 --- a/res/values/strings_ha.arb +++ b/res/values/strings_ha.arb @@ -87,6 +87,7 @@ "buy": "Sayi", "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.", "buy_bitcoin": "Sayi Bitcoin", + "buy_now": "Saya yanzu", "buy_provider_unavailable": "Mai ba da kyauta a halin yanzu babu.", "buy_with": "Saya da", "by_cake_pay": "da Cake Pay", @@ -94,8 +95,7 @@ "cake_dark_theme": "Cake Dark Jigo", "cake_pay_account_note": "Yi rajista tare da adireshin imel kawai don gani da siyan katunan. Wasu ma suna samuwa a rangwame!", "cake_pay_learn_more": "Nan take siya ku kwaso katunan kyaututtuka a cikin app!\nTake hagu zuwa dama don ƙarin koyo.", - "cake_pay_subtitle": "Sayi katunan kyauta masu rahusa (Amurka kawai)", - "cake_pay_title": "Cake Pay Gift Cards", + "cake_pay_subtitle": "Sayi katunan shirye-shiryen duniya da katunan kyauta", "cake_pay_web_cards_subtitle": "Sayi katunan da aka riga aka biya na duniya da katunan kyauta", "cake_pay_web_cards_title": "Cake Pay Web Cards", "cake_wallet": "Cake Wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "Canja walat yanzu", "choose_account": "Zaɓi asusu", "choose_address": "\n\n Da fatan za a zaɓi adireshin:", + "choose_card_value": "Zabi darajar katin", "choose_derivation": "Zaɓi walatawa", "choose_from_available_options": "Zaɓi daga zaɓuɓɓukan da ake da su:", "choose_one": "Zaɓi ɗaya", @@ -166,6 +167,7 @@ "copy_address": "Kwafi Adireshin", "copy_id": "Kwafi ID", "copyWalletConnectLink": "Kwafi hanyar haɗin WalletConnect daga dApp kuma liƙa a nan", + "countries": "Kasashe", "create_account": "Kirkira ajiya", "create_backup": "Ƙirƙiri madadin", "create_donation_link": "Sanya hanyar sadaka", @@ -178,6 +180,7 @@ "custom": "al'ada", "custom_drag": "Al'ada (riƙe da ja)", "custom_redeem_amount": "Adadin Fansa na Musamman", + "custom_value": "Darajar al'ada", "dark_theme": "Duhu", "debit_card": "Katin Zare kudi", "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 @@ "delete_wallet": "Share walat", "delete_wallet_confirm_message": "Shin kun tabbata cewa kuna son share jakar ${wallet_name}?", "deleteConnectionConfirmationPrompt": "Shin kun tabbata cewa kuna son share haɗin zuwa", + "denominations": "Denominations", "descending": "Saukowa", "description": "Bayani", "destination_tag": "Tambarin makoma:", @@ -277,6 +281,7 @@ "expired": "Karewa", "expires": "Ya ƙare", "expiresOn": "Yana ƙarewa", + "expiry_and_validity": "Karewa da inganci", "export_backup": "Ajiyayyen fitarwa", "extra_id": "Karin ID:", "extracted_address_content": "Za ku aika da kudade zuwa\n${recipient_name}", @@ -384,6 +389,7 @@ "new_template": "Sabon Samfura", "new_wallet": "Sabuwar Wallet", "newConnection": "Sabuwar Haɗi", + "no_cards_found": "Babu katunan da aka samo", "no_id_needed": "Babu ID da ake buƙata!", "no_id_required": "Babu ID da ake buƙata. Yi da kuma ciyar a ko'ina", "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 @@ "pre_seed_button_text": "Ina fahimta. Nuna mini seed din nawa", "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.", "pre_seed_title": "MUHIMMANCI", + "prepaid_cards": "Katunan shirye-shirye", "prevent_screenshots": "Fada lambobi da jarrabobi na kayan lambobi", "privacy": "Keɓantawa", "privacy_policy": "takardar kebantawa", @@ -469,6 +476,7 @@ "purple_dark_theme": "M duhu jigo", "qr_fullscreen": "Matsa don buɗe lambar QR na cikakken allo", "qr_payment_amount": "Wannan QR code yana da adadin kuɗi. Kuna so ku overwrite wannan adadi?", + "quantity": "Yawa", "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.", "receivable_balance": "Daidaituwa da daidaituwa", "receive": "Samu", @@ -710,6 +718,7 @@ "tokenID": "ID", "tor_connection": "Tor haɗin gwiwa", "tor_only": "Tor kawai", + "total": "Duka", "total_saving": "Jimlar Adana", "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.", "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 @@ "use_ssl": "Yi amfani da SSL", "use_suggested": "Amfani da Shawarwari", "use_testnet": "Amfani da gwaji", + "value": "Daraja", + "value_type": "Nau'in darajar", "variable_pair_not_supported": "Ba a samun goyan bayan wannan m biyu tare da zaɓaɓɓun musayar", "verification": "tabbatar", "verify_with_2fa": "Tabbatar da Cake 2FA", diff --git a/res/values/strings_hi.arb b/res/values/strings_hi.arb index 0b21747b4..55aead5a3 100644 --- a/res/values/strings_hi.arb +++ b/res/values/strings_hi.arb @@ -87,6 +87,7 @@ "buy": "खरीदें", "buy_alert_content": "वर्तमान में हम केवल बिटकॉइन, एथेरियम, लाइटकॉइन और मोनेरो की खरीद का समर्थन करते हैं। कृपया अपना बिटकॉइन, एथेरियम, लाइटकॉइन, या मोनेरो वॉलेट बनाएं या उस पर स्विच करें।", "buy_bitcoin": "बिटकॉइन खरीदें", + "buy_now": "अभी खरीदें", "buy_provider_unavailable": "वर्तमान में प्रदाता अनुपलब्ध है।", "buy_with": "के साथ खरीदें", "by_cake_pay": "केकपे द्वारा", @@ -94,8 +95,7 @@ "cake_dark_theme": "केक डार्क थीम", "cake_pay_account_note": "कार्ड देखने और खरीदने के लिए केवल एक ईमेल पते के साथ साइन अप करें। कुछ छूट पर भी उपलब्ध हैं!", "cake_pay_learn_more": "ऐप में उपहार कार्ड तुरंत खरीदें और रिडीम करें!\nअधिक जानने के लिए बाएं से दाएं स्वाइप करें।", - "cake_pay_subtitle": "रियायती उपहार कार्ड खरीदें (केवल यूएसए)", - "cake_pay_title": "केक पे गिफ्ट कार्ड्स", + "cake_pay_subtitle": "दुनिया भर में प्रीपेड कार्ड और उपहार कार्ड खरीदें", "cake_pay_web_cards_subtitle": "दुनिया भर में प्रीपेड कार्ड और गिफ्ट कार्ड खरीदें", "cake_pay_web_cards_title": "केक भुगतान वेब कार्ड", "cake_wallet": "Cake Wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "वर्तमान बटुआ बदलें", "choose_account": "खाता चुनें", "choose_address": "\n\nकृपया पता चुनें:", + "choose_card_value": "एक कार्ड मूल्य चुनें", "choose_derivation": "वॉलेट व्युत्पत्ति चुनें", "choose_from_available_options": "उपलब्ध विकल्पों में से चुनें:", "choose_one": "एक का चयन", @@ -166,6 +167,7 @@ "copy_address": "पता कॉपी करें", "copy_id": "प्रतिलिपि ID", "copyWalletConnectLink": "dApp से वॉलेटकनेक्ट लिंक को कॉपी करें और यहां पेस्ट करें", + "countries": "देशों", "create_account": "खाता बनाएं", "create_backup": "बैकअप बनाएँ", "create_donation_link": "दान लिंक बनाएं", @@ -178,6 +180,7 @@ "custom": "कस्टम", "custom_drag": "कस्टम (पकड़ और खींचें)", "custom_redeem_amount": "कस्टम रिडीम राशि", + "custom_value": "कस्टम मूल्य", "dark_theme": "अंधेरा", "debit_card": "डेबिट कार्ड", "debit_card_terms": "इस डिजिटल वॉलेट में आपके भुगतान कार्ड नंबर (और आपके भुगतान कार्ड नंबर से संबंधित क्रेडेंशियल) का भंडारण और उपयोग भुगतान कार्ड जारीकर्ता के साथ लागू कार्डधारक समझौते के नियमों और शर्तों के अधीन है, जैसा कि प्रभावी है समय - समय पर।", @@ -190,6 +193,7 @@ "delete_wallet": "वॉलेट हटाएं", "delete_wallet_confirm_message": "क्या आप वाकई ${wallet_name} वॉलेट हटाना चाहते हैं?", "deleteConnectionConfirmationPrompt": "क्या आप वाकई कनेक्शन हटाना चाहते हैं?", + "denominations": "मूल्यवर्ग", "descending": "अवरोही", "description": "विवरण", "destination_tag": "गंतव्य टैग:", @@ -277,6 +281,7 @@ "expired": "समय सीमा समाप्त", "expires": "समाप्त हो जाता है", "expiresOn": "पर समय सीमा समाप्त", + "expiry_and_validity": "समाप्ति और वैधता", "export_backup": "निर्यात बैकअप", "extra_id": "अतिरिक्त आईडी:", "extracted_address_content": "आपको धनराशि भेजी जाएगी\n${recipient_name}", @@ -384,6 +389,7 @@ "new_template": "नया टेम्पलेट", "new_wallet": "नया बटुआ", "newConnection": "नया कनेक्शन", + "no_cards_found": "कोई कार्ड नहीं मिला", "no_id_needed": "कोई आईडी नहीं चाहिए!", "no_id_required": "कोई आईडी आवश्यक नहीं है। टॉप अप करें और कहीं भी खर्च करें", "no_relay_on_domain": "उपयोगकर्ता के डोमेन के लिए कोई रिले नहीं है या रिले अनुपलब्ध है। कृपया उपयोग करने के लिए एक रिले चुनें।", @@ -453,6 +459,7 @@ "pre_seed_button_text": "मै समझता हुँ। मुझे अपना बीज दिखाओ", "pre_seed_description": "अगले पेज पर आपको ${words} शब्दों की एक श्रृंखला दिखाई देगी। यह आपका अद्वितीय और निजी बीज है और नुकसान या खराबी के मामले में अपने बटुए को पुनर्प्राप्त करने का एकमात्र तरीका है। यह आपकी जिम्मेदारी है कि इसे नीचे लिखें और इसे Cake Wallet ऐप के बाहर सुरक्षित स्थान पर संग्रहीत करें।", "pre_seed_title": "महत्वपूर्ण", + "prepaid_cards": "पूर्वदत्त कार्ड", "prevent_screenshots": "स्क्रीनशॉट और स्क्रीन रिकॉर्डिंग रोकें", "privacy": "गोपनीयता", "privacy_policy": "गोपनीयता नीति", @@ -468,6 +475,7 @@ "purple_dark_theme": "पर्पल डार्क थीम", "qr_fullscreen": "फ़ुल स्क्रीन क्यूआर कोड खोलने के लिए टैप करें", "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?", + "quantity": "मात्रा", "question_to_disable_2fa": "क्या आप सुनिश्चित हैं कि आप Cake 2FA को अक्षम करना चाहते हैं? वॉलेट और कुछ कार्यों तक पहुँचने के लिए अब 2FA कोड की आवश्यकता नहीं होगी।", "ready_have_account": "क्या आपके पास पहले से ही एक खाता है?", "receivable_balance": "प्राप्य शेष", @@ -710,6 +718,7 @@ "tokenID": "पहचान", "tor_connection": "टोर कनेक्शन", "tor_only": "Tor केवल", + "total": "कुल", "total_saving": "कुल बचत", "totp_2fa_failure": "गलत कोड़। कृपया एक अलग कोड का प्रयास करें या एक नई गुप्त कुंजी उत्पन्न करें। 8-अंकीय कोड और SHA512 का समर्थन करने वाले संगत 2FA ऐप का उपयोग करें।", "totp_2fa_success": "सफलता! इस वॉलेट के लिए Cake 2FA सक्षम है। यदि आप वॉलेट एक्सेस खो देते हैं तो अपने स्मरक बीज को सहेजना याद रखें।", @@ -800,6 +809,8 @@ "use_ssl": "उपयोग SSL", "use_suggested": "सुझाए गए का प्रयोग करें", "use_testnet": "टेस्टनेट का उपयोग करें", + "value": "कीमत", + "value_type": "मान प्रकार", "variable_pair_not_supported": "यह परिवर्तनीय जोड़ी चयनित एक्सचेंजों के साथ समर्थित नहीं है", "verification": "सत्यापन", "verify_with_2fa": "केक 2FA के साथ सत्यापित करें", diff --git a/res/values/strings_hr.arb b/res/values/strings_hr.arb index dd2093a03..c999b7dfd 100644 --- a/res/values/strings_hr.arb +++ b/res/values/strings_hr.arb @@ -87,6 +87,7 @@ "buy": "Kupi", "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.", "buy_bitcoin": "Kupite Bitcoin", + "buy_now": "Kupi sada", "buy_provider_unavailable": "Davatelj trenutno nije dostupan.", "buy_with": "Kupite s", "by_cake_pay": "od Cake Paya", @@ -94,8 +95,7 @@ "cake_dark_theme": "TOKA DARKA TEMA", "cake_pay_account_note": "Prijavite se samo s adresom e-pošte da biste vidjeli i kupili kartice. Neke su čak dostupne uz popust!", "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.", - "cake_pay_subtitle": "Kupite darovne kartice s popustom (samo SAD)", - "cake_pay_title": "Cake Pay poklon kartice", + "cake_pay_subtitle": "Kupite svjetske unaprijed plaćene kartice i poklon kartice", "cake_pay_web_cards_subtitle": "Kupujte prepaid kartice i poklon kartice diljem svijeta", "cake_pay_web_cards_title": "Cake Pay Web kartice", "cake_wallet": "Cake Wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "Izmijeni trenutni novčanik", "choose_account": "Odaberi račun", "choose_address": "\n\nOdaberite adresu:", + "choose_card_value": "Odaberite vrijednost kartice", "choose_derivation": "Odaberite izvedbu novčanika", "choose_from_available_options": "Odaberite neku od dostupnih opcija:", "choose_one": "Izaberi jedan", @@ -166,6 +167,7 @@ "copy_address": "Kopiraj adresu", "copy_id": "Kopirati ID", "copyWalletConnectLink": "Kopirajte vezu WalletConnect iz dApp-a i zalijepite je ovdje", + "countries": "Zemalja", "create_account": "Stvori račun", "create_backup": "Stvori sigurnosnu kopiju", "create_donation_link": "Izradi poveznicu za donaciju", @@ -178,6 +180,7 @@ "custom": "prilagođeno", "custom_drag": "Prilagođeni (držite i povucite)", "custom_redeem_amount": "Prilagođeni iznos otkupa", + "custom_value": "Prilagođena vrijednost", "dark_theme": "Tamna", "debit_card": "Debitna kartica", "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 @@ "delete_wallet": "Izbriši novčanik", "delete_wallet_confirm_message": "Jeste li sigurni da želite izbrisati ${wallet_name} novčanik?", "deleteConnectionConfirmationPrompt": "Jeste li sigurni da želite izbrisati vezu s", + "denominations": "Denominacije", "descending": "Silazni", "description": "Opis", "destination_tag": "Odredišna oznaka:", @@ -277,6 +281,7 @@ "expired": "Isteklo", "expires": "Ističe", "expiresOn": "Istječe", + "expiry_and_validity": "Istek i valjanost", "export_backup": "Izvezi sigurnosnu kopiju", "extra_id": "Dodatni ID:", "extracted_address_content": "Poslat ćete sredstva primatelju\n${recipient_name}", @@ -308,7 +313,7 @@ "gift_card_is_generated": "Poklon kartica je generirana", "gift_card_number": "Broj darovne kartice", "gift_card_redeemed_note": "Poklon kartice koje ste iskoristili pojavit će se ovdje", - "gift_cards": "Ajándékkártya", + "gift_cards": "Darovne kartice", "gift_cards_unavailable": "Poklon kartice trenutno su dostupne za kupnju samo putem Monera, Bitcoina i Litecoina", "got_it": "U redu", "gross_balance": "Bruto bilanca", @@ -384,6 +389,7 @@ "new_template": "novi predložak", "new_wallet": "Novi novčanik", "newConnection": "Nova veza", + "no_cards_found": "Nisu pronađene kartice", "no_id_needed": "Nije potreban ID!", "no_id_required": "Nije potreban ID. Nadopunite i potrošite bilo gdje", "no_relay_on_domain": "Ne postoji relej za korisničku domenu ili je relej nedostupan. Odaberite relej za korištenje.", @@ -452,6 +458,7 @@ "pre_seed_button_text": "Razumijem. Prikaži mi moj pristupni izraz", "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.", "pre_seed_title": "VAŽNO", + "prepaid_cards": "Unaprijed plaćene kartice", "prevent_screenshots": "Spriječite snimke zaslona i snimanje zaslona", "privacy": "Privatnost", "privacy_policy": "Pravila privatnosti", @@ -467,6 +474,7 @@ "purple_dark_theme": "Ljubičasta tamna tema", "qr_fullscreen": "Dodirnite za otvaranje QR koda preko cijelog zaslona", "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?", + "quantity": "Količina", "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.", "receivable_balance": "Stanje potraživanja", "receive": "Primi", @@ -708,6 +716,7 @@ "tokenID": "iskaznica", "tor_connection": "Tor veza", "tor_only": "Samo Tor", + "total": "Ukupno", "total_saving": "Ukupna ušteda", "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.", "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 @@ "use_ssl": "Koristi SSL", "use_suggested": "Koristite predloženo", "use_testnet": "Koristite TestNet", + "value": "Vrijednost", + "value_type": "Tipa vrijednosti", "variable_pair_not_supported": "Ovaj par varijabli nije podržan s odabranim burzama", "verification": "Potvrda", "verify_with_2fa": "Provjerite s Cake 2FA", diff --git a/res/values/strings_id.arb b/res/values/strings_id.arb index 3726d431b..24208718c 100644 --- a/res/values/strings_id.arb +++ b/res/values/strings_id.arb @@ -87,6 +87,7 @@ "buy": "Beli", "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.", "buy_bitcoin": "Beli Bitcoin", + "buy_now": "Beli sekarang", "buy_provider_unavailable": "Penyedia saat ini tidak tersedia.", "buy_with": "Beli dengan", "by_cake_pay": "oleh Cake Pay", @@ -94,8 +95,7 @@ "cake_dark_theme": "Tema Kue Gelap", "cake_pay_account_note": "Daftar hanya dengan alamat email untuk melihat dan membeli kartu. Beberapa di antaranya bahkan tersedia dengan diskon!", "cake_pay_learn_more": "Beli dan tukar kartu hadiah secara instan di aplikasi!\nGeser ke kanan untuk informasi lebih lanjut.", - "cake_pay_subtitle": "Beli kartu hadiah dengan harga diskon (hanya USA)", - "cake_pay_title": "Kartu Hadiah Cake Pay", + "cake_pay_subtitle": "Beli kartu prabayar di seluruh dunia dan kartu hadiah", "cake_pay_web_cards_subtitle": "Beli kartu prabayar dan kartu hadiah secara global", "cake_pay_web_cards_title": "Kartu Web Cake Pay", "cake_wallet": "Cake Wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "Ganti dompet saat ini", "choose_account": "Pilih akun", "choose_address": "\n\nSilakan pilih alamat:", + "choose_card_value": "Pilih nilai kartu", "choose_derivation": "Pilih dompet dompet", "choose_from_available_options": "Pilih dari pilihan yang tersedia:", "choose_one": "Pilih satu", @@ -166,6 +167,7 @@ "copy_address": "Salin Alamat", "copy_id": "Salin ID", "copyWalletConnectLink": "Salin tautan WalletConnect dari dApp dan tempel di sini", + "countries": "Negara", "create_account": "Buat Akun", "create_backup": "Buat cadangan", "create_donation_link": "Buat tautan donasi", @@ -178,6 +180,7 @@ "custom": "kustom", "custom_drag": "Khusus (tahan dan seret)", "custom_redeem_amount": "Jumlah Tukar Kustom", + "custom_value": "Nilai khusus", "dark_theme": "Gelap", "debit_card": "Kartu Debit", "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 @@ "delete_wallet": "Hapus dompet", "delete_wallet_confirm_message": "Apakah Anda yakin ingin menghapus dompet ${wallet_name}?", "deleteConnectionConfirmationPrompt": "Apakah Anda yakin ingin menghapus koneksi ke", + "denominations": "Denominasi", "descending": "Menurun", "description": "Keterangan", "destination_tag": "Tag tujuan:", @@ -277,6 +281,7 @@ "expired": "Kedaluwarsa", "expires": "Kadaluarsa", "expiresOn": "Kadaluarsa pada", + "expiry_and_validity": "Kedaluwarsa dan validitas", "export_backup": "Ekspor cadangan", "extra_id": "ID tambahan:", "extracted_address_content": "Anda akan mengirim dana ke\n${recipient_name}", @@ -308,7 +313,7 @@ "gift_card_is_generated": "Kartu Hadiah telah dibuat", "gift_card_number": "Nomor Kartu Hadiah", "gift_card_redeemed_note": "Kartu hadiah yang sudah Anda tukar akan muncul di sini", - "gift_cards": "Kartu Hadiah", + "gift_cards": "Kartu hadiah", "gift_cards_unavailable": "Kartu hadiah hanya tersedia untuk dibeli dengan Monero, Bitcoin, dan Litecoin saat ini", "got_it": "Sudah paham", "gross_balance": "Saldo Kotor", @@ -384,6 +389,7 @@ "new_template": "Template Baru", "new_wallet": "Dompet Baru", "newConnection": "Koneksi Baru", + "no_cards_found": "Tidak ada kartu yang ditemukan", "no_id_needed": "Tidak perlu ID!", "no_id_required": "Tidak perlu ID. Isi ulang dan belanja di mana saja", "no_relay_on_domain": "Tidak ada relai untuk domain pengguna atau relai tidak tersedia. Silakan pilih relai yang akan digunakan.", @@ -454,6 +460,7 @@ "pre_seed_button_text": "Saya mengerti. Tampilkan seed saya", "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.", "pre_seed_title": "PENTING", + "prepaid_cards": "Kartu prabayar", "prevent_screenshots": "Cegah tangkapan layar dan perekaman layar", "privacy": "Privasi", "privacy_policy": "Kebijakan Privasi", @@ -469,6 +476,7 @@ "purple_dark_theme": "Tema gelap ungu", "qr_fullscreen": "Tap untuk membuka layar QR code penuh", "qr_payment_amount": "QR code ini berisi jumlah pembayaran. Apakah Anda ingin menimpa nilai saat ini?", + "quantity": "Kuantitas", "question_to_disable_2fa": "Apakah Anda yakin ingin menonaktifkan Cake 2FA? Kode 2FA tidak lagi diperlukan untuk mengakses dompet dan fungsi tertentu.", "receivable_balance": "Saldo piutang", "receive": "Menerima", @@ -711,6 +719,7 @@ "tokenID": "PENGENAL", "tor_connection": "koneksi Tor", "tor_only": "Hanya Tor", + "total": "Total", "total_saving": "Total Pembayaran", "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.", "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 @@ "use_ssl": "Gunakan SSL", "use_suggested": "Gunakan yang Disarankan", "use_testnet": "Gunakan TestNet", + "value": "Nilai", + "value_type": "Jenis Nilai", "variable_pair_not_supported": "Pasangan variabel ini tidak didukung dengan bursa yang dipilih", "verification": "Verifikasi", "verify_with_2fa": "Verifikasi dengan Cake 2FA", diff --git a/res/values/strings_it.arb b/res/values/strings_it.arb index 92c893fd2..5509c0067 100644 --- a/res/values/strings_it.arb +++ b/res/values/strings_it.arb @@ -87,6 +87,7 @@ "buy": "Comprare", "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.", "buy_bitcoin": "Acquista Bitcoin", + "buy_now": "Acquista ora", "buy_provider_unavailable": "Provider attualmente non disponibile.", "buy_with": "Acquista con", "by_cake_pay": "da Cake Pay", @@ -94,8 +95,7 @@ "cake_dark_theme": "Tema oscuro della torta", "cake_pay_account_note": "Iscriviti con solo un indirizzo email per vedere e acquistare le carte. Alcune sono anche disponibili con uno sconto!", "cake_pay_learn_more": "Acquista e riscatta istantaneamente carte regalo nell'app!\nScorri da sinistra a destra per saperne di più.", - "cake_pay_subtitle": "Acquista buoni regalo scontati (solo USA)", - "cake_pay_title": "Carte regalo Cake Pay", + "cake_pay_subtitle": "Acquista carte prepagate in tutto il mondo e carte regalo", "cake_pay_web_cards_subtitle": "Acquista carte prepagate e carte regalo in tutto il mondo", "cake_pay_web_cards_title": "Carte Web Cake Pay", "cake_wallet": "Cake Wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "Cambia portafoglio attuale", "choose_account": "Scegli account", "choose_address": "\n\nSi prega di scegliere l'indirizzo:", + "choose_card_value": "Scegli un valore della carta", "choose_derivation": "Scegli la derivazione del portafoglio", "choose_from_available_options": "Scegli tra le opzioni disponibili:", "choose_one": "Scegline uno", @@ -167,6 +168,7 @@ "copy_address": "Copia Indirizzo", "copy_id": "Copia ID", "copyWalletConnectLink": "Copia il collegamento WalletConnect dalla dApp e incollalo qui", + "countries": "Paesi", "create_account": "Crea account", "create_backup": "Crea backup", "create_donation_link": "Crea un link per la donazione", @@ -179,6 +181,7 @@ "custom": "personalizzato", "custom_drag": "Custom (Hold and Drag)", "custom_redeem_amount": "Importo di riscatto personalizzato", + "custom_value": "Valore personalizzato", "dark_theme": "Scuro", "debit_card": "Carta di debito", "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 @@ "delete_wallet": "Elimina portafoglio", "delete_wallet_confirm_message": "Sei sicuro di voler eliminare il portafoglio ${wallet_name}?", "deleteConnectionConfirmationPrompt": "Sei sicuro di voler eliminare la connessione a", + "denominations": "Denominazioni", "descending": "Discendente", "description": "Descrizione", "destination_tag": "Tag destinazione:", @@ -278,6 +282,7 @@ "expired": "Scaduta", "expires": "Scade", "expiresOn": "Scade il", + "expiry_and_validity": "Scadenza e validità", "export_backup": "Esporta backup", "extra_id": "Extra ID:", "extracted_address_content": "Invierai i tuoi fondi a\n${recipient_name}", @@ -385,6 +390,7 @@ "new_template": "Nuovo modello", "new_wallet": "Nuovo Portafoglio", "newConnection": "Nuova connessione", + "no_cards_found": "Nessuna carta trovata", "no_id_needed": "Nessun ID necessario!", "no_id_required": "Nessun ID richiesto. Ricarica e spendi ovunque", "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 @@ "pre_seed_button_text": "Ho capito. Mostrami il seme", "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.", "pre_seed_title": "IMPORTANTE", + "prepaid_cards": "Carte prepagata", "prevent_screenshots": "Impedisci screenshot e registrazione dello schermo", "privacy": "Privacy", "privacy_policy": "Informativa sulla privacy", @@ -469,6 +476,7 @@ "purple_dark_theme": "Tema oscuro viola", "qr_fullscreen": "Tocca per aprire il codice QR a schermo intero", "qr_payment_amount": "Questo codice QR contiene l'ammontare del pagamento. Vuoi sovrascrivere il varlore attuale?", + "quantity": "Quantità", "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.", "receivable_balance": "Bilanciamento creditizio", "receive": "Ricevi", @@ -710,6 +718,7 @@ "tokenID": "ID", "tor_connection": "Connessione Tor", "tor_only": "Solo Tor", + "total": "Totale", "total_saving": "Risparmio totale", "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.", "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 @@ "use_ssl": "Usa SSL", "use_suggested": "Usa suggerito", "use_testnet": "Usa TestNet", + "value": "Valore", + "value_type": "Tipo di valore", "variable_pair_not_supported": "Questa coppia di variabili non è supportata con gli scambi selezionati", "verification": "Verifica", "verify_with_2fa": "Verifica con Cake 2FA", diff --git a/res/values/strings_ja.arb b/res/values/strings_ja.arb index e3e105d4a..9204ffdf4 100644 --- a/res/values/strings_ja.arb +++ b/res/values/strings_ja.arb @@ -87,6 +87,7 @@ "buy": "購入", "buy_alert_content": "現在、ビットコイン、イーサリアム、ライトコイン、モネロの購入のみをサポートしています。ビットコイン、イーサリアム、ライトコイン、またはモネロのウォレットを作成するか、これらのウォレットに切り替えてください。", "buy_bitcoin": "ビットコインを購入する", + "buy_now": "今すぐ購入", "buy_provider_unavailable": "現在、プロバイダーは利用できません。", "buy_with": "で購入", "by_cake_pay": "by Cake Pay", @@ -94,8 +95,7 @@ "cake_dark_theme": "ケーキ暗いテーマ", "cake_pay_account_note": "メールアドレスだけでサインアップして、カードを表示して購入できます。割引価格で利用できるカードもあります!", "cake_pay_learn_more": "アプリですぐにギフトカードを購入して引き換えましょう!\n左から右にスワイプして詳細をご覧ください。", - "cake_pay_subtitle": "割引ギフトカードを購入する (米国のみ)", - "cake_pay_title": "ケーキペイギフトカード", + "cake_pay_subtitle": "世界中のプリペイドカードとギフトカードを購入します", "cake_pay_web_cards_subtitle": "世界中のプリペイド カードとギフト カードを購入する", "cake_pay_web_cards_title": "Cake Pay ウェブカード", "cake_wallet": "Cake Wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "現在のウォレットを変更する", "choose_account": "アカウントを選択", "choose_address": "\n\n住所を選択してください:", + "choose_card_value": "カード値を選択します", "choose_derivation": "ウォレット派生を選択します", "choose_from_available_options": "利用可能なオプションから選択してください:", "choose_one": "1 つ選択してください", @@ -166,6 +167,7 @@ "copy_address": "住所をコピー", "copy_id": "IDをコピー", "copyWalletConnectLink": "dApp から WalletConnect リンクをコピーし、ここに貼り付けます", + "countries": "国", "create_account": "アカウントの作成", "create_backup": "バックアップを作成", "create_donation_link": "寄付リンクを作成", @@ -178,6 +180,7 @@ "custom": "カスタム", "custom_drag": "カスタム(ホールドとドラッグ)", "custom_redeem_amount": "カスタム交換金額", + "custom_value": "カスタム値", "dark_theme": "闇", "debit_card": "デビットカード", "debit_card_terms": "このデジタルウォレットでの支払いカード番号(および支払いカード番号に対応する資格情報)の保存と使用には、支払いカード発行者との該当するカード所有者契約の利用規約が適用されます。時々。", @@ -190,6 +193,7 @@ "delete_wallet": "ウォレットを削除", "delete_wallet_confirm_message": "${wallet_name} ウォレットを削除してもよろしいですか?", "deleteConnectionConfirmationPrompt": "への接続を削除してもよろしいですか?", + "denominations": "宗派", "descending": "下降", "description": "説明", "destination_tag": "宛先タグ:", @@ -277,6 +281,7 @@ "expired": "期限切れ", "expires": "Expires", "expiresOn": "有効期限は次のとおりです", + "expiry_and_validity": "有効期限と有効性", "export_backup": "バックアップのエクスポート", "extra_id": "追加ID:", "extracted_address_content": "に送金します\n${recipient_name}", @@ -385,6 +390,7 @@ "new_template": "新しいテンプレート", "new_wallet": "新しいウォレット", "newConnection": "新しい接続", + "no_cards_found": "カードは見つかりません", "no_id_needed": "IDは必要ありません!", "no_id_required": "IDは必要ありません。どこにでも補充して使用できます", "no_relay_on_domain": "ユーザーのドメインのリレーが存在しないか、リレーが使用できません。使用するリレーを選択してください。", @@ -453,6 +459,7 @@ "pre_seed_button_text": "わかります。 種を見せて", "pre_seed_description": "次のページでは、一連の${words}語が表示されます。 これはあなたのユニークでプライベートなシードであり、紛失や誤動作が発生した場合にウォレットを回復する唯一の方法です。 それを書き留めて、Cake Wallet アプリの外の安全な場所に保管するのはあなたの責任です。", "pre_seed_title": "重要", + "prepaid_cards": "プリペイドカード", "prevent_screenshots": "スクリーンショットと画面録画を防止する", "privacy": "プライバシー", "privacy_policy": "プライバシーポリシー", @@ -468,6 +475,7 @@ "purple_dark_theme": "紫色の暗いテーマ", "qr_fullscreen": "タップして全画面QRコードを開く", "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?", + "quantity": "量", "question_to_disable_2fa": "Cake 2FA を無効にしてもよろしいですか?ウォレットと特定の機能にアクセスするために 2FA コードは必要なくなります。", "receivable_balance": "売掛金残高", "receive": "受け取る", @@ -709,6 +717,7 @@ "tokenID": "ID", "tor_connection": "Tor接続", "tor_only": "Torのみ", + "total": "合計", "total_saving": "合計節約額", "totp_2fa_failure": "コードが正しくありません。 別のコードを試すか、新しい秘密鍵を生成してください。 8 桁のコードと SHA512 をサポートする互換性のある 2FA アプリを使用してください。", "totp_2fa_success": "成功!このウォレットでは Cake 2FA が有効になっています。ウォレットへのアクセスを失った場合に備えて、ニーモニック シードを忘れずに保存してください。", @@ -799,6 +808,8 @@ "use_ssl": "SSLを使用する", "use_suggested": "推奨を使用", "use_testnet": "テストネットを使用します", + "value": "価値", + "value_type": "値タイプ", "variable_pair_not_supported": "この変数ペアは、選択した取引所ではサポートされていません", "verification": "検証", "verify_with_2fa": "Cake 2FA で検証する", diff --git a/res/values/strings_ko.arb b/res/values/strings_ko.arb index bf1e4ee61..99d138de1 100644 --- a/res/values/strings_ko.arb +++ b/res/values/strings_ko.arb @@ -87,6 +87,7 @@ "buy": "구입", "buy_alert_content": "현재 Bitcoin, Ethereum, Litecoin 및 Monero 구매만 지원합니다. Bitcoin, Ethereum, Litecoin 또는 Monero 지갑을 생성하거나 전환하십시오.", "buy_bitcoin": "비트 코인 구매", + "buy_now": "지금 구매하십시오", "buy_provider_unavailable": "제공자는 현재 사용할 수 없습니다.", "buy_with": "구매", "by_cake_pay": "Cake Pay로", @@ -94,8 +95,7 @@ "cake_dark_theme": "케이크 다크 테마", "cake_pay_account_note": "이메일 주소로 가입하면 카드를 보고 구매할 수 있습니다. 일부는 할인된 가격으로 사용 가능합니다!", "cake_pay_learn_more": "앱에서 즉시 기프트 카드를 구매하고 사용하세요!\n자세히 알아보려면 왼쪽에서 오른쪽으로 스와이프하세요.", - "cake_pay_subtitle": "할인된 기프트 카드 구매(미국만 해당)", - "cake_pay_title": "케이크 페이 기프트 카드", + "cake_pay_subtitle": "전세계 선불 카드와 기프트 카드를 구입하십시오", "cake_pay_web_cards_subtitle": "전 세계 선불 카드 및 기프트 카드 구매", "cake_pay_web_cards_title": "케이크페이 웹카드", "cake_wallet": "Cake Wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "현재 지갑 변경", "choose_account": "계정을 선택하십시오", "choose_address": "\n\n주소를 선택하십시오:", + "choose_card_value": "카드 값을 선택하십시오", "choose_derivation": "지갑 파생을 선택하십시오", "choose_from_available_options": "사용 가능한 옵션에서 선택:", "choose_one": "하나 선택", @@ -166,6 +167,7 @@ "copy_address": "주소 복사", "copy_id": "부 ID", "copyWalletConnectLink": "dApp에서 WalletConnect 링크를 복사하여 여기에 붙여넣으세요.", + "countries": "국가", "create_account": "계정 만들기", "create_backup": "백업 생성", "create_donation_link": "기부 링크 만들기", @@ -178,6 +180,7 @@ "custom": "커스텀", "custom_drag": "사용자 정의 (홀드 앤 드래그)", "custom_redeem_amount": "사용자 지정 상환 금액", + "custom_value": "맞춤 가치", "dark_theme": "어두운", "debit_card": "직불 카드", "debit_card_terms": "이 디지털 지갑에 있는 귀하의 지불 카드 번호(및 귀하의 지불 카드 번호에 해당하는 자격 증명)의 저장 및 사용은 부터 발효되는 지불 카드 발행자와의 해당 카드 소지자 계약의 이용 약관을 따릅니다. 수시로.", @@ -190,6 +193,7 @@ "delete_wallet": "지갑 삭제", "delete_wallet_confirm_message": "${wallet_name} 지갑을 삭제하시겠습니까?", "deleteConnectionConfirmationPrompt": "다음 연결을 삭제하시겠습니까?", + "denominations": "교파", "descending": "내림차순", "description": "설명", "destination_tag": "목적지 태그:", @@ -277,6 +281,7 @@ "expired": "만료", "expires": "만료", "expiresOn": "만료 날짜", + "expiry_and_validity": "만료와 타당성", "export_backup": "백업 내보내기", "extra_id": "추가 ID:", "extracted_address_content": "당신은에 자금을 보낼 것입니다\n${recipient_name}", @@ -384,6 +389,7 @@ "new_template": "새 템플릿", "new_wallet": "새 월렛", "newConnection": "새로운 연결", + "no_cards_found": "카드를 찾지 못했습니다", "no_id_needed": "ID가 필요하지 않습니다!", "no_id_required": "신분증이 필요하지 않습니다. 충전하고 어디에서나 사용하세요", "no_relay_on_domain": "사용자 도메인에 릴레이가 없거나 릴레이를 사용할 수 없습니다. 사용할 릴레이를 선택해주세요.", @@ -453,6 +459,7 @@ "pre_seed_button_text": "이해 했어요. 내 씨앗을 보여줘", "pre_seed_description": "다음 페이지에서 ${words} 개의 단어를 볼 수 있습니다. 이것은 귀하의 고유하고 개인적인 시드이며 분실 또는 오작동시 지갑을 복구하는 유일한 방법입니다. 기록해두고 Cake Wallet 앱 외부의 안전한 장소에 보관하는 것은 귀하의 책임입니다.", "pre_seed_title": "중대한", + "prepaid_cards": "선불 카드", "prevent_screenshots": "스크린샷 및 화면 녹화 방지", "privacy": "프라이버시", "privacy_policy": "개인 정보 보호 정책", @@ -468,6 +475,7 @@ "purple_dark_theme": "보라색 어두운 테마", "qr_fullscreen": "전체 화면 QR 코드를 열려면 탭하세요.", "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?", + "quantity": "수량", "question_to_disable_2fa": "Cake 2FA를 비활성화하시겠습니까? 지갑 및 특정 기능에 액세스하는 데 더 이상 2FA 코드가 필요하지 않습니다.", "receivable_balance": "채권 잔액", "receive": "받다", @@ -709,6 +717,7 @@ "tokenID": "ID", "tor_connection": "토르 연결", "tor_only": "Tor 뿐", + "total": "총", "total_saving": "총 절감액", "totp_2fa_failure": "잘못된 코드입니다. 다른 코드를 시도하거나 새 비밀 키를 생성하십시오. 8자리 코드와 SHA512를 지원하는 호환되는 2FA 앱을 사용하세요.", "totp_2fa_success": "성공! 이 지갑에 케이크 2FA가 활성화되었습니다. 지갑 액세스 권한을 잃을 경우를 대비하여 니모닉 시드를 저장하는 것을 잊지 마십시오.", @@ -799,6 +808,8 @@ "use_ssl": "SSL 사용", "use_suggested": "추천 사용", "use_testnet": "TestNet을 사용하십시오", + "value": "값", + "value_type": "가치 유형", "variable_pair_not_supported": "이 변수 쌍은 선택한 교환에서 지원되지 않습니다.", "verification": "검증", "verify_with_2fa": "케이크 2FA로 확인", diff --git a/res/values/strings_my.arb b/res/values/strings_my.arb index 7530b6678..41b082457 100644 --- a/res/values/strings_my.arb +++ b/res/values/strings_my.arb @@ -87,6 +87,7 @@ "buy": "ဝယ်ပါ။", "buy_alert_content": "လက်ရှိတွင် ကျွန်ုပ်တို့သည် Bitcoin၊ Ethereum၊ Litecoin နှင့် Monero တို့ကိုသာ ဝယ်ယူမှုကို ပံ့ပိုးပေးပါသည်။ သင်၏ Bitcoin၊ Ethereum၊ Litecoin သို့မဟုတ် Monero ပိုက်ဆံအိတ်ကို ဖန်တီးပါ သို့မဟုတ် ပြောင်းပါ။", "buy_bitcoin": "Bitcoin ကိုဝယ်ပါ။", + "buy_now": "အခုဝယ်ပါ", "buy_provider_unavailable": "လက်ရှိတွင်လက်ရှိမရနိုင်ပါ။", "buy_with": "အတူဝယ်ပါ။", "by_cake_pay": "Cake Pay ဖြင့်", @@ -94,8 +95,7 @@ "cake_dark_theme": "ကိတ်မုန့် Dark Theme", "cake_pay_account_note": "ကတ်များကြည့်ရှုဝယ်ယူရန် အီးမေးလ်လိပ်စာတစ်ခုဖြင့် စာရင်းသွင်းပါ။ အချို့ကို လျှော့ဈေးဖြင့်ပင် ရနိုင်သည်။", "cake_pay_learn_more": "အက်ပ်ရှိ လက်ဆောင်ကတ်များကို ချက်ချင်းဝယ်ယူပြီး ကူပွန်ဖြင့် လဲလှယ်ပါ။\nပိုမိုလေ့လာရန် ဘယ်မှညာသို့ ပွတ်ဆွဲပါ။", - "cake_pay_subtitle": "လျှော့စျေးလက်ဆောင်ကတ်များဝယ်ပါ (USA သာ)", - "cake_pay_title": "ကိတ်မုန့်လက်ဆောင်ကတ်များ", + "cake_pay_subtitle": "Worldwide ကြိုတင်ငွေဖြည့်ကဒ်များနှင့်လက်ဆောင်ကဒ်များကို 0 ယ်ပါ", "cake_pay_web_cards_subtitle": "ကမ္ဘာတစ်ဝှမ်း ကြိုတင်ငွေပေးကတ်များနှင့် လက်ဆောင်ကတ်များကို ဝယ်ယူပါ။", "cake_pay_web_cards_title": "Cake Pay ဝဘ်ကတ်များ", "cake_wallet": "Cake ပိုက်ဆံအိတ်", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "လက်ရှိပိုက်ဆံအိတ်ကို ပြောင်းပါ။", "choose_account": "အကောင့်ကို ရွေးပါ။", "choose_address": "\n\nလိပ်စာကို ရွေးပါ-", + "choose_card_value": "ကဒ်တန်ဖိုးတစ်ခုရွေးပါ", "choose_derivation": "ပိုက်ဆံအိတ်ကိုရွေးချယ်ပါ", "choose_from_available_options": "ရနိုင်သောရွေးချယ်မှုများမှ ရွေးပါ-", "choose_one": "တစ်ခုရွေးပါ။", @@ -166,6 +167,7 @@ "copy_address": "လိပ်စာကို ကူးယူပါ။", "copy_id": "ID ကူးယူပါ။", "copyWalletConnectLink": "dApp မှ WalletConnect လင့်ခ်ကို ကူးယူပြီး ဤနေရာတွင် ကူးထည့်ပါ။", + "countries": "နိုင်ငံများ", "create_account": "အကောင့်ပြုလုပ်ပါ", "create_backup": "အရန်သိမ်းခြင်းကို ဖန်တီးပါ။", "create_donation_link": "လှူဒါန်းမှုလင့်ခ်ကို ဖန်တီးပါ။", @@ -178,6 +180,7 @@ "custom": "စိတ်ကြိုက်", "custom_drag": "စိတ်ကြိုက် (Drag)", "custom_redeem_amount": "စိတ်ကြိုက်သုံးငွေပမာဏ", + "custom_value": "စိတ်ကြိုက်တန်ဖိုး", "dark_theme": "မှောငျမိုကျသော", "debit_card": "ဒက်ဘစ်ကတ်", "debit_card_terms": "ဤဒစ်ဂျစ်တယ်ပိုက်ဆံအိတ်ရှိ သင့်ငွေပေးချေမှုကတ်နံပါတ် (နှင့် သင့်ငွေပေးချေကတ်နံပါတ်နှင့် သက်ဆိုင်သောအထောက်အထားများ) ၏ သိုလှောင်မှုနှင့် အသုံးပြုမှုသည် အချိန်အခါနှင့်အမျှ သက်ရောက်မှုရှိသကဲ့သို့ ကတ်ကိုင်ဆောင်ထားသူ၏ သဘောတူညီချက်၏ စည်းကမ်းသတ်မှတ်ချက်များနှင့် ကိုက်ညီပါသည်။", @@ -190,6 +193,7 @@ "delete_wallet": "ပိုက်ဆံအိတ်ကို ဖျက်ပါ။", "delete_wallet_confirm_message": "${wallet_name} ပိုက်ဆံအိတ်ကို ဖျက်လိုသည်မှာ သေချာပါသလား။", "deleteConnectionConfirmationPrompt": "ချိတ်ဆက်မှုကို ဖျက်လိုသည်မှာ သေချာပါသလား။", + "denominations": "ဂိုဏ်းချုပ်ပစ္စည်းများ", "descending": "ဆင်း", "description": "ဖော်ပြချက်", "destination_tag": "ခရီးဆုံးအမှတ်-", @@ -277,6 +281,7 @@ "expired": "သက်တမ်းကုန်သွားပြီ", "expires": "သက်တမ်းကုန်သည်။", "expiresOn": "သက်တမ်းကုန်သည်။", + "expiry_and_validity": "သက်တမ်းကုန်ဆုံးခြင်းနှင့်တရားဝင်မှု", "export_backup": "အရန်ကူးထုတ်ရန်", "extra_id": "အပို ID-", "extracted_address_content": "သင်သည် \n${recipient_name} သို့ ရန်ပုံငွေများ ပေးပို့ပါမည်", @@ -384,6 +389,7 @@ "new_template": "ပုံစံအသစ်", "new_wallet": "ပိုက်ဆံအိတ်အသစ်", "newConnection": "ချိတ်ဆက်မှုအသစ်", + "no_cards_found": "ကဒ်များမရှိပါ", "no_id_needed": "ID မလိုအပ်ပါ။", "no_id_required": "ID မလိုအပ်ပါ။ ငွေဖြည့်ပြီး ဘယ်နေရာမဆို သုံးစွဲပါ။", "no_relay_on_domain": "အသုံးပြုသူ၏ဒိုမိန်းအတွက် ထပ်ဆင့်လွှင့်ခြင်း မရှိပါ သို့မဟုတ် ထပ်ဆင့်လွှင့်ခြင်း မရနိုင်ပါ။ အသုံးပြုရန် relay ကိုရွေးချယ်ပါ။", @@ -452,6 +458,7 @@ "pre_seed_button_text": "ကျွန်တော်နားလည်ပါတယ်။ ငါ့အမျိုးအနွယ်ကို ပြလော့", "pre_seed_description": "နောက်စာမျက်နှာတွင် ${words} စကားလုံးများ အတွဲလိုက်ကို တွေ့ရပါမည်။ ၎င်းသည် သင်၏ထူးခြားပြီး သီးသန့်မျိုးစေ့ဖြစ်ပြီး ပျောက်ဆုံးခြင်း သို့မဟုတ် ချွတ်ယွင်းမှုရှိပါက သင့်ပိုက်ဆံအိတ်ကို ပြန်လည်ရယူရန် တစ်ခုတည်းသောနည်းလမ်းဖြစ်သည်။ ၎င်းကို Cake Wallet အက်ပ်၏အပြင်ဘက်တွင် လုံခြုံသောနေရာတွင် သိမ်းဆည်းရန်မှာ သင်၏တာဝန်ဖြစ်သည်။", "pre_seed_title": "အရေးကြီးသည်။", + "prepaid_cards": "ကြိုတင်ငွေဖြည့်ကဒ်များ", "prevent_screenshots": "ဖန်သားပြင်ဓာတ်ပုံများနှင့် မျက်နှာပြင်ရိုက်ကူးခြင်းကို တားဆီးပါ။", "privacy": "ကိုယ်ရေးကိုယ်တာ", "privacy_policy": "ကိုယ်ရေးအချက်အလက်မူဝါဒ", @@ -467,6 +474,7 @@ "purple_dark_theme": "ခရမ်းရောင် Drwing Theme", "qr_fullscreen": "မျက်နှာပြင်အပြည့် QR ကုဒ်ကိုဖွင့်ရန် တို့ပါ။", "qr_payment_amount": "ဤ QR ကုဒ်တွင် ငွေပေးချေမှုပမာဏတစ်ခုပါရှိသည်။ လက်ရှိတန်ဖိုးကို ထပ်ရေးလိုပါသလား။", + "quantity": "အရေအတွက်", "question_to_disable_2fa": "Cake 2FA ကို ပိတ်လိုသည်မှာ သေချာပါသလား။ ပိုက်ဆံအိတ်နှင့် အချို့သောလုပ်ဆောင်ချက်များကို အသုံးပြုရန်အတွက် 2FA ကုဒ်တစ်ခု မလိုအပ်တော့ပါ။", "receivable_balance": "လက်ကျန်ငွေ", "receive": "လက်ခံသည်။", @@ -708,6 +716,7 @@ "tokenID": "အမှတ်သညာ", "tor_connection": "Tor ချိတ်ဆက်မှု", "tor_only": "Tor သာ", + "total": "လုံးဝသော", "total_saving": "စုစုပေါင်းစုဆောင်းငွေ", "totp_2fa_failure": "ကုဒ်မမှန်ပါ။ ကျေးဇူးပြု၍ အခြားကုဒ်တစ်ခုကို စမ်းကြည့်ပါ သို့မဟုတ် လျှို့ဝှက်သော့အသစ်တစ်ခု ဖန်တီးပါ။ ဂဏန်း ၈ လုံးကုဒ်များနှင့် SHA512 ကို ပံ့ပိုးပေးသည့် တွဲဖက်အသုံးပြုနိုင်သော 2FA အက်ပ်ကို အသုံးပြုပါ။", "totp_2fa_success": "အောင်မြင် ဤပိုက်ဆံအိတ်အတွက် ကိတ်မုန့် 2FA ကို ဖွင့်ထားသည်။ ပိုက်ဆံအိတ်ဝင်ရောက်ခွင့်ဆုံးရှုံးသွားသောအခါတွင် သင်၏ mnemonic မျိုးစေ့များကို သိမ်းဆည်းရန် မမေ့ပါနှင့်။", @@ -798,6 +807,8 @@ "use_ssl": "SSL ကိုသုံးပါ။", "use_suggested": "အကြံပြုထားသည်ကို အသုံးပြုပါ။", "use_testnet": "testnet ကိုသုံးပါ", + "value": "အဘိုး", + "value_type": "Value အမျိုးအစား", "variable_pair_not_supported": "ရွေးချယ်ထားသော ဖလှယ်မှုများဖြင့် ဤပြောင်းလဲနိုင်သောအတွဲကို ပံ့ပိုးမထားပါ။", "verification": "စိစစ်ခြင်း။", "verify_with_2fa": "Cake 2FA ဖြင့် စစ်ဆေးပါ။", diff --git a/res/values/strings_nl.arb b/res/values/strings_nl.arb index 7764cb659..a7a3a20a5 100644 --- a/res/values/strings_nl.arb +++ b/res/values/strings_nl.arb @@ -87,6 +87,7 @@ "buy": "Kopen", "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.", "buy_bitcoin": "Koop Bitcoin", + "buy_now": "Koop nu", "buy_provider_unavailable": "Provider momenteel niet beschikbaar.", "buy_with": "Koop met", "by_cake_pay": "door Cake Pay", @@ -94,8 +95,7 @@ "cake_dark_theme": "Cake Dark Theme", "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!", "cake_pay_learn_more": "Koop en wissel cadeaubonnen direct in de app in!\nSwipe van links naar rechts voor meer informatie.", - "cake_pay_subtitle": "Koop cadeaubonnen met korting (alleen VS)", - "cake_pay_title": "Cake Pay-cadeaubonnen", + "cake_pay_subtitle": "Koop wereldwijde prepaid -kaarten en cadeaubonnen", "cake_pay_web_cards_subtitle": "Koop wereldwijd prepaidkaarten en cadeaubonnen", "cake_pay_web_cards_title": "Cake Pay-webkaarten", "cake_wallet": "Cake Wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "Wijzig huidige portemonnee", "choose_account": "Kies account", "choose_address": "\n\nKies het adres:", + "choose_card_value": "Kies een kaartwaarde", "choose_derivation": "Kies portemonnee -afleiding", "choose_from_available_options": "Kies uit de beschikbare opties:", "choose_one": "Kies er een", @@ -166,6 +167,7 @@ "copy_address": "Adres kopiëren", "copy_id": "ID kopiëren", "copyWalletConnectLink": "Kopieer de WalletConnect-link van dApp en plak deze hier", + "countries": "Landen", "create_account": "Account aanmaken", "create_backup": "Maak een back-up", "create_donation_link": "Maak een donatielink aan", @@ -178,6 +180,7 @@ "custom": "aangepast", "custom_drag": "Custom (vasthouden en slepen)", "custom_redeem_amount": "Aangepast inwisselbedrag", + "custom_value": "Aangepaste waarde", "dark_theme": "Donker", "debit_card": "Debetkaart", "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 @@ "delete_wallet": "Portemonnee verwijderen", "delete_wallet_confirm_message": "Weet u zeker dat u de portemonnee van ${wallet_name} wilt verwijderen?", "deleteConnectionConfirmationPrompt": "Weet u zeker dat u de verbinding met", + "denominations": "Denominaties", "descending": "Aflopend", "description": "Beschrijving", "destination_tag": "Bestemmingstag:", @@ -277,6 +281,7 @@ "expired": "Verlopen", "expires": "Verloopt", "expiresOn": "Verloopt op", + "expiry_and_validity": "Vervallen en geldigheid", "export_backup": "Back-up exporteren", "extra_id": "Extra ID:", "extracted_address_content": "U stuurt geld naar\n${recipient_name}", @@ -384,6 +389,7 @@ "new_template": "Nieuwe sjabloon", "new_wallet": "Nieuwe portemonnee", "newConnection": "Nieuwe verbinding", + "no_cards_found": "Geen kaarten gevonden", "no_id_needed": "Geen ID nodig!", "no_id_required": "Geen ID vereist. Opwaarderen en overal uitgeven", "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 @@ "pre_seed_button_text": "Ik begrijp het. Laat me mijn zaad zien", "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.", "pre_seed_title": "BELANGRIJK", + "prepaid_cards": "Prepaid-kaarten", "prevent_screenshots": "Voorkom screenshots en schermopname", "privacy": "Privacy", "privacy_policy": "Privacybeleid", @@ -467,6 +474,7 @@ "purple_dark_theme": "Paars donker thema", "qr_fullscreen": "Tik om de QR-code op volledig scherm te openen", "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?", + "quantity": "Hoeveelheid", "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.", "receivable_balance": "Het saldo", "receive": "Krijgen", @@ -708,6 +716,7 @@ "tokenID": "ID kaart", "tor_connection": "Tor-verbinding", "tor_only": "Alleen Tor", + "total": "Totaal", "total_saving": "Totale besparingen", "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.", "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 @@ "use_ssl": "Gebruik SSL", "use_suggested": "Gebruik aanbevolen", "use_testnet": "Gebruik testnet", + "value": "Waarde", + "value_type": "Waarde type", "variable_pair_not_supported": "Dit variabelenpaar wordt niet ondersteund met de geselecteerde uitwisselingen", "verification": "Verificatie", "verify_with_2fa": "Controleer met Cake 2FA", diff --git a/res/values/strings_pl.arb b/res/values/strings_pl.arb index ef502d31b..e3cea5cad 100644 --- a/res/values/strings_pl.arb +++ b/res/values/strings_pl.arb @@ -87,6 +87,7 @@ "buy": "Kup", "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.", "buy_bitcoin": "Kup Bitcoin", + "buy_now": "Kup Teraz", "buy_provider_unavailable": "Dostawca obecnie niedostępny.", "buy_with": "Kup za pomocą", "by_cake_pay": "przez Cake Pay", @@ -94,8 +95,7 @@ "cake_dark_theme": "Cake Dark Temat", "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ą!", "cake_pay_learn_more": "Kupuj i wykorzystuj karty podarunkowe od razu w aplikacji!\nPrzesuń od lewej do prawej, aby dowiedzieć się więcej.", - "cake_pay_subtitle": "Kup karty upominkowe ze zniżką (tylko USA)", - "cake_pay_title": "Karty podarunkowe Cake Pay", + "cake_pay_subtitle": "Kup na całym świecie karty przedpłacone i karty podarunkowe", "cake_pay_web_cards_subtitle": "Kupuj na całym świecie karty przedpłacone i karty podarunkowe", "cake_pay_web_cards_title": "Cake Pay Web Cards", "cake_wallet": "Cake Wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "Zmień obecny portfel", "choose_account": "Wybierz konto", "choose_address": "\n\nWybierz adres:", + "choose_card_value": "Wybierz wartość karty", "choose_derivation": "Wybierz wyprowadzenie portfela", "choose_from_available_options": "Wybierz z dostępnych opcji:", "choose_one": "Wybierz jeden", @@ -166,6 +167,7 @@ "copy_address": "Skopiuj adress", "copy_id": "skopiuj ID", "copyWalletConnectLink": "Skopiuj link do WalletConnect z dApp i wklej tutaj", + "countries": "Kraje", "create_account": "Utwórz konto", "create_backup": "Utwórz kopię zapasową", "create_donation_link": "Utwórz link do darowizny", @@ -178,6 +180,7 @@ "custom": "niestandardowy", "custom_drag": "Niestandardowe (trzymaj i przeciągnij)", "custom_redeem_amount": "Niestandardowa kwota wykorzystania", + "custom_value": "Wartość niestandardowa", "dark_theme": "Ciemny", "debit_card": "Karta debetowa", "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 @@ "delete_wallet": "Usuń portfel", "delete_wallet_confirm_message": "Czy na pewno chcesz usunąć portfel ${wallet_name}?", "deleteConnectionConfirmationPrompt": "Czy na pewno chcesz usunąć połączenie z", + "denominations": "Wyznaczenia", "descending": "Schodzenie", "description": "Opis", "destination_tag": "Tag docelowy:", @@ -277,6 +281,7 @@ "expired": "Przedawniony", "expires": "Wygasa", "expiresOn": "Upływa w dniu", + "expiry_and_validity": "Wygaśnięcie i ważność", "export_backup": "Eksportuj kopię zapasową", "extra_id": "Dodatkowy ID:", "extracted_address_content": "Wysyłasz środki na\n${recipient_name}", @@ -384,6 +389,7 @@ "new_template": "Nowy szablon", "new_wallet": "Nowy portfel", "newConnection": "Nowe połączenie", + "no_cards_found": "Nie znaleziono żadnych kart", "no_id_needed": "Nie potrzeba Dowodu!", "no_id_required": "Nie wymagamy Dowodu. Doładuj i wydawaj gdziekolwiek", "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 @@ "pre_seed_button_text": "Rozumiem. Pokaż mi moją fraze seed", "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).", "pre_seed_title": "WAŻNY", + "prepaid_cards": "Karty przedpłacone", "prevent_screenshots": "Zapobiegaj zrzutom ekranu i nagrywaniu ekranu", "privacy": "Prywatność", "privacy_policy": "Polityka prywatności", @@ -467,6 +474,7 @@ "purple_dark_theme": "Purple Dark Temat", "qr_fullscreen": "Dotknij, aby otworzyć pełnoekranowy kod QR", "qr_payment_amount": "Ten kod QR zawiera kwotę do zapłaty. Czy chcesz nadpisać obecną wartość?", + "quantity": "Ilość", "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.", "receivable_balance": "Saldo należności", "receive": "Otrzymaj", @@ -708,6 +716,7 @@ "tokenID": "ID", "tor_connection": "Połączenie Torem", "tor_only": "Tylko sieć Tor", + "total": "Całkowity", "total_saving": "Całkowite oszczędności", "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.", "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 @@ "use_ssl": "Użyj SSL", "use_suggested": "Użyj sugerowane", "use_testnet": "Użyj testne", + "value": "Wartość", + "value_type": "Typ wartości", "variable_pair_not_supported": "Ta para zmiennych nie jest obsługiwana na wybranych giełdach", "verification": "Weryfikacja", "verify_with_2fa": "Sprawdź za pomocą Cake 2FA", diff --git a/res/values/strings_pt.arb b/res/values/strings_pt.arb index 02fcf11a5..45241e5a0 100644 --- a/res/values/strings_pt.arb +++ b/res/values/strings_pt.arb @@ -87,6 +87,7 @@ "buy": "Comprar", "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.", "buy_bitcoin": "Compre Bitcoin", + "buy_now": "Comprar agora", "buy_provider_unavailable": "Provedor atualmente indisponível.", "buy_with": "Compre com", "by_cake_pay": "por Cake Pay", @@ -94,8 +95,7 @@ "cake_dark_theme": "Bolo tema escuro", "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!", "cake_pay_learn_more": "Compre e resgate vales-presente instantaneamente no app!\nDeslize da esquerda para a direita para saber mais.", - "cake_pay_subtitle": "Compre vales-presente com desconto (somente nos EUA)", - "cake_pay_title": "Cartões de presente de CakePay", + "cake_pay_subtitle": "Compre cartões pré -pagos em todo o mundo e cartões -presente", "cake_pay_web_cards_subtitle": "Compre cartões pré-pagos e cartões-presente em todo o mundo", "cake_pay_web_cards_title": "Cartões Cake Pay Web", "cake_wallet": "Cake Wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "Alterar carteira atual", "choose_account": "Escolha uma conta", "choose_address": "\n\nEscolha o endereço:", + "choose_card_value": "Escolha um valor de cartão", "choose_derivation": "Escolha a derivação da carteira", "choose_from_available_options": "Escolha entre as opções disponíveis:", "choose_one": "Escolha um", @@ -166,6 +167,7 @@ "copy_address": "Copiar endereço", "copy_id": "Copiar ID", "copyWalletConnectLink": "Copie o link WalletConnect do dApp e cole aqui", + "countries": "Países", "create_account": "Criar conta", "create_backup": "Criar backup", "create_donation_link": "Criar link de doação", @@ -178,6 +180,7 @@ "custom": "personalizado", "custom_drag": "Personalizado (segure e arraste)", "custom_redeem_amount": "Valor de resgate personalizado", + "custom_value": "Valor customizado", "dark_theme": "Sombria", "debit_card": "Cartão de débito", "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 @@ "delete_wallet": "Excluir carteira", "delete_wallet_confirm_message": "Tem certeza de que deseja excluir a carteira ${wallet_name}?", "deleteConnectionConfirmationPrompt": "Tem certeza de que deseja excluir a conexão com", + "denominations": "Denominações", "descending": "descendente", "description": "Descrição", "destination_tag": "Tag de destino:", @@ -277,6 +281,7 @@ "expired": "Expirada", "expires": "Expira", "expiresOn": "Expira em", + "expiry_and_validity": "Expiração e validade", "export_backup": "Backup de exportação", "extra_id": "ID extra:", "extracted_address_content": "Você enviará fundos para\n${recipient_name}", @@ -385,6 +390,7 @@ "new_template": "Novo modelo", "new_wallet": "Nova carteira", "newConnection": "Nova conexão", + "no_cards_found": "Nenhum cartão encontrado", "no_id_needed": "Nenhum ID necessário!", "no_id_required": "Não é necessário ID. Recarregue e gaste em qualquer lugar", "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 @@ "pre_seed_button_text": "Compreendo. Me mostre minha semente", "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.", "pre_seed_title": "IMPORTANTE", + "prepaid_cards": "Cartões pré-pagos", "prevent_screenshots": "Evite capturas de tela e gravação de tela", "privacy": "Privacidade", "privacy_policy": "Política de privacidade", @@ -469,6 +476,7 @@ "purple_dark_theme": "Tema escuro roxo", "qr_fullscreen": "Toque para abrir o código QR em tela cheia", "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?", + "quantity": "Quantidade", "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.", "receivable_balance": "Saldo a receber", "receive": "Receber", @@ -710,6 +718,7 @@ "tokenID": "EU IA", "tor_connection": "Conexão Tor", "tor_only": "Tor apenas", + "total": "Total", "total_saving": "Economia total", "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.", "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 @@ "use_ssl": "Use SSL", "use_suggested": "Uso sugerido", "use_testnet": "Use testNet", + "value": "Valor", + "value_type": "Tipo de valor", "variable_pair_not_supported": "Este par de variáveis não é compatível com as trocas selecionadas", "verification": "Verificação", "verify_with_2fa": "Verificar com Cake 2FA", @@ -864,4 +875,4 @@ "you_will_get": "Converter para", "you_will_send": "Converter de", "yy": "aa" -} +} \ No newline at end of file diff --git a/res/values/strings_ru.arb b/res/values/strings_ru.arb index bb0abbc08..281673326 100644 --- a/res/values/strings_ru.arb +++ b/res/values/strings_ru.arb @@ -87,6 +87,7 @@ "buy": "Купить", "buy_alert_content": "В настоящее время мы поддерживаем только покупку биткойнов, Ethereum, Litecoin и Monero. Пожалуйста, создайте или переключитесь на свой кошелек Bitcoin, Ethereum, Litecoin или Monero.", "buy_bitcoin": "Купить Bitcoin", + "buy_now": "Купить сейчас", "buy_provider_unavailable": "Поставщик в настоящее время недоступен.", "buy_with": "Купить с помощью", "by_cake_pay": "от Cake Pay", @@ -94,8 +95,7 @@ "cake_dark_theme": "Тейт темная тема", "cake_pay_account_note": "Зарегистрируйтесь, указав только адрес электронной почты, чтобы просматривать и покупать карты. Некоторые даже доступны со скидкой!", "cake_pay_learn_more": "Мгновенно покупайте и используйте подарочные карты в приложении!\nПроведите по экрану слева направо, чтобы узнать больше.", - "cake_pay_subtitle": "Покупайте подарочные карты со скидкой (только для США)", - "cake_pay_title": "Подарочные карты Cake Pay", + "cake_pay_subtitle": "Купить карты с предоплатой и подарочными картами по всему миру", "cake_pay_web_cards_subtitle": "Покупайте карты предоплаты и подарочные карты по всему миру", "cake_pay_web_cards_title": "Веб-карты Cake Pay", "cake_wallet": "Cake Wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "Изменить текущий кошелек", "choose_account": "Выберите аккаунт", "choose_address": "\n\nПожалуйста, выберите адрес:", + "choose_card_value": "Выберите значение карты", "choose_derivation": "Выберите вывод кошелька", "choose_from_available_options": "Выберите из доступных вариантов:", "choose_one": "Выбери один", @@ -166,6 +167,7 @@ "copy_address": "Cкопировать адрес", "copy_id": "Скопировать ID", "copyWalletConnectLink": "Скопируйте ссылку WalletConnect из dApp и вставьте сюда.", + "countries": "Страны", "create_account": "Создать аккаунт", "create_backup": "Создать резервную копию", "create_donation_link": "Создать ссылку для пожертвований", @@ -178,6 +180,7 @@ "custom": "обычай", "custom_drag": "Пользователь (удерживайте и перетаскивайте)", "custom_redeem_amount": "Пользовательская сумма погашения", + "custom_value": "Пользовательское значение", "dark_theme": "Темная", "debit_card": "Дебетовая карта", "debit_card_terms": "Хранение и использование номера вашей платежной карты (и учетных данных, соответствующих номеру вашей платежной карты) в этом цифровом кошельке регулируются положениями и условиями применимого соглашения держателя карты с эмитентом платежной карты, действующим с время от времени.", @@ -190,6 +193,7 @@ "delete_wallet": "Удалить кошелек", "delete_wallet_confirm_message": "Вы уверены, что хотите удалить кошелек ${wallet_name}?", "deleteConnectionConfirmationPrompt": "Вы уверены, что хотите удалить подключение к", + "denominations": "Деноминации", "descending": "Нисходящий", "description": "Описание", "destination_tag": "Целевой тег:", @@ -277,6 +281,7 @@ "expired": "Истекает", "expires": "Истекает", "expiresOn": "Годен до", + "expiry_and_validity": "Истечение и достоверность", "export_backup": "Экспорт резервной копии", "extra_id": "Дополнительный ID:", "extracted_address_content": "Вы будете отправлять средства\n${recipient_name}", @@ -384,6 +389,7 @@ "new_template": "Новый шаблон", "new_wallet": "Новый кошелёк", "newConnection": "Новое соединение", + "no_cards_found": "Карт не найдено", "no_id_needed": "Идентификатор не нужен!", "no_id_required": "Идентификатор не требуется. Пополняйте и тратьте где угодно", "no_relay_on_domain": "Для домена пользователя реле не существует или реле недоступно. Пожалуйста, выберите реле для использования.", @@ -453,6 +459,7 @@ "pre_seed_button_text": "Понятно. Покажите мнемоническую фразу", "pre_seed_description": "На следующей странице вы увидите серию из ${words} слов. Это ваша уникальная и личная мнемоническая фраза, и это ЕДИНСТВЕННЫЙ способ восстановить свой кошелек в случае потери или неисправности. ВАМ необходимо записать ее и хранить в надежном месте вне приложения Cake Wallet.", "pre_seed_title": "ВАЖНО", + "prepaid_cards": "Предоплаченные карты", "prevent_screenshots": "Предотвратить скриншоты и запись экрана", "privacy": "Конфиденциальность", "privacy_policy": "Политика конфиденциальности", @@ -468,6 +475,7 @@ "purple_dark_theme": "Пурпурная темная тема", "qr_fullscreen": "Нажмите, чтобы открыть полноэкранный QR-код", "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?", + "quantity": "Количество", "question_to_disable_2fa": "Вы уверены, что хотите отключить Cake 2FA? Код 2FA больше не потребуется для доступа к кошельку и некоторым функциям.", "receivable_balance": "Баланс дебиторской задолженности", "receive": "Получить", @@ -709,6 +717,7 @@ "tokenID": "ИДЕНТИФИКАТОР", "tor_connection": "Тор соединение", "tor_only": "Только Tor", + "total": "Общий", "total_saving": "Общая экономия", "totp_2fa_failure": "Неверный код. Пожалуйста, попробуйте другой код или создайте новый секретный ключ. Используйте совместимое приложение 2FA, которое поддерживает 8-значные коды и SHA512.", "totp_2fa_success": "Успех! Для этого кошелька включена двухфакторная аутентификация Cake. Не забудьте сохранить мнемоническое семя на случай, если вы потеряете доступ к кошельку.", @@ -799,6 +808,8 @@ "use_ssl": "Использовать SSL", "use_suggested": "Использовать предложенный", "use_testnet": "Используйте Testnet", + "value": "Ценить", + "value_type": "Тип значения", "variable_pair_not_supported": "Эта пара переменных не поддерживается выбранными биржами.", "verification": "Проверка", "verify_with_2fa": "Подтвердить с помощью Cake 2FA", diff --git a/res/values/strings_th.arb b/res/values/strings_th.arb index 990c92cb1..98dfed3ea 100644 --- a/res/values/strings_th.arb +++ b/res/values/strings_th.arb @@ -87,6 +87,7 @@ "buy": "ซื้อ", "buy_alert_content": "ขณะนี้เรารองรับการซื้อ Bitcoin, Ethereum, Litecoin และ Monero เท่านั้น โปรดสร้างหรือเปลี่ยนเป็นกระเป๋าเงิน Bitcoin, Ethereum, Litecoin หรือ Monero", "buy_bitcoin": "ซื้อ Bitcoin", + "buy_now": "ซื้อตอนนี้", "buy_provider_unavailable": "ผู้ให้บริการไม่สามารถใช้งานได้ในปัจจุบัน", "buy_with": "ซื้อด้วย", "by_cake_pay": "โดย Cake Pay", @@ -94,8 +95,7 @@ "cake_dark_theme": "ธีมเค้กมืด", "cake_pay_account_note": "ลงทะเบียนด้วยอีเมลเพียงอย่างเดียวเพื่อดูและซื้อบัตร บางบัตรอาจมีส่วนลด!", "cake_pay_learn_more": "ซื้อและเบิกบัตรของขวัญในแอพพลิเคชันทันที!\nกระแทกขวาไปซ้ายเพื่อเรียนรู้เพิ่มเติม", - "cake_pay_subtitle": "ซื้อบัตรของขวัญราคาถูก (สำหรับสหรัฐอเมริกาเท่านั้น)", - "cake_pay_title": "บัตรของขวัญ Cake Pay", + "cake_pay_subtitle": "ซื้อบัตรเติมเงินและบัตรของขวัญทั่วโลก", "cake_pay_web_cards_subtitle": "ซื้อบัตรพร้อมเงินระดับโลกและบัตรของขวัญ", "cake_pay_web_cards_title": "Cake Pay Web Cards", "cake_wallet": "Cake Wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "เปลี่ยนกระเป๋าปัจจุบัน", "choose_account": "เลือกบัญชี", "choose_address": "\n\nโปรดเลือกที่อยู่:", + "choose_card_value": "เลือกค่าบัตร", "choose_derivation": "เลือก Wallet Derivation", "choose_from_available_options": "เลือกจากตัวเลือกที่มีอยู่:", "choose_one": "เลือกหนึ่งรายการ", @@ -166,6 +167,7 @@ "copy_address": "คัดลอกที่อยู่", "copy_id": "คัดลอก ID", "copyWalletConnectLink": "คัดลอกลิงก์ WalletConnect จาก dApp แล้ววางที่นี่", + "countries": "ประเทศ", "create_account": "สร้างบัญชี", "create_backup": "สร้างการสำรองข้อมูล", "create_donation_link": "สร้างลิงค์บริจาค", @@ -178,6 +180,7 @@ "custom": "กำหนดเอง", "custom_drag": "กำหนดเอง (ค้างและลาก)", "custom_redeem_amount": "จำนวนรับคืนที่กำหนดเอง", + "custom_value": "ค่าที่กำหนดเอง", "dark_theme": "เข้ม", "debit_card": "บัตรเดบิต", "debit_card_terms": "การเก็บรักษาและใช้หมายเลขบัตรจ่ายเงิน (และข้อมูลประจำตัวที่เกี่ยวข้องกับหมายเลขบัตรจ่ายเงิน) ในกระเป๋าดิจิทัลนี้ จะต้องยึดถือข้อกำหนดและเงื่อนไขของข้อตกลงผู้ใช้บัตรของผู้ถือบัตรที่เกี่ยวข้องกับบัตรผู้ถือบัตร ซึ่งจะมีผลตั้งแต่เวลานั้น", @@ -190,6 +193,7 @@ "delete_wallet": "ลบกระเป๋า", "delete_wallet_confirm_message": "คุณแน่ใจหรือว่าต้องการลบกระเป๋า${wallet_name}?", "deleteConnectionConfirmationPrompt": "คุณแน่ใจหรือไม่ว่าต้องการลบการเชื่อมต่อไปยัง", + "denominations": "นิกาย", "descending": "ลงมา", "description": "คำอธิบาย", "destination_tag": "แท็กปลายทาง:", @@ -277,6 +281,7 @@ "expired": "หมดอายุ", "expires": "หมดอายุ", "expiresOn": "หมดอายุวันที่", + "expiry_and_validity": "หมดอายุและถูกต้อง", "export_backup": "ส่งออกข้อมูลสำรอง", "extra_id": "ไอดีเพิ่มเติม:", "extracted_address_content": "คุณกำลังจะส่งเงินไปยัง\n${recipient_name}", @@ -384,6 +389,7 @@ "new_template": "แม่แบบใหม่", "new_wallet": "กระเป๋าใหม่", "newConnection": "การเชื่อมต่อใหม่", + "no_cards_found": "ไม่พบการ์ด", "no_id_needed": "ไม่จำเป็นต้องใช้บัตรประชาชน!", "no_id_required": "ไม่จำเป็นต้องใช้บัตรประจำตัว ฝากเงินและใช้งานได้ทุกที่", "no_relay_on_domain": "ไม่มีการส่งต่อสำหรับโดเมนของผู้ใช้ หรือการส่งต่อไม่พร้อมใช้งาน กรุณาเลือกรีเลย์ที่จะใช้", @@ -452,6 +458,7 @@ "pre_seed_button_text": "ฉันเข้าใจ แสดง seed ของฉัน", "pre_seed_description": "บนหน้าถัดไปคุณจะเห็นชุดของคำ ${words} คำ นี่คือ seed ของคุณที่ไม่ซ้ำใดๆ และเป็นความลับเพียงของคุณ และนี่คือเพียงวิธีเดียวที่จะกู้กระเป๋าของคุณในกรณีที่สูญหายหรือมีปัญหา มันเป็นความรับผิดชอบของคุณเพื่อเขียนมันลงบนกระดาษและจัดเก็บไว้ในที่ปลอดภัยนอกแอป Cake Wallet", "pre_seed_title": "สำคัญ", + "prepaid_cards": "บัตรเติมเงิน", "prevent_screenshots": "ป้องกันภาพหน้าจอและการบันทึกหน้าจอ", "privacy": "ความเป็นส่วนตัว", "privacy_policy": "นโยบายความเป็นส่วนตัว", @@ -467,6 +474,7 @@ "purple_dark_theme": "ธีมสีม่วงเข้ม", "qr_fullscreen": "แตะเพื่อเปิดหน้าจอ QR code แบบเต็มจอ", "qr_payment_amount": "QR code นี้มีจำนวนการชำระเงิน คุณต้องการเขียนทับค่าปัจจุบันหรือไม่?", + "quantity": "ปริมาณ", "question_to_disable_2fa": "คุณแน่ใจหรือไม่ว่าต้องการปิดการใช้งาน Cake 2FA ไม่จำเป็นต้องใช้รหัส 2FA ในการเข้าถึงกระเป๋าเงินและฟังก์ชั่นบางอย่างอีกต่อไป", "receivable_balance": "ยอดลูกหนี้", "receive": "รับ", @@ -708,6 +716,7 @@ "tokenID": "บัตรประจำตัวประชาชน", "tor_connection": "การเชื่อมต่อทอร์", "tor_only": "Tor เท่านั้น", + "total": "ทั้งหมด", "total_saving": "ประหยัดรวม", "totp_2fa_failure": "รหัสไม่ถูกต้อง. โปรดลองใช้รหัสอื่นหรือสร้างรหัสลับใหม่ ใช้แอพ 2FA ที่เข้ากันได้ซึ่งรองรับรหัส 8 หลักและ SHA512", "totp_2fa_success": "ความสำเร็จ! Cake 2FA เปิดใช้งานสำหรับกระเป๋าเงินนี้ อย่าลืมบันทึกเมล็ดช่วยจำของคุณในกรณีที่คุณสูญเสียการเข้าถึงกระเป๋าเงิน", @@ -798,6 +807,8 @@ "use_ssl": "ใช้ SSL", "use_suggested": "ใช้ที่แนะนำ", "use_testnet": "ใช้ testnet", + "value": "ค่า", + "value_type": "ประเภทค่า", "variable_pair_not_supported": "คู่ความสัมพันธ์ที่เปลี่ยนแปลงได้นี้ไม่สนับสนุนกับหุ้นที่เลือก", "verification": "การตรวจสอบ", "verify_with_2fa": "ตรวจสอบกับ Cake 2FA", diff --git a/res/values/strings_tl.arb b/res/values/strings_tl.arb index 8c3347d6a..7506a7e2f 100644 --- a/res/values/strings_tl.arb +++ b/res/values/strings_tl.arb @@ -87,6 +87,7 @@ "buy": "Bilhin", "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.", "buy_bitcoin": "Bumili ng bitcoin", + "buy_now": "Bumili ka na ngayon", "buy_provider_unavailable": "Kasalukuyang hindi available ang provider.", "buy_with": "Bumili ka", "by_cake_pay": "sa pamamagitan ng cake pay", @@ -94,8 +95,7 @@ "cake_dark_theme": "Cake madilim na tema", "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!", "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.", - "cake_pay_subtitle": "Bumili ng mga diskwento na gift card (USA lamang)", - "cake_pay_title": "Cake pay card card", + "cake_pay_subtitle": "Bumili ng mga pandaigdigang prepaid card at gift card", "cake_pay_web_cards_subtitle": "Bumili ng mga pandaigdigang prepaid card at gift card", "cake_pay_web_cards_title": "Cake pay web card", "cake_wallet": "Cake wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "Baguhin ang kasalukuyang pitaka", "choose_account": "Pumili ng account", "choose_address": "Mangyaring piliin ang address:", + "choose_card_value": "Pumili ng isang halaga ng card", "choose_derivation": "Piliin ang derivation ng Wallet", "choose_from_available_options": "Pumili mula sa magagamit na mga pagpipilian:", "choose_one": "Pumili ng isa", @@ -166,6 +167,7 @@ "copy_address": "Kopyahin ang address", "copy_id": "Kopyahin ang id", "copyWalletConnectLink": "Kopyahin ang link ng WalletConnect mula sa dApp at i-paste dito", + "countries": "Mga bansa", "create_account": "Lumikha ng account", "create_backup": "Gumawa ng backup", "create_donation_link": "Lumikha ng link ng donasyon", @@ -178,6 +180,7 @@ "custom": "pasadya", "custom_drag": "Pasadyang (hawakan at i -drag)", "custom_redeem_amount": "Pasadyang tinubos ang halaga", + "custom_value": "Pasadyang halaga", "dark_theme": "Madilim", "debit_card": "Debit card", "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 @@ "delete_wallet": "Tanggalin ang pitaka", "delete_wallet_confirm_message": "Sigurado ka bang nais mong tanggalin ang ${wallet_name} wallet?", "deleteConnectionConfirmationPrompt": "Sigurado ka bang gusto mong tanggalin ang koneksyon sa", + "denominations": "Denominasyon", "descending": "Pababang", "description": "Paglalarawan", "destination_tag": "Tag ng patutunguhan:", @@ -277,6 +281,7 @@ "expired": "Nag -expire", "expires": "Mag -expire", "expiresOn": "Mag-e-expire sa", + "expiry_and_validity": "Pag -expire at bisa", "export_backup": "I -export ang backup", "extra_id": "Dagdag na ID:", "extracted_address_content": "Magpapadala ka ng pondo sa\n${recipient_name}", @@ -384,6 +389,7 @@ "new_template": "Bagong template", "new_wallet": "Bagong pitaka", "newConnection": "Bagong Koneksyon", + "no_cards_found": "Walang nahanap na mga kard", "no_id_needed": "Hindi kailangan ng ID!", "no_id_required": "Walang kinakailangang ID. I -top up at gumastos kahit saan", "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 @@ "pre_seed_button_text": "Naiintindihan ko. Ipakita sa akin ang aking binhi", "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.", "pre_seed_title": "Mahalaga", + "prepaid_cards": "Prepaid card", "prevent_screenshots": "Maiwasan ang mga screenshot at pag -record ng screen", "privacy": "Privacy", "privacy_policy": "Patakaran sa Pagkapribado", @@ -467,6 +474,7 @@ "purple_dark_theme": "Purple Madilim na Tema", "qr_fullscreen": "Tapikin upang buksan ang buong screen QR code", "qr_payment_amount": "Ang QR code na ito ay naglalaman ng isang halaga ng pagbabayad. Nais mo bang i -overwrite ang kasalukuyang halaga?", + "quantity": "Dami", "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.", "receivable_balance": "Natatanggap na balanse", "receive": "Tumanggap", @@ -708,6 +716,7 @@ "tokenID": "ID", "tor_connection": "Koneksyon ng Tor", "tor_only": "Tor lang", + "total": "Kabuuan", "total_saving": "Kabuuang pagtitipid", "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.", "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 @@ "use_ssl": "Gumamit ng SSL", "use_suggested": "Gumamit ng iminungkahing", "use_testnet": "Gumamit ng testnet", + "value": "Halaga", + "value_type": "Uri ng halaga", "variable_pair_not_supported": "Ang variable na pares na ito ay hindi suportado sa mga napiling palitan", "verification": "Pag -verify", "verify_with_2fa": "Mag -verify sa cake 2FA", diff --git a/res/values/strings_tr.arb b/res/values/strings_tr.arb index a346d874f..b03e36a1b 100644 --- a/res/values/strings_tr.arb +++ b/res/values/strings_tr.arb @@ -87,6 +87,7 @@ "buy": "Alış", "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.", "buy_bitcoin": "Bitcoin Satın Al", + "buy_now": "Şimdi al", "buy_provider_unavailable": "Sağlayıcı şu anda kullanılamıyor.", "buy_with": "Şunun ile al: ", "by_cake_pay": "Cake Pay tarafından", @@ -94,8 +95,7 @@ "cake_dark_theme": "Kek Koyu Tema", "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!", "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.", - "cake_pay_subtitle": "İndirimli hediye kartları satın alın (yalnızca ABD)", - "cake_pay_title": "Cake Pay Hediye Kartları", + "cake_pay_subtitle": "Dünya çapında ön ödemeli kartlar ve hediye kartları satın alın", "cake_pay_web_cards_subtitle": "Dünya çapında ön ödemeli kartlar ve hediye kartları satın alın", "cake_pay_web_cards_title": "Cake Pay Web Kartları", "cake_wallet": "Cake Wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "Şimdiki cüzdanı değiştir", "choose_account": "Hesabı seç", "choose_address": "\n\nLütfen adresi seçin:", + "choose_card_value": "Bir kart değeri seçin", "choose_derivation": "Cüzdan türevini seçin", "choose_from_available_options": "Mevcut seçenekler arasından seçim yap:", "choose_one": "Birini seç", @@ -166,6 +167,7 @@ "copy_address": "Adresi kopyala", "copy_id": "ID'yi kopyala", "copyWalletConnectLink": "WalletConnect bağlantısını dApp'ten kopyalayıp buraya yapıştırın", + "countries": "Ülkeler", "create_account": "Hesap oluştur", "create_backup": "Yedek oluştur", "create_donation_link": "Bağış bağlantısı oluştur", @@ -178,6 +180,7 @@ "custom": "özel", "custom_drag": "Özel (Bekle ve Sürükle)", "custom_redeem_amount": "Özel Harcama Tutarı", + "custom_value": "Özel değer", "dark_theme": "Karanlık", "debit_card": "Ön ödemeli Kart", "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 @@ "delete_wallet": "Cüzdanı sil", "delete_wallet_confirm_message": "${wallet_name} isimli cüzdanını silmek istediğinden emin misin?", "deleteConnectionConfirmationPrompt": "Bağlantıyı silmek istediğinizden emin misiniz?", + "denominations": "Mezhepler", "descending": "Azalan", "description": "Tanım", "destination_tag": "Hedef Etiketi:", @@ -277,6 +281,7 @@ "expired": "Süresi doldu", "expires": "Son kullanma tarihi", "expiresOn": "Tarihinde sona eriyor", + "expiry_and_validity": "Sona erme ve geçerlilik", "export_backup": "Yedeği dışa aktar", "extra_id": "Ekstra ID:", "extracted_address_content": "Parayı buraya gönderceksin:\n${recipient_name}", @@ -308,7 +313,7 @@ "gift_card_is_generated": "Hediye Kartı oluşturuldu", "gift_card_number": "Hediye kartı numarası", "gift_card_redeemed_note": "Harcadığın hediye kartları burada görünecek", - "gift_cards": "Hediye kartları", + "gift_cards": "Hediye Kartları", "gift_cards_unavailable": "Hediye kartları şu anda yalnızca Monero, Bitcoin ve Litecoin ile satın alınabilir", "got_it": "Tamamdır", "gross_balance": "Brüt Bakiye", @@ -384,6 +389,7 @@ "new_template": "Yeni Şablon", "new_wallet": "Yeni Cüzdan", "newConnection": "Yeni bağlantı", + "no_cards_found": "Kart bulunamadı", "no_id_needed": "Kimlik gerekmez!", "no_id_required": "Kimlik gerekmez. Para yükleyin ve istediğiniz yerde harcayın", "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 @@ "pre_seed_button_text": "Anladım. Bana tohumumu göster.", "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.", "pre_seed_title": "UYARI", + "prepaid_cards": "Ön ödemeli kartlar", "prevent_screenshots": "Ekran görüntülerini ve ekran kaydını önleyin", "privacy": "Gizlilik", "privacy_policy": "Gizlilik Politikası", @@ -467,6 +474,7 @@ "purple_dark_theme": "Mor karanlık tema", "qr_fullscreen": "QR kodunu tam ekranda açmak için dokun", "qr_payment_amount": "Bu QR kodu ödeme tutarını içeriyor. Geçerli miktarın üzerine yazmak istediğine emin misin?", + "quantity": "Miktar", "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.", "receivable_balance": "Alacak bakiyesi", "receive": "Para Al", @@ -708,6 +716,7 @@ "tokenID": "İD", "tor_connection": "Tor bağlantısı", "tor_only": "Yalnızca Tor", + "total": "Toplam", "total_saving": "Toplam Tasarruf", "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.", "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 @@ "use_ssl": "SSL kullan", "use_suggested": "Önerileni Kullan", "use_testnet": "TestNet kullanın", + "value": "Değer", + "value_type": "Değer türü", "variable_pair_not_supported": "Bu değişken paritesi seçilen borsalarda desteklenmemekte", "verification": "Doğrulama", "verify_with_2fa": "Cake 2FA ile Doğrulayın", diff --git a/res/values/strings_uk.arb b/res/values/strings_uk.arb index 33c4ca67b..5738bd13d 100644 --- a/res/values/strings_uk.arb +++ b/res/values/strings_uk.arb @@ -87,6 +87,7 @@ "buy": "Купити", "buy_alert_content": "Наразі ми підтримуємо купівлю лише Bitcoin, Ethereum, Litecoin і Monero. Створіть або перейдіть на свій гаманець Bitcoin, Ethereum, Litecoin або Monero.", "buy_bitcoin": "Купити Bitcoin", + "buy_now": "Купити зараз", "buy_provider_unavailable": "В даний час постачальник недоступний.", "buy_with": "Купити за допомогою", "by_cake_pay": "від Cake Pay", @@ -94,8 +95,7 @@ "cake_dark_theme": "Темна тема торта", "cake_pay_account_note": "Зареєструйтеся, використовуючи лише адресу електронної пошти, щоб переглядати та купувати картки. Деякі навіть доступні зі знижкою!", "cake_pay_learn_more": "Миттєво купуйте та активуйте подарункові картки в додатку!\nПроведіть пальцем зліва направо, щоб дізнатися більше.", - "cake_pay_subtitle": "Купуйте подарункові картки зі знижкою (тільки для США)", - "cake_pay_title": "Подарункові картки Cake Pay", + "cake_pay_subtitle": "Купіть у всьому світі передплачені картки та подарункові картки", "cake_pay_web_cards_subtitle": "Купуйте передоплачені та подарункові картки по всьому світу", "cake_pay_web_cards_title": "Веб-картки Cake Pay", "cake_wallet": "Cake Wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "Змінити поточний гаманець", "choose_account": "Оберіть акаунт", "choose_address": "\n\nБудь ласка, оберіть адресу:", + "choose_card_value": "Виберіть значення картки", "choose_derivation": "Виберіть деривацію гаманця", "choose_from_available_options": "Виберіть із доступних варіантів:", "choose_one": "Вибери один", @@ -166,6 +167,7 @@ "copy_address": "Cкопіювати адресу", "copy_id": "Скопіювати ID", "copyWalletConnectLink": "Скопіюйте посилання WalletConnect із dApp і вставте сюди", + "countries": "Країни", "create_account": "Створити обліковий запис", "create_backup": "Створити резервну копію", "create_donation_link": "Створити посилання для пожертв", @@ -178,6 +180,7 @@ "custom": "на замовлення", "custom_drag": "На замовлення (утримуйте та перетягується)", "custom_redeem_amount": "Власна сума викупу", + "custom_value": "Спеціальне значення", "dark_theme": "Темна", "debit_card": "Дебетова картка", "debit_card_terms": "Зберігання та використання номера вашої платіжної картки (та облікових даних, які відповідають номеру вашої платіжної картки) у цьому цифровому гаманці регулюються Умовами відповідної угоди власника картки з емітентом платіжної картки, що діє з час від часу.", @@ -190,6 +193,7 @@ "delete_wallet": "Видалити гаманець", "delete_wallet_confirm_message": "Ви впевнені, що хочете видалити гаманець ${wallet_name}?", "deleteConnectionConfirmationPrompt": "Ви впевнені, що хочете видалити з’єднання з", + "denominations": "Конфесія", "descending": "Низхідний", "description": "опис", "destination_tag": "Тег призначення:", @@ -277,6 +281,7 @@ "expired": "Закінчується", "expires": "Закінчується", "expiresOn": "Термін дії закінчується", + "expiry_and_validity": "Закінчення та обгрунтованість", "export_backup": "Експортувати резервну копію", "extra_id": "Додатковий ID:", "extracted_address_content": "Ви будете відправляти кошти\n${recipient_name}", @@ -384,6 +389,7 @@ "new_template": "Новий шаблон", "new_wallet": "Новий гаманець", "newConnection": "Нове підключення", + "no_cards_found": "Карт не знайдено", "no_id_needed": "Ідентифікатор не потрібен!", "no_id_required": "Ідентифікатор не потрібен. Поповнюйте та витрачайте будь-де", "no_relay_on_domain": "Немає ретранслятора для домену користувача або ретранслятор недоступний. Будь ласка, виберіть реле для використання.", @@ -452,6 +458,7 @@ "pre_seed_button_text": "Зрозуміло. Покажіть мнемонічну фразу", "pre_seed_description": "На наступній сторінці ви побачите серію з ${words} слів. Це ваша унікальна та приватна мнемонічна фраза, і це ЄДИНИЙ спосіб відновити ваш гаманець на випадок втрати або несправності. ВАМ необхідно записати її та зберігати в безпечному місці поза програмою Cake Wallet.", "pre_seed_title": "ВАЖЛИВО", + "prepaid_cards": "Передплачені картки", "prevent_screenshots": "Запобігати знімкам екрана та запису екрана", "privacy": "Конфіденційність", "privacy_policy": "Політика конфіденційності", @@ -467,6 +474,7 @@ "purple_dark_theme": "Фіолетова темна тема", "qr_fullscreen": "Торкніться, щоб відкрити QR-код на весь екран", "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?", + "quantity": "Кількість", "question_to_disable_2fa": "Ви впевнені, що хочете вимкнути Cake 2FA? Код 2FA більше не потрібен для доступу до гаманця та певних функцій.", "receivable_balance": "Баланс дебіторської заборгованості", "receive": "Отримати", @@ -709,6 +717,7 @@ "tokenID": "ID", "tor_connection": "Підключення Tor", "tor_only": "Тільки Tor", + "total": "Загальний", "total_saving": "Загальна економія", "totp_2fa_failure": "Невірний код. Спробуйте інший код або створіть новий секретний ключ. Використовуйте сумісний додаток 2FA, який підтримує 8-значні коди та SHA512.", "totp_2fa_success": "Успіх! Cake 2FA увімкнено для цього гаманця. Пам’ятайте про збереження мнемоніки на випадок, якщо ви втратите доступ до гаманця.", @@ -799,6 +808,8 @@ "use_ssl": "Використати SSL", "use_suggested": "Використати запропоноване", "use_testnet": "Використовуйте тестову мережу", + "value": "Цінність", + "value_type": "Тип значення", "variable_pair_not_supported": "Ця пара змінних не підтримується вибраними біржами", "verification": "Перевірка", "verify_with_2fa": "Перевірте за допомогою Cake 2FA", diff --git a/res/values/strings_ur.arb b/res/values/strings_ur.arb index 49c187426..6a971383d 100644 --- a/res/values/strings_ur.arb +++ b/res/values/strings_ur.arb @@ -87,6 +87,7 @@ "buy": "خریدنے", "buy_alert_content": "۔ﮟﯾﺮﮐ ﭻﺋﻮﺳ ﺮﭘ ﺱﺍ ﺎﯾ ﮟﯿﺋﺎﻨﺑ ﭧﯿﻟﺍﻭ Monero ﺎﯾ ،Bitcoin، Ethereum، Litecoin ﺎﻨﭘﺍ ﻡ", "buy_bitcoin": "Bitcoin خریدیں۔", + "buy_now": "ابھی خریدئے", "buy_provider_unavailable": "فراہم کنندہ فی الحال دستیاب نہیں ہے۔", "buy_with": "کے ساتھ خریدیں۔", "by_cake_pay": "Cake پے کے ذریعے", @@ -94,8 +95,7 @@ "cake_dark_theme": "کیک ڈارک تھیم", "cake_pay_account_note": "کارڈز دیکھنے اور خریدنے کے لیے صرف ایک ای میل ایڈریس کے ساتھ سائن اپ کریں۔ کچھ رعایت پر بھی دستیاب ہیں!", "cake_pay_learn_more": "ایپ میں فوری طور پر گفٹ کارڈز خریدیں اور بھنائیں!\\nمزید جاننے کے لیے بائیں سے دائیں سوائپ کریں۔", - "cake_pay_subtitle": "رعایتی گفٹ کارڈز خریدیں (صرف امریکہ)", - "cake_pay_title": "Cake پے گفٹ کارڈز", + "cake_pay_subtitle": "دنیا بھر میں پری پیڈ کارڈز اور گفٹ کارڈ خریدیں", "cake_pay_web_cards_subtitle": "دنیا بھر میں پری پیڈ کارڈز اور گفٹ کارڈز خریدیں۔", "cake_pay_web_cards_title": "Cake پے ویب کارڈز", "cake_wallet": "Cake والیٹ", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "موجودہ پرس تبدیل کریں۔", "choose_account": "اکاؤنٹ کا انتخاب کریں۔", "choose_address": "\\n\\nبراہ کرم پتہ منتخب کریں:", + "choose_card_value": "کارڈ کی قیمت کا انتخاب کریں", "choose_derivation": "پرس سے ماخوذ منتخب کریں", "choose_from_available_options": "دستیاب اختیارات میں سے انتخاب کریں:", "choose_one": "ایک کا انتخاب کریں", @@ -166,6 +167,7 @@ "copy_address": "ایڈریس کاپی کریں۔", "copy_id": "کاپی ID", "copyWalletConnectLink": "dApp ﮯﺳ WalletConnect ۔ﮟﯾﺮﮐ ﭧﺴﯿﭘ ﮞﺎﮩﯾ ﺭﻭﺍ ﮟﯾﺮﮐ ﯽﭘﺎﮐ ﻮﮐ ﮏﻨﻟ", + "countries": "ممالک", "create_account": "اکاؤنٹ بنائیں", "create_backup": "بیک اپ بنائیں", "create_donation_link": "عطیہ کا لنک بنائیں", @@ -178,6 +180,7 @@ "custom": "اپنی مرضی کے مطابق", "custom_drag": "کسٹم (ہولڈ اینڈ ڈریگ)", "custom_redeem_amount": "حسب ضرورت چھڑانے کی رقم", + "custom_value": "کسٹم ویلیو", "dark_theme": "اندھیرا", "debit_card": "ڈیبٹ کارڈ", "debit_card_terms": "اس ڈیجیٹل والیٹ میں آپ کے ادائیگی کارڈ نمبر (اور آپ کے ادائیگی کارڈ نمبر سے متعلقہ اسناد) کا ذخیرہ اور استعمال ادائیگی کارڈ جاری کنندہ کے ساتھ قابل اطلاق کارڈ ہولڈر کے معاہدے کی شرائط و ضوابط کے ساتھ مشروط ہے، جیسا کہ وقتاً فوقتاً نافذ ہوتا ہے۔", @@ -190,6 +193,7 @@ "delete_wallet": "پرس کو حذف کریں۔", "delete_wallet_confirm_message": "کیا آپ واقعی ${wallet_name} والیٹ کو حذف کرنا چاہتے ہیں؟", "deleteConnectionConfirmationPrompt": "۔ﮟﯿﮨ ﮯﺘﮨﺎﭼ ﺎﻧﺮﮐ ﻑﺬﺣ ﻮﮐ ﻦﺸﮑﻨﮐ ﭖﺁ ﮧﮐ ﮯﮨ ﻦﯿﻘﯾ ﻮﮐ ﭖﺁ ﺎﯿﮐ", + "denominations": "فرق", "descending": "اترتے ہوئے", "description": "ﻞﯿﺼﻔﺗ", "destination_tag": "منزل کا ٹیگ:", @@ -277,6 +281,7 @@ "expired": "میعاد ختم", "expires": "میعاد ختم", "expiresOn": "ﺩﺎﻌﯿﻣ ﯽﻣﺎﺘﺘﺧﺍ", + "expiry_and_validity": "میعاد ختم اور صداقت", "export_backup": "بیک اپ برآمد کریں۔", "extra_id": "اضافی ID:", "extracted_address_content": "آپ فنڈز بھیج رہے ہوں گے\n${recipient_name}", @@ -384,6 +389,7 @@ "new_template": "نیا سانچہ", "new_wallet": "نیا پرس", "newConnection": "ﻦﺸﮑﻨﮐ ﺎﯿﻧ", + "no_cards_found": "کوئی کارڈ نہیں ملا", "no_id_needed": "شناخت کی ضرورت نہیں!", "no_id_required": "کوئی ID درکار نہیں۔ ٹاپ اپ اور کہیں بھی خرچ کریں۔", "no_relay_on_domain": "۔ﮟﯾﺮﮐ ﺏﺎﺨﺘﻧﺍ ﺎﮐ ﮯﻠﯾﺭ ﮯﯿﻟ ﮯﮐ ﮯﻧﺮﮐ ﻝﺎﻤﻌﺘﺳﺍ ﻡﺮﮐ ﮦﺍﺮﺑ ۔ﮯﮨ ﮟﯿﮩﻧ ﺏﺎﯿﺘﺳﺩ ﮯﻠﯾﺭ ﺎﯾ ﮯﮨ ﮟ", @@ -454,6 +460,7 @@ "pre_seed_button_text": "میں سمجھتا ہوں۔ مجھے میرا بیج دکھاؤ", "pre_seed_description": "اگلے صفحے پر آپ کو ${words} الفاظ کا ایک سلسلہ نظر آئے گا۔ یہ آپ کا انوکھا اور نجی بیج ہے اور یہ آپ کے بٹوے کو ضائع یا خرابی کی صورت میں بازیافت کرنے کا واحد طریقہ ہے۔ اسے لکھنا اور اسے کیک والیٹ ایپ سے باہر کسی محفوظ جگہ پر اسٹور کرنا آپ کی ذمہ داری ہے۔", "pre_seed_title": "اہم", + "prepaid_cards": "پری پیڈ کارڈز", "prevent_screenshots": "اسکرین شاٹس اور اسکرین ریکارڈنگ کو روکیں۔", "privacy": "رازداری", "privacy_policy": "رازداری کی پالیسی", @@ -469,6 +476,7 @@ "purple_dark_theme": "ارغوانی ڈارک تھیم", "qr_fullscreen": "فل سکرین QR کوڈ کھولنے کے لیے تھپتھپائیں۔", "qr_payment_amount": "اس QR کوڈ میں ادائیگی کی رقم شامل ہے۔ کیا آپ موجودہ قدر کو اوور رائٹ کرنا چاہتے ہیں؟", + "quantity": "مقدار", "question_to_disable_2fa": "کیا آپ واقعی کیک 2FA کو غیر فعال کرنا چاہتے ہیں؟ بٹوے اور بعض افعال تک رسائی کے لیے اب 2FA کوڈ کی ضرورت نہیں ہوگی۔", "receivable_balance": "قابل وصول توازن", "receive": "وصول کریں۔", @@ -710,6 +718,7 @@ "tokenID": "ID", "tor_connection": "ﻦﺸﮑﻨﮐ ﺭﻮﭨ", "tor_only": "صرف Tor", + "total": "کل", "total_saving": "کل بچت", "totp_2fa_failure": "غلط کوڈ. براہ کرم ایک مختلف کوڈ آزمائیں یا ایک نئی خفیہ کلید بنائیں۔ ایک ہم آہنگ 2FA ایپ استعمال کریں جو 8 ہندسوں کے کوڈز اور SHA512 کو سپورٹ کرتی ہو۔", "totp_2fa_success": "کامیابی! کیک 2FA اس بٹوے کے لیے فعال ہے۔ بٹوے تک رسائی سے محروم ہونے کی صورت میں اپنے یادداشت کے بیج کو محفوظ کرنا یاد رکھیں۔", @@ -800,6 +809,8 @@ "use_ssl": "SSL استعمال کریں۔", "use_suggested": "تجویز کردہ استعمال کریں۔", "use_testnet": "ٹیسٹ نیٹ استعمال کریں", + "value": "قدر", + "value_type": "قدر کی قسم", "variable_pair_not_supported": "یہ متغیر جوڑا منتخب ایکسچینجز کے ساتھ تعاون یافتہ نہیں ہے۔", "verification": "تصدیق", "verify_with_2fa": "کیک 2FA سے تصدیق کریں۔", diff --git a/res/values/strings_yo.arb b/res/values/strings_yo.arb index 0a5d66afe..1efc25216 100644 --- a/res/values/strings_yo.arb +++ b/res/values/strings_yo.arb @@ -87,6 +87,7 @@ "buy": "Rà", "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.", "buy_bitcoin": "Ra Bitcoin", + "buy_now": "Ra Bayibayi", "buy_provider_unavailable": "Olupese lọwọlọwọ ko si.", "buy_with": "Rà pẹ̀lú", "by_cake_pay": "láti ọwọ́ Cake Pay", @@ -94,8 +95,7 @@ "cake_dark_theme": "Akara oyinbo dudu koko", "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!", "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ù.", - "cake_pay_subtitle": "Ra àwọn káàdì ìrajà t'á lò nínú ìtajà kan fún owó tí kò pọ̀ (USA nìkan)", - "cake_pay_title": "Àwọn káàdì ìrajà t'á lò nínú ìtajà kan ti Cake Pay", + "cake_pay_subtitle": "Ra awọn kaadi ti a san ni agbaye ati awọn kaadi ẹbun", "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", "cake_pay_web_cards_title": "Àwọn káàdì wẹ́ẹ̀bù ti Cake Pay", "cake_wallet": "Cake Wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "Ẹ pààrọ̀ àpamọ́wọ́ yìí", "choose_account": "Yan àkáǹtì", "choose_address": "\n\nẸ jọ̀wọ́ yan àdírẹ́sì:", + "choose_card_value": "Yan iye kaadi", "choose_derivation": "Yan awọn apamọwọ apamọwọ", "choose_from_available_options": "Ẹ yàn láti àwọn ìyàn yìí:", "choose_one": "Ẹ yàn kan", @@ -166,6 +167,7 @@ "copy_address": "Ṣẹ̀dà àdírẹ́sì", "copy_id": "Ṣẹ̀dà àmì ìdánimọ̀", "copyWalletConnectLink": "Daakọ ọna asopọ WalletConnect lati dApp ki o si lẹẹmọ nibi", + "countries": "Awọn orilẹ-ede", "create_account": "Dá àkáǹtì", "create_backup": "Ṣẹ̀dà nípamọ́", "create_donation_link": "Ṣe kọọkan alabara asopọ", @@ -178,6 +180,7 @@ "custom": "Ohun t'á ti pààrọ̀", "custom_drag": "Aṣa (mu ati fa)", "custom_redeem_amount": "Iye owó l'á máa ná", + "custom_value": "Iye aṣa", "dark_theme": "Dúdú", "debit_card": "Káàdì ìrajà", "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 @@ "delete_wallet": "Pa àpamọ́wọ́", "delete_wallet_confirm_message": "Ṣó dá ẹ lójú pé ẹ fẹ́ pa àpamọ́wọ́ ${wallet_name}?", "deleteConnectionConfirmationPrompt": "Ṣe o da ọ loju pe o fẹ paarẹ asopọ si", + "denominations": "Awọn ede", "descending": "Sọkalẹ", "description": "Apejuwe", "destination_tag": "Orúkọ tí ìbí tó a ránṣẹ́ sí:", @@ -278,6 +282,7 @@ "expired": "Kíkú", "expires": "Ó parí", "expiresOn": "Ipari lori", + "expiry_and_validity": "Ipari ati idaniloju", "export_backup": "Sún ẹ̀dà nípamọ́ síta", "extra_id": "Àmì ìdánimọ̀ tó fikún:", "extracted_address_content": "Ẹ máa máa fi owó ránṣẹ́ sí\n${recipient_name}", @@ -309,7 +314,7 @@ "gift_card_is_generated": "A ti dá káàdí ìrajà t'á lò nínú irú kan ìtajà", "gift_card_number": "Òǹkà káàdì ìrajì", "gift_card_redeemed_note": "Àwọn káàdì ìrajà t'á lò nínú irú kan ìtajà t'ẹ́ ti lò máa fihàn ḿbí", - "gift_cards": "Àwọn káàdì ìrajà t'á lò nínú iye kan ìtajà", + "gift_cards": "Awọn kaadi ẹbun", "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ọ́", "got_it": "Ó dáa", "gross_balance": "Iwontunws.funfun apapọ", @@ -385,6 +390,7 @@ "new_template": "Àwòṣe títun", "new_wallet": "Àpamọ́wọ́ títun", "newConnection": "Tuntun Asopọ", + "no_cards_found": "Ko si awọn kaadi ti a rii", "no_id_needed": "Ẹ kò nílò àmì ìdánimọ̀!", "no_id_required": "Ẹ kò nílò àmì ìdánimọ̀. Ẹ lè fikún owó àti san níbikíbi", "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 @@ "pre_seed_button_text": "Mo ti gbọ́. O fi hóró mi hàn mi", "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.", "pre_seed_title": "Ó TI ṢE PÀTÀKÌ", + "prepaid_cards": "Awọn kaadi ti a ti sanwo", "prevent_screenshots": "Pese asapọ ti awọn ẹrọ eto aṣa", "privacy": "Ìdáwà", "privacy_policy": "Òfin Aládàáni", @@ -468,6 +475,7 @@ "purple_dark_theme": "Akọle dudu dudu", "qr_fullscreen": "Àmì ìlujá túbọ̀ máa tóbi tí o bá tẹ̀", "qr_payment_amount": "Iye owó t'á ránṣé wà nínú àmì ìlujá yìí. Ṣé ẹ fẹ́ pààrọ̀ ẹ̀?", + "quantity": "Ọpọ", "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.", "receivable_balance": "Iwontunws.funfun ti o gba", "receive": "Gbà", @@ -709,6 +717,7 @@ "tokenID": "ID", "tor_connection": "Tor asopọ", "tor_only": "Tor nìkan", + "total": "Apapọ", "total_saving": "Owó t'ẹ́ ti pamọ́", "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.", "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 @@ "use_ssl": "Lo SSL", "use_suggested": "Lo àbá", "use_testnet": "Lo tele", + "value": "Iye", + "value_type": "Iru iye", "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ìí", "verification": "Ìjẹ́rìísí", "verify_with_2fa": "Ṣeẹda pẹlu Cake 2FA", diff --git a/res/values/strings_zh.arb b/res/values/strings_zh.arb index be1234325..297f7ef28 100644 --- a/res/values/strings_zh.arb +++ b/res/values/strings_zh.arb @@ -87,6 +87,7 @@ "buy": "购买", "buy_alert_content": "目前我们仅支持购买比特币、以太坊、莱特币和门罗币。请创建或切换到您的比特币、以太坊、莱特币或门罗币钱包。", "buy_bitcoin": "购买比特币", + "buy_now": "立即购买", "buy_provider_unavailable": "提供者目前不可用。", "buy_with": "一起购买", "by_cake_pay": "通过 Cake Pay", @@ -94,8 +95,7 @@ "cake_dark_theme": "蛋糕黑暗主题", "cake_pay_account_note": "只需使用電子郵件地址註冊即可查看和購買卡片。有些甚至可以打折!", "cake_pay_learn_more": "立即在应用中购买和兑换礼品卡!\n从左向右滑动以了解详情。", - "cake_pay_subtitle": "购买打折礼品卡(仅限美国)", - "cake_pay_title": "Cake Pay 礼品卡", + "cake_pay_subtitle": "购买全球预付费卡和礼品卡", "cake_pay_web_cards_subtitle": "购买全球预付卡和礼品卡", "cake_pay_web_cards_title": "蛋糕支付网络卡", "cake_wallet": "Cake Wallet", @@ -123,6 +123,7 @@ "change_wallet_alert_title": "更换当前钱包", "choose_account": "选择账户", "choose_address": "\n\n請選擇地址:", + "choose_card_value": "选择卡值", "choose_derivation": "选择钱包推导", "choose_from_available_options": "从可用选项中选择:", "choose_one": "选一个", @@ -166,6 +167,7 @@ "copy_address": "复制地址", "copy_id": "复制ID", "copyWalletConnectLink": "从 dApp 复制 WalletConnect 链接并粘贴到此处", + "countries": "国家", "create_account": "创建账户", "create_backup": "创建备份", "create_donation_link": "创建捐赠链接", @@ -178,6 +180,7 @@ "custom": "自定义", "custom_drag": "定制(保持和拖动)", "custom_redeem_amount": "自定义兑换金额", + "custom_value": "自定义值", "dark_theme": "黑暗", "debit_card": "借记卡", "debit_card_terms": "您的支付卡号(以及与您的支付卡号对应的凭证)在此数字钱包中的存储和使用受适用的持卡人与支付卡发卡机构签订的协议的条款和条件的约束,自时不时。", @@ -190,6 +193,7 @@ "delete_wallet": "删除钱包", "delete_wallet_confirm_message": "您确定要删除 ${wallet_name} 钱包吗?", "deleteConnectionConfirmationPrompt": "您确定要删除与", + "denominations": "教派", "descending": "下降", "description": "描述", "destination_tag": "目标Tag:", @@ -277,6 +281,7 @@ "expired": "已过期", "expires": "过期", "expiresOn": "到期", + "expiry_and_validity": "到期和有效性", "export_backup": "导出备份", "extra_id": "额外ID:", "extracted_address_content": "您将汇款至\n${recipient_name}", @@ -384,6 +389,7 @@ "new_template": "新模板", "new_wallet": "新钱包", "newConnection": "新连接", + "no_cards_found": "找不到卡", "no_id_needed": "不需要 ID!", "no_id_required": "不需要身份证。充值并在任何地方消费", "no_relay_on_domain": "用户域没有中继或中继不可用。请选择要使用的继电器。", @@ -452,6 +458,7 @@ "pre_seed_button_text": "我明白。 查看种子", "pre_seed_description": "在下一页上,您将看到${words}个文字。 这是您独有的种子,是丟失或出现故障时恢复钱包的唯一方法。 您有必须将其写下并储存在Cake Wallet应用程序以外的安全地方。", "pre_seed_title": "重要", + "prepaid_cards": "预付费卡", "prevent_screenshots": "防止截屏和录屏", "privacy": "隐私", "privacy_policy": "隐私政策", @@ -467,6 +474,7 @@ "purple_dark_theme": "紫色的黑暗主题", "qr_fullscreen": "点击打开全屏二维码", "qr_payment_amount": "This QR code contains a payment amount. Do you want to overwrite the current value?", + "quantity": "数量", "question_to_disable_2fa": "您确定要禁用 Cake 2FA 吗?访问钱包和某些功能将不再需要 2FA 代码。", "receivable_balance": "应收余额", "receive": "接收", @@ -708,6 +716,7 @@ "tokenID": "ID", "tor_connection": "Tor连接", "tor_only": "仅限 Tor", + "total": "全部的", "total_saving": "总储蓄", "totp_2fa_failure": "不正确的代码。 请尝试不同的代码或生成新的密钥。 使用支持 8 位代码和 SHA512 的兼容 2FA 应用程序。", "totp_2fa_success": "成功!为此钱包启用了 Cake 2FA。请记住保存您的助记词种子,以防您无法访问钱包。", @@ -798,6 +807,8 @@ "use_ssl": "使用SSL", "use_suggested": "使用建议", "use_testnet": "使用TestNet", + "value": "价值", + "value_type": "值类型", "variable_pair_not_supported": "所选交易所不支持此变量对", "verification": "验证", "verify_with_2fa": "用 Cake 2FA 验证", diff --git a/scripts/android/inject_app_details.sh b/scripts/android/inject_app_details.sh index 27b7efa39..3fa9ef921 100755 --- a/scripts/android/inject_app_details.sh +++ b/scripts/android/inject_app_details.sh @@ -6,7 +6,7 @@ if [ -z "$APP_ANDROID_TYPE" ]; then fi cd ../.. -sed -i "0,/version:/{s/version:.*/version: ${APP_ANDROID_VERSION}+${APP_ANDROID_BUILD_NUMBER}/}" ./pubspec.yaml +sed -i "0,/version:/{s/version:.*/version: ${APP_ANDROID_VERSION}+${APP_ANDROID_BUILD_NUMBER}/}" ./pubspec.yaml sed -i "0,/version:/{s/__APP_PACKAGE__/${APP_ANDROID_PACKAGE}/}" ./android/app/src/main/AndroidManifest.xml sed -i "0,/__APP_SCHEME__/s/__APP_SCHEME__/${APP_ANDROID_SCHEME}/" ./android/app/src/main/AndroidManifest.xml sed -i "0,/version:/{s/__versionCode__/${APP_ANDROID_BUILD_NUMBER}/}" ./android/app/src/main/AndroidManifest.xml