Merge pull request #657 from cake-tech/CW-66-open-app-from-qr-code

Cw 66 open app from qr code
This commit is contained in:
Omar Hatem 2022-12-13 20:38:06 +02:00 committed by GitHub
commit b21bcf3652
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 195 additions and 51 deletions

View file

@ -39,6 +39,15 @@
android:scheme="cakewallet" android:scheme="cakewallet"
android:host="y.at" /> android:host="y.at" />
</intent-filter> </intent-filter>
<!-- currencies qr code scheme -->
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="bitcoin" />
<data android:scheme="monero" />
<data android:scheme="litecoin" />
</intent-filter>
</activity> </activity>
<meta-data <meta-data
android:name="flutterEmbedding" android:name="flutterEmbedding"

View file

@ -21,18 +21,48 @@
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleURLTypes</key> <key>CFBundleURLTypes</key>
<array> <array>
<dict> <dict>
<key>CFBundleTypeRole</key> <key>CFBundleTypeRole</key>
<string>Editor</string> <string>Editor</string>
<key>CFBundleURLName</key> <key>CFBundleURLName</key>
<string>y.at</string> <string>y.at</string>
<key>CFBundleURLSchemes</key> <key>CFBundleURLSchemes</key>
<array> <array>
<string>cakewallet</string> <string>cakewallet</string>
</array> </array>
</dict> </dict>
</array> <dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>bitcoin</string>
<key>CFBundleURLSchemes</key>
<array>
<string>bitcoin</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>monero</string>
<key>CFBundleURLSchemes</key>
<array>
<string>monero</string>
</array>
</dict>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>litecoin</string>
<key>CFBundleURLSchemes</key>
<array>
<string>litecoin</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string> <string>$(CURRENT_PROJECT_VERSION)</string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>

View file

@ -13,6 +13,7 @@ import 'package:cake_wallet/src/screens/ionia/cards/ionia_custom_redeem_page.dar
import 'package:cake_wallet/src/screens/ionia/cards/ionia_gift_card_detail_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_more_options_page.dart';
import 'package:cake_wallet/src/screens/settings/connection_sync_page.dart'; import 'package:cake_wallet/src/screens/settings/connection_sync_page.dart';
import 'package:cake_wallet/utils/payment_request.dart';
import 'package:cake_wallet/view_model/ionia/ionia_auth_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_buy_card_view_model.dart';
import 'package:cake_wallet/view_model/ionia/ionia_custom_tip_view_model.dart'; import 'package:cake_wallet/view_model/ionia/ionia_custom_tip_view_model.dart';
@ -384,8 +385,11 @@ Future setup(
getIt.get<BalanceViewModel>(), getIt.get<BalanceViewModel>(),
_transactionDescriptionBox)); _transactionDescriptionBox));
getIt.registerFactory( getIt.registerFactoryParam<SendPage, PaymentRequest?, void>(
() => SendPage(sendViewModel: getIt.get<SendViewModel>())); (PaymentRequest? initialPaymentRequest, _) => SendPage(
sendViewModel: getIt.get<SendViewModel>(),
initialPaymentRequest: initialPaymentRequest,
));
getIt.registerFactory(() => SendTemplatePage( getIt.registerFactory(() => SendTemplatePage(
sendTemplateViewModel: getIt.get<SendTemplateViewModel>())); sendTemplateViewModel: getIt.get<SendTemplateViewModel>()));

View file

@ -204,12 +204,6 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
//_handleInitialUri(); //_handleInitialUri();
} }
@override
void dispose() {
stream?.cancel();
super.dispose();
}
Future<void> _handleInitialUri() async { Future<void> _handleInitialUri() async {
try { try {
final uri = await getInitialUri(); final uri = await getInitialUri();

View file

@ -25,6 +25,7 @@ import 'package:cake_wallet/src/screens/settings/connection_sync_page.dart';
import 'package:cake_wallet/src/screens/support/support_page.dart'; import 'package:cake_wallet/src/screens/support/support_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_details_page.dart';
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart'; import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
import 'package:cake_wallet/utils/payment_request.dart';
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart'; import 'package:cake_wallet/view_model/monero_account_list/account_list_item.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_create_or_edit_view_model.dart';
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart'; import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
@ -216,8 +217,12 @@ Route<dynamic> createRoute(RouteSettings settings) {
builder: (_) => getIt.get<DashboardPage>()); builder: (_) => getIt.get<DashboardPage>());
case Routes.send: case Routes.send:
final initialPaymentRequest = settings.arguments as PaymentRequest?;
return CupertinoPageRoute<void>( return CupertinoPageRoute<void>(
fullscreenDialog: true, builder: (_) => getIt.get<SendPage>()); fullscreenDialog: true, builder: (_) => getIt.get<SendPage>(
param1: initialPaymentRequest,
));
case Routes.sendTemplate: case Routes.sendTemplate:
return CupertinoPageRoute<void>( return CupertinoPageRoute<void>(

View file

@ -1,10 +1,12 @@
import 'dart:async'; import 'dart:async';
import 'package:cake_wallet/utils/payment_request.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/auth/auth_page.dart'; import 'package:cake_wallet/src/screens/auth/auth_page.dart';
import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/store/authentication_store.dart'; import 'package:cake_wallet/store/authentication_store.dart';
import 'package:cake_wallet/entities/qr_scanner.dart'; import 'package:cake_wallet/entities/qr_scanner.dart';
import 'package:uni_links/uni_links.dart';
class Root extends StatefulWidget { class Root extends StatefulWidget {
Root( Root(
@ -35,6 +37,9 @@ class RootState extends State<Root> with WidgetsBindingObserver {
bool _isInactive; bool _isInactive;
bool _postFrameCallback; bool _postFrameCallback;
StreamSubscription<Uri?>? stream;
Uri? launchUri;
@override @override
void initState() { void initState() {
_isInactiveController = StreamController<bool>.broadcast(); _isInactiveController = StreamController<bool>.broadcast();
@ -42,6 +47,34 @@ class RootState extends State<Root> with WidgetsBindingObserver {
_postFrameCallback = false; _postFrameCallback = false;
WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance.addObserver(this);
super.initState(); super.initState();
initUniLinks();
}
@override
void dispose() {
stream?.cancel();
super.dispose();
}
/// handle app links while the app is already started
/// whether its in the foreground or in the background.
Future<void> initUniLinks() async {
try {
stream = uriLinkStream.listen((Uri? uri) {
handleDeepLinking(uri);
});
handleDeepLinking(await getInitialUri());
} catch (e) {
print(e);
}
}
void handleDeepLinking(Uri? uri) {
if (uri == null || !mounted) return;
launchUri = uri;
} }
@override @override
@ -75,7 +108,11 @@ class RootState extends State<Root> with WidgetsBindingObserver {
} }
_reset(); _reset();
auth.close(); auth.close(
route: launchUri != null ? Routes.send : null,
arguments: PaymentRequest.fromUri(launchUri),
);
launchUri = null;
}); });
}); });
} }

View file

@ -4,6 +4,7 @@ import 'package:cake_wallet/src/screens/send/widgets/send_card.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/src/widgets/picker.dart'; import 'package:cake_wallet/src/widgets/picker.dart';
import 'package:cake_wallet/src/widgets/template_tile.dart'; import 'package:cake_wallet/src/widgets/template_tile.dart';
import 'package:cake_wallet/utils/payment_request.dart';
import 'package:cake_wallet/view_model/send/output.dart'; import 'package:cake_wallet/view_model/send/output.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
@ -25,11 +26,15 @@ import 'package:smooth_page_indicator/smooth_page_indicator.dart';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
class SendPage extends BasePage { class SendPage extends BasePage {
SendPage({required this.sendViewModel}) : _formKey = GlobalKey<FormState>(); SendPage({
required this.sendViewModel,
this.initialPaymentRequest,
}) : _formKey = GlobalKey<FormState>();
final SendViewModel sendViewModel; final SendViewModel sendViewModel;
final GlobalKey<FormState> _formKey; final GlobalKey<FormState> _formKey;
final controller = PageController(initialPage: 0); final controller = PageController(initialPage: 0);
final PaymentRequest? initialPaymentRequest;
bool _effectsInstalled = false; bool _effectsInstalled = false;
@ -116,6 +121,7 @@ class SendPage extends BasePage {
key: output.key, key: output.key,
output: output, output: output,
sendViewModel: sendViewModel, sendViewModel: sendViewModel,
initialPaymentRequest: initialPaymentRequest,
); );
}); });
}, },

View file

@ -1,4 +1,5 @@
import 'package:cake_wallet/entities/priority_for_wallet_type.dart'; import 'package:cake_wallet/entities/priority_for_wallet_type.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/utils/payment_request.dart'; import 'package:cake_wallet/utils/payment_request.dart';
import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/transaction_priority.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
@ -20,21 +21,28 @@ class SendCard extends StatefulWidget {
SendCard({ SendCard({
Key? key, Key? key,
required this.output, required this.output,
required this.sendViewModel}) : super(key: key); required this.sendViewModel,
this.initialPaymentRequest,
}) : super(key: key);
final Output output; final Output output;
final SendViewModel sendViewModel; final SendViewModel sendViewModel;
final PaymentRequest? initialPaymentRequest;
@override @override
SendCardState createState() => SendCardState( SendCardState createState() => SendCardState(
output: output, output: output,
sendViewModel: sendViewModel sendViewModel: sendViewModel,
initialPaymentRequest: initialPaymentRequest,
); );
} }
class SendCardState extends State<SendCard> class SendCardState extends State<SendCard>
with AutomaticKeepAliveClientMixin<SendCard> { with AutomaticKeepAliveClientMixin<SendCard> {
SendCardState({required this.output, required this.sendViewModel}) SendCardState({
required this.output,
required this.sendViewModel,
this.initialPaymentRequest})
: addressController = TextEditingController(), : addressController = TextEditingController(),
cryptoAmountController = TextEditingController(), cryptoAmountController = TextEditingController(),
fiatAmountController = TextEditingController(), fiatAmountController = TextEditingController(),
@ -49,6 +57,7 @@ class SendCardState extends State<SendCard>
final Output output; final Output output;
final SendViewModel sendViewModel; final SendViewModel sendViewModel;
final PaymentRequest? initialPaymentRequest;
final TextEditingController addressController; final TextEditingController addressController;
final TextEditingController cryptoAmountController; final TextEditingController cryptoAmountController;
@ -61,6 +70,27 @@ class SendCardState extends State<SendCard>
bool _effectsInstalled = false; bool _effectsInstalled = false;
@override
void initState() {
super.initState();
/// if the current wallet doesn't match the one in the qr code
if (initialPaymentRequest != null &&
sendViewModel.walletCurrencyName != initialPaymentRequest!.scheme.toLowerCase()) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithOneAction(
alertTitle: S.of(context).error,
alertContent: S.of(context).unmatched_currencies,
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop());
});
});
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
super.build(context); super.build(context);
@ -512,8 +542,12 @@ class SendCardState extends State<SendCard>
} }
void _setEffects(BuildContext context) { void _setEffects(BuildContext context) {
addressController.text = output.address; if (output.address.isNotEmpty) {
cryptoAmountController.text = output.cryptoAmount; addressController.text = output.address;
}
if (output.cryptoAmount.isNotEmpty) {
cryptoAmountController.text = output.cryptoAmount;
}
fiatAmountController.text = output.fiatAmount; fiatAmountController.text = output.fiatAmount;
noteController.text = output.note; noteController.text = output.note;
extractedAddressController.text = output.extractedAddress; extractedAddressController.text = output.extractedAddress;
@ -605,6 +639,13 @@ class SendCardState extends State<SendCard>
extractedAddressController.text = extractedAddress; extractedAddressController.text = extractedAddress;
}); });
if (initialPaymentRequest != null &&
sendViewModel.walletCurrencyName == initialPaymentRequest!.scheme.toLowerCase()) {
addressController.text = initialPaymentRequest!.address;
cryptoAmountController.text = initialPaymentRequest!.amount;
noteController.text = initialPaymentRequest!.note;
}
_effectsInstalled = true; _effectsInstalled = true;
} }

View file

@ -1,22 +1,25 @@
class PaymentRequest { class PaymentRequest {
PaymentRequest(this.address, this.amount, this.note); PaymentRequest(this.address, this.amount, this.note, this.scheme);
factory PaymentRequest.fromUri(Uri uri) { factory PaymentRequest.fromUri(Uri? uri) {
var address = ""; var address = "";
var amount = ""; var amount = "";
var note = ""; var note = "";
var scheme = "";
if (uri != null) { if (uri != null) {
address = uri.path; address = uri.path;
amount = uri.queryParameters['tx_amount'] ?? uri.queryParameters['amount'] ?? ""; amount = uri.queryParameters['tx_amount'] ?? uri.queryParameters['amount'] ?? "";
note = uri.queryParameters['tx_description'] note = uri.queryParameters['tx_description']
?? uri.queryParameters['message'] ?? ""; ?? uri.queryParameters['message'] ?? "";
scheme = uri.scheme;
} }
return PaymentRequest(address, amount, note); return PaymentRequest(address, amount, note, scheme);
} }
final String address; final String address;
final String amount; final String amount;
final String note; final String note;
final String scheme;
} }

View file

@ -53,7 +53,7 @@ abstract class SendViewModelBase with Store {
outputs.add(Output(_wallet, _settingsStore, _fiatConversationStore, () => selectedCryptoCurrency)); outputs.add(Output(_wallet, _settingsStore, _fiatConversationStore, () => selectedCryptoCurrency));
} }
@observable @observable
ExecutionState state; ExecutionState state;
@ -180,6 +180,8 @@ abstract class SendViewModelBase with Store {
WalletType get walletType => _wallet.type; WalletType get walletType => _wallet.type;
String? get walletCurrencyName => _wallet.currency.name?.toLowerCase();
bool get hasCurrecyChanger => walletType == WalletType.haven; bool get hasCurrecyChanger => walletType == WalletType.haven;
@computed @computed
@ -306,7 +308,7 @@ abstract class SendViewModelBase with Store {
@action @action
void onClose() => void onClose() =>
_settingsStore.fiatCurrency = fiatFromSettings; _settingsStore.fiatCurrency = fiatFromSettings;
@action @action
void setFiatCurrency(FiatCurrency fiat) => void setFiatCurrency(FiatCurrency fiat) =>
_settingsStore.fiatCurrency = fiat; _settingsStore.fiatCurrency = fiat;

View file

@ -669,5 +669,6 @@
"fiat_api": "Fiat API", "fiat_api": "Fiat API",
"disabled": "Deaktiviert", "disabled": "Deaktiviert",
"enabled": "Ermöglicht", "enabled": "Ermöglicht",
"tor_only": "Nur Tor" "tor_only": "Nur Tor",
"unmatched_currencies": "Die Währung Ihres aktuellen Wallets stimmt nicht mit der des gescannten QR überein"
} }

View file

@ -669,5 +669,6 @@
"fiat_api": "Fiat API", "fiat_api": "Fiat API",
"disabled": "Disabled", "disabled": "Disabled",
"enabled": "Enabled", "enabled": "Enabled",
"tor_only": "Tor only" "tor_only": "Tor only",
"unmatched_currencies": "Your current wallet's currency does not match that of the scanned QR"
} }

View file

@ -669,5 +669,6 @@
"fiat_api": "Fiat API", "fiat_api": "Fiat API",
"disabled": "Desactivado", "disabled": "Desactivado",
"enabled": "Activado", "enabled": "Activado",
"tor_only": "solo Tor" "tor_only": "solo Tor",
"unmatched_currencies": "La moneda de su billetera actual no coincide con la del QR escaneado"
} }

View file

@ -667,5 +667,6 @@
"fiat_api": "Fiat API", "fiat_api": "Fiat API",
"disabled": "Handicapé", "disabled": "Handicapé",
"enabled": "Activé", "enabled": "Activé",
"tor_only": "Tor uniquement" "tor_only": "Tor uniquement",
"unmatched_currencies": "La devise de votre portefeuille actuel ne correspond pas à celle du QR scanné"
} }

View file

@ -665,9 +665,9 @@
"advanced_privacy_settings": "उन्नत गोपनीयता सेटिंग्स", "advanced_privacy_settings": "उन्नत गोपनीयता सेटिंग्स",
"settings_can_be_changed_later": "इन सेटिंग्स को बाद में ऐप सेटिंग में बदला जा सकता है", "settings_can_be_changed_later": "इन सेटिंग्स को बाद में ऐप सेटिंग में बदला जा सकता है",
"add_custom_node": "नया कस्टम नोड जोड़ें", "add_custom_node": "नया कस्टम नोड जोड़ें",
"disable_exchange": "एक्सचेंज अक्षम करें",
"fiat_api": "फिएट पैसे API", "fiat_api": "फिएट पैसे API",
"disabled": "अक्षम", "disabled": "अक्षम",
"enabled": "सक्रिय", "enabled": "सक्रिय",
"tor_only": "Tor केवल" "tor_only": "Tor केवल",
"unmatched_currencies": "आपके वर्तमान वॉलेट की मुद्रा स्कैन किए गए क्यूआर से मेल नहीं खाती"
} }

View file

@ -669,5 +669,6 @@
"fiat_api": "Fiat API", "fiat_api": "Fiat API",
"disabled": "Onemogućeno", "disabled": "Onemogućeno",
"enabled": "Omogućeno", "enabled": "Omogućeno",
"tor_only": "Samo Tor" "tor_only": "Samo Tor",
"unmatched_currencies": "Valuta vašeg trenutnog novčanika ne odgovara onoj na skeniranom QR-u"
} }

View file

@ -669,5 +669,6 @@
"fiat_api": "Fiat API", "fiat_api": "Fiat API",
"disabled": "Disabilitato", "disabled": "Disabilitato",
"enabled": "Abilitato", "enabled": "Abilitato",
"tor_only": "Solo Tor" "tor_only": "Solo Tor",
"unmatched_currencies": "La valuta del tuo portafoglio attuale non corrisponde a quella del QR scansionato"
} }

View file

@ -669,5 +669,6 @@
"fiat_api": "不換紙幣 API", "fiat_api": "不換紙幣 API",
"disabled": "無効", "disabled": "無効",
"enabled": "有効", "enabled": "有効",
"tor_only": "Torのみ" "tor_only": "Torのみ",
"unmatched_currencies": "現在のウォレットの通貨がスキャンされたQRの通貨と一致しません"
} }

View file

@ -669,5 +669,6 @@
"fiat_api": "명목 화폐 API", "fiat_api": "명목 화폐 API",
"disabled": "장애가 있는", "disabled": "장애가 있는",
"enabled": "사용", "enabled": "사용",
"tor_only": "Tor 뿐" "tor_only": "Tor 뿐",
"unmatched_currencies": "현재 지갑의 통화가 스캔한 QR의 통화와 일치하지 않습니다."
} }

View file

@ -669,5 +669,6 @@
"fiat_api": "Fiat API", "fiat_api": "Fiat API",
"disabled": "Gehandicapt", "disabled": "Gehandicapt",
"enabled": "Ingeschakeld", "enabled": "Ingeschakeld",
"tor_only": "Alleen Tor" "tor_only": "Alleen Tor",
"unmatched_currencies": "De valuta van uw huidige portemonnee komt niet overeen met die van de gescande QR"
} }

View file

@ -669,5 +669,6 @@
"fiat_api": "API Fiata", "fiat_api": "API Fiata",
"disabled": "Wyłączone", "disabled": "Wyłączone",
"enabled": "Włączony", "enabled": "Włączony",
"tor_only": "Tylko Tor" "tor_only": "Tylko Tor",
"unmatched_currencies": "Waluta Twojego obecnego portfela nie odpowiada walucie zeskanowanego kodu QR"
} }

View file

@ -668,5 +668,6 @@
"fiat_api": "API da Fiat", "fiat_api": "API da Fiat",
"disabled": "Desabilitado", "disabled": "Desabilitado",
"enabled": "Habilitado", "enabled": "Habilitado",
"tor_only": "Tor apenas" "tor_only": "Tor apenas",
"unmatched_currencies": "A moeda da sua carteira atual não corresponde à do QR digitalizado"
} }

View file

@ -369,7 +369,7 @@
"trade_for_not_created" : "Сделка для ${title} не создана.", "trade_for_not_created" : "Сделка для ${title} не создана.",
"trade_not_created" : "Сделка не создана", "trade_not_created" : "Сделка не создана",
"trade_id_not_found" : "Сделка ${tradeId} ${title} не найдена.", "trade_id_not_found" : "Сделка ${tradeId} ${title} не найдена.",
"trade_not_found" : "Trade not found.", "trade_not_found" : "Торговля не найдена.",
"trade_state_pending" : "Ожидание", "trade_state_pending" : "Ожидание",
@ -669,5 +669,6 @@
"fiat_api": "Фиат API", "fiat_api": "Фиат API",
"disabled": "Отключено", "disabled": "Отключено",
"enabled": "Включено", "enabled": "Включено",
"tor_only": "Только Tor" "tor_only": "Только Tor",
"unmatched_currencies": "Валюта вашего текущего кошелька не соответствует валюте отсканированного QR-кода."
} }

View file

@ -668,6 +668,6 @@
"fiat_api": "Фіат API", "fiat_api": "Фіат API",
"disabled": "Вимкнено", "disabled": "Вимкнено",
"enabled": "Увімкнено", "enabled": "Увімкнено",
"tor_only": "Тільки Tor" "tor_only": "Тільки Tor",
"unmatched_currencies": "Валюта вашого гаманця не збігається з валютою сканованого QR-коду"
} }

View file

@ -667,5 +667,6 @@
"fiat_api": "法币API", "fiat_api": "法币API",
"disabled": "禁用", "disabled": "禁用",
"enabled": "启用", "enabled": "启用",
"tor_only": "仅限 Tor" "tor_only": "仅限 Tor",
"unmatched_currencies": "您当前钱包的货币与扫描的 QR 的货币不匹配"
} }