mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-22 19:49:22 +00:00
Merge branch 'main' into CW-302-Update-Cake-Pay-checkout-wording-for-Bitcoin-only
This commit is contained in:
commit
50f1c051f9
46 changed files with 467 additions and 367 deletions
1
.github/workflows/pr_test_build.yml
vendored
1
.github/workflows/pr_test_build.yml
vendored
|
@ -110,6 +110,7 @@ jobs:
|
|||
echo "const onramperApiKey = '${{ secrets.ONRAMPER_API_KEY }}';" >> lib/.secrets.g.dart
|
||||
echo "const anypayToken = '${{ secrets.ANY_PAY_TOKEN }}';" >> lib/.secrets.g.dart
|
||||
echo "const ioniaClientId = '${{ secrets.IONIA_CLIENT_ID }}';" >> lib/.secrets.g.dart
|
||||
echo "const twitterBearerToken = '${{ secrets.TWITTER_BEARER_TOKEN }}';" >> lib/.secrets.g.dart
|
||||
|
||||
- name: Rename app
|
||||
run: sed -i -e "s/\${APP_NAME}/$GITHUB_HEAD_REF/g" /opt/android/cake_wallet/android/app/src/main/AndroidManifest.xml
|
||||
|
|
|
@ -119,7 +119,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
|
|||
static const ape = CryptoCurrency(title: 'APE', tag: 'ETH', fullName: 'ApeCoin', raw: 30, name: 'ape', iconPath: 'assets/images/ape_icon.png');
|
||||
static const avaxc = CryptoCurrency(title: 'AVAX', tag: 'C-CHAIN', raw: 31, name: 'avaxc', iconPath: 'assets/images/avaxc_icon.png');
|
||||
static const btt = CryptoCurrency(title: 'BTT', tag: 'ETH', fullName: 'BitTorrent', raw: 32, name: 'btt', iconPath: 'assets/images/btt_icon.png');
|
||||
static const bttc = CryptoCurrency(title: 'BTTC', tag: 'BSC', fullName: 'BitTorrent-NEW', raw: 33, name: 'bttc', iconPath: 'assets/images/bttbsc_icon.png');
|
||||
static const bttc = CryptoCurrency(title: 'BTTC', tag: 'TRX', fullName: 'BitTorrent-NEW', raw: 33, name: 'bttc', iconPath: 'assets/images/bttbsc_icon.png');
|
||||
static const doge = CryptoCurrency(title: 'DOGE', fullName: 'Dogecoin', raw: 34, name: 'doge', iconPath: 'assets/images/doge_icon.png');
|
||||
static const firo = CryptoCurrency(title: 'FIRO', raw: 35, name: 'firo', iconPath: 'assets/images/firo_icon.png');
|
||||
static const usdttrc20 = CryptoCurrency(title: 'USDT', tag: 'TRX', fullName: 'USDT Tether', raw: 36, name: 'usdttrc20', iconPath: 'assets/images/usdttrc20_icon.png');
|
||||
|
|
|
@ -198,4 +198,22 @@ class AddressValidator extends TextValidator {
|
|||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
static String? getAddressFromStringPattern(CryptoCurrency type) {
|
||||
switch (type) {
|
||||
case CryptoCurrency.xmr:
|
||||
return '([^0-9a-zA-Z]|^)4[0-9a-zA-Z]{94}([^0-9a-zA-Z]|\$)'
|
||||
'|([^0-9a-zA-Z]|^)8[0-9a-zA-Z]{94}([^0-9a-zA-Z]|\$)'
|
||||
'|([^0-9a-zA-Z]|^)[0-9a-zA-Z]{106}([^0-9a-zA-Z]|\$)';
|
||||
case CryptoCurrency.btc:
|
||||
return '([^0-9a-zA-Z]|^)1[0-9a-zA-Z]{32}([^0-9a-zA-Z]|\$)'
|
||||
'|([^0-9a-zA-Z]|^)1[0-9a-zA-Z]{33}([^0-9a-zA-Z]|\$)'
|
||||
'|([^0-9a-zA-Z]|^)3[0-9a-zA-Z]{32}([^0-9a-zA-Z]|\$)'
|
||||
'|([^0-9a-zA-Z]|^)3[0-9a-zA-Z]{33}([^0-9a-zA-Z]|\$)'
|
||||
'|([^0-9a-zA-Z]|^)bc1[0-9a-zA-Z]{39}([^0-9a-zA-Z]|\$)'
|
||||
'|([^0-9a-zA-Z]|^)bc1[0-9a-zA-Z]{59}([^0-9a-zA-Z]|\$)';
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ 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/wallet_address_list/wallet_address_list_item.dart';
|
||||
import 'package:cw_core/unspent_coins_info.dart';
|
||||
import 'package:cake_wallet/core/backup_service.dart';
|
||||
import 'package:cw_core/wallet_service.dart';
|
||||
|
@ -365,8 +366,8 @@ Future setup(
|
|||
addressListViewModel: getIt.get<WalletAddressListViewModel>(),
|
||||
walletViewModel: getIt.get<DashboardViewModel>()));
|
||||
|
||||
getIt.registerFactoryParam<WalletAddressEditOrCreateViewModel, dynamic, void>(
|
||||
(dynamic item, _) => WalletAddressEditOrCreateViewModel(
|
||||
getIt.registerFactoryParam<WalletAddressEditOrCreateViewModel, WalletAddressListItem?, void>(
|
||||
(WalletAddressListItem? item, _) => WalletAddressEditOrCreateViewModel(
|
||||
wallet: getIt.get<AppStore>().wallet!, item: item));
|
||||
|
||||
getIt.registerFactoryParam<AddressEditOrCreatePage, dynamic, void>(
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:basic_utils/basic_utils.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
||||
class OpenaliasRecord {
|
||||
OpenaliasRecord({
|
||||
|
@ -22,69 +21,68 @@ class OpenaliasRecord {
|
|||
return formattedName;
|
||||
}
|
||||
|
||||
static Future<OpenaliasRecord> fetchAddressAndName({
|
||||
static Future<List<RRecord>?> lookupOpenAliasRecord(String name) async {
|
||||
try {
|
||||
final txtRecord = await DnsUtils.lookupRecord(name, RRecordType.TXT, dnssec: true);
|
||||
|
||||
return txtRecord;
|
||||
} catch (e) {
|
||||
print("${e.toString()}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static OpenaliasRecord fetchAddressAndName({
|
||||
required String formattedName,
|
||||
required String ticker,
|
||||
}) async {
|
||||
required List<RRecord> txtRecord,
|
||||
}) {
|
||||
String address = formattedName;
|
||||
String name = formattedName;
|
||||
String note = '';
|
||||
|
||||
if (formattedName.contains(".")) {
|
||||
try {
|
||||
final txtRecord = await DnsUtils.lookupRecord(
|
||||
formattedName, RRecordType.TXT,
|
||||
dnssec: true);
|
||||
for (RRecord element in txtRecord) {
|
||||
String record = element.data;
|
||||
|
||||
if (txtRecord != null) {
|
||||
for (RRecord element in txtRecord) {
|
||||
String record = element.data;
|
||||
if (record.contains("oa1:$ticker") && record.contains("recipient_address")) {
|
||||
record = record.replaceAll('\"', "");
|
||||
|
||||
if (record.contains("oa1:$ticker") &&
|
||||
record.contains("recipient_address")) {
|
||||
record = record.replaceAll('\"', "");
|
||||
final dataList = record.split(";");
|
||||
|
||||
final dataList = record.split(";");
|
||||
address = dataList
|
||||
.where((item) => (item.contains("recipient_address")))
|
||||
.toString()
|
||||
.replaceAll("oa1:$ticker recipient_address=", "")
|
||||
.replaceAll("(", "")
|
||||
.replaceAll(")", "")
|
||||
.trim();
|
||||
|
||||
address = dataList
|
||||
.where((item) => (item.contains("recipient_address")))
|
||||
.toString()
|
||||
.replaceAll("oa1:$ticker recipient_address=", "")
|
||||
.replaceAll("(", "")
|
||||
.replaceAll(")", "")
|
||||
.trim();
|
||||
final recipientName = dataList
|
||||
.where((item) => (item.contains("recipient_name")))
|
||||
.toString()
|
||||
.replaceAll("(", "")
|
||||
.replaceAll(")", "")
|
||||
.trim();
|
||||
|
||||
final recipientName = dataList
|
||||
.where((item) => (item.contains("recipient_name")))
|
||||
.toString()
|
||||
.replaceAll("(", "")
|
||||
.replaceAll(")", "")
|
||||
.trim();
|
||||
|
||||
if (recipientName.isNotEmpty) {
|
||||
name = recipientName.replaceAll("recipient_name=", "");
|
||||
}
|
||||
|
||||
final description = dataList
|
||||
.where((item) => (item.contains("tx_description")))
|
||||
.toString()
|
||||
.replaceAll("(", "")
|
||||
.replaceAll(")", "")
|
||||
.trim();
|
||||
|
||||
if (description.isNotEmpty) {
|
||||
note = description.replaceAll("tx_description=", "");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (recipientName.isNotEmpty) {
|
||||
name = recipientName.replaceAll("recipient_name=", "");
|
||||
}
|
||||
} catch (e) {
|
||||
print("${e.toString()}");
|
||||
}
|
||||
}
|
||||
|
||||
return OpenaliasRecord(address: address, name: name, description: note);
|
||||
final description = dataList
|
||||
.where((item) => (item.contains("tx_description")))
|
||||
.toString()
|
||||
.replaceAll("(", "")
|
||||
.replaceAll(")", "")
|
||||
.trim();
|
||||
|
||||
if (description.isNotEmpty) {
|
||||
note = description.replaceAll("tx_description=", "");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return OpenaliasRecord(address: address, name: name, description: note);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,40 +1,61 @@
|
|||
import 'package:cake_wallet/core/address_validator.dart';
|
||||
import 'package:cake_wallet/core/yat_service.dart';
|
||||
import 'package:cake_wallet/entities/openalias_record.dart';
|
||||
import 'package:cake_wallet/entities/parsed_address.dart';
|
||||
import 'package:cake_wallet/entities/unstoppable_domain_address.dart';
|
||||
import 'package:cake_wallet/entities/emoji_string_extension.dart';
|
||||
import 'package:cake_wallet/twitter/twitter_api.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/entities/fio_address_provider.dart';
|
||||
|
||||
class AddressResolver {
|
||||
|
||||
AddressResolver({required this.yatService, required this.walletType});
|
||||
|
||||
|
||||
final YatService yatService;
|
||||
final WalletType walletType;
|
||||
|
||||
|
||||
static const unstoppableDomains = [
|
||||
'crypto',
|
||||
'zil',
|
||||
'x',
|
||||
'coin',
|
||||
'wallet',
|
||||
'bitcoin',
|
||||
'888',
|
||||
'nft',
|
||||
'dao',
|
||||
'blockchain'
|
||||
];
|
||||
'crypto',
|
||||
'zil',
|
||||
'x',
|
||||
'coin',
|
||||
'wallet',
|
||||
'bitcoin',
|
||||
'888',
|
||||
'nft',
|
||||
'dao',
|
||||
'blockchain'
|
||||
];
|
||||
|
||||
static String? extractAddressByType({required String raw, required CryptoCurrency type}) {
|
||||
final addressPattern = AddressValidator.getAddressFromStringPattern(type);
|
||||
|
||||
if (addressPattern == null) {
|
||||
throw 'Unexpected token: $type for getAddressFromStringPattern';
|
||||
}
|
||||
|
||||
final match = RegExp(addressPattern).firstMatch(raw);
|
||||
return match?.group(0)?.replaceAll(RegExp('[^0-9a-zA-Z]'), '');
|
||||
}
|
||||
|
||||
Future<ParsedAddress> resolve(String text, String ticker) async {
|
||||
try {
|
||||
if (text.contains('@') && !text.contains('.')) {
|
||||
if (text.startsWith('@') && !text.substring(1).contains('@')) {
|
||||
final formattedName = text.substring(1);
|
||||
final twitterUser = await TwitterApi.lookupUserByName(userName: formattedName);
|
||||
final address = extractAddressByType(
|
||||
raw: twitterUser.description ?? '', type: CryptoCurrency.fromString(ticker));
|
||||
if (address != null) {
|
||||
return ParsedAddress.fetchTwitterAddress(address: address, name: text);
|
||||
}
|
||||
}
|
||||
if (!text.startsWith('@') && text.contains('@') && !text.contains('.')) {
|
||||
final bool isFioRegistered = await FioAddressProvider.checkAvail(text);
|
||||
if (isFioRegistered) {
|
||||
final address = await FioAddressProvider.getPubAddress(text, ticker);
|
||||
return ParsedAddress.fetchFioAddress(address: address, name: text);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (text.hasOnlyEmojis) {
|
||||
if (walletType != WalletType.haven) {
|
||||
|
@ -55,10 +76,14 @@ class AddressResolver {
|
|||
return ParsedAddress.fetchUnstoppableDomainAddress(address: address, name: text);
|
||||
}
|
||||
|
||||
final record = await OpenaliasRecord.fetchAddressAndName(
|
||||
formattedName: formattedName, ticker: ticker);
|
||||
return ParsedAddress.fetchOpenAliasAddress(record: record, name: text);
|
||||
|
||||
if (formattedName.contains(".")) {
|
||||
final txtRecord = await OpenaliasRecord.lookupOpenAliasRecord(formattedName);
|
||||
if (txtRecord != null) {
|
||||
final record = await OpenaliasRecord.fetchAddressAndName(
|
||||
formattedName: formattedName, ticker: ticker, txtRecord: txtRecord);
|
||||
return ParsedAddress.fetchOpenAliasAddress(record: record, name: text);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
}
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
import 'package:cake_wallet/entities/openalias_record.dart';
|
||||
import 'package:cake_wallet/entities/yat_record.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
enum ParseFrom { unstoppableDomains, openAlias, yatRecord, fio, notParsed }
|
||||
enum ParseFrom { unstoppableDomains, openAlias, yatRecord, fio, notParsed, twitter }
|
||||
|
||||
class ParsedAddress {
|
||||
ParsedAddress({
|
||||
|
@ -41,11 +40,7 @@ class ParsedAddress {
|
|||
);
|
||||
}
|
||||
|
||||
factory ParsedAddress.fetchOpenAliasAddress({OpenaliasRecord? record, required String name}){
|
||||
final formattedName = OpenaliasRecord.formatDomainName(name);
|
||||
if (record == null || record.address.contains(formattedName)) {
|
||||
return ParsedAddress(addresses: [name]);
|
||||
}
|
||||
factory ParsedAddress.fetchOpenAliasAddress({required OpenaliasRecord record, required String name}){
|
||||
return ParsedAddress(
|
||||
addresses: [record.address],
|
||||
name: record.name,
|
||||
|
@ -62,6 +57,14 @@ class ParsedAddress {
|
|||
);
|
||||
}
|
||||
|
||||
factory ParsedAddress.fetchTwitterAddress({required String address, required String name}){
|
||||
return ParsedAddress(
|
||||
addresses: [address],
|
||||
name: name,
|
||||
parseFrom: ParseFrom.twitter,
|
||||
);
|
||||
}
|
||||
|
||||
final List<String> addresses;
|
||||
final String name;
|
||||
final String description;
|
||||
|
|
|
@ -143,6 +143,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
final inputAddress = responseJSON['payinAddress'] as String;
|
||||
final refundAddress = responseJSON['refundAddress'] as String;
|
||||
final extraId = responseJSON['payinExtraId'] as String?;
|
||||
final payoutAddress = responseJSON['payoutAddress'] as String;
|
||||
|
||||
return Trade(
|
||||
id: id,
|
||||
|
@ -154,7 +155,8 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
extraId: extraId,
|
||||
createdAt: DateTime.now(),
|
||||
amount: responseJSON['fromAmount']?.toString() ?? _request.fromAmount,
|
||||
state: TradeState.created);
|
||||
state: TradeState.created,
|
||||
payoutAddress: payoutAddress);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -192,6 +194,7 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
final extraId = responseJSON['payinExtraId'] as String;
|
||||
final outputTransaction = responseJSON['payoutHash'] as String;
|
||||
final expiredAtRaw = responseJSON['validUntil'] as String;
|
||||
final payoutAddress = responseJSON['payoutAddress'] as String;
|
||||
final expiredAt = DateTime.tryParse(expiredAtRaw)?.toLocal();
|
||||
|
||||
return Trade(
|
||||
|
@ -204,7 +207,8 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
state: state,
|
||||
extraId: extraId,
|
||||
expiredAt: expiredAt,
|
||||
outputTransaction: outputTransaction);
|
||||
outputTransaction: outputTransaction,
|
||||
payoutAddress: payoutAddress);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -271,6 +275,10 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
switch(currency) {
|
||||
case CryptoCurrency.zec:
|
||||
return 'zec';
|
||||
case CryptoCurrency.usdcpoly:
|
||||
return 'usdcmatic';
|
||||
case CryptoCurrency.maticpoly:
|
||||
return 'maticmainnet';
|
||||
default:
|
||||
return currency.title.toLowerCase();
|
||||
}
|
||||
|
|
|
@ -150,6 +150,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
refundAddress: settleAddress,
|
||||
state: TradeState.created,
|
||||
amount: _request.depositAmount,
|
||||
payoutAddress: settleAddress,
|
||||
createdAt: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
@ -244,6 +245,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
final inputAddress = responseJSON['depositAddress']['address'] as String;
|
||||
final expectedSendAmount = responseJSON['depositAmount'].toString();
|
||||
final deposits = responseJSON['deposits'] as List?;
|
||||
final settleAddress = responseJSON['settleAddress']['address'] as String;
|
||||
TradeState? state;
|
||||
String? status;
|
||||
|
||||
|
@ -264,6 +266,7 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
amount: expectedSendAmount,
|
||||
state: state,
|
||||
expiredAt: expiredAt,
|
||||
payoutAddress: settleAddress
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -108,6 +108,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
|||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
final id = responseJSON['id'] as String;
|
||||
final inputAddress = responseJSON['address_from'] as String;
|
||||
final payoutAddress = responseJSON['address_to'] as String;
|
||||
final settleAddress = responseJSON['user_refund_address'] as String;
|
||||
final extraId = responseJSON['extra_id_from'] as String?;
|
||||
return Trade(
|
||||
|
@ -120,6 +121,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
|||
extraId: extraId,
|
||||
state: TradeState.created,
|
||||
amount: _request.amount,
|
||||
payoutAddress: payoutAddress,
|
||||
createdAt: DateTime.now(),
|
||||
);
|
||||
}
|
||||
|
@ -189,6 +191,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
|||
final expectedSendAmount = responseJSON['expected_amount'].toString();
|
||||
final extraId = responseJSON['extra_id_from'] as String?;
|
||||
final status = responseJSON['status'] as String;
|
||||
final payoutAddress = responseJSON['address_to'] as String;
|
||||
final state = TradeState.deserialize(raw: status);
|
||||
|
||||
return Trade(
|
||||
|
@ -200,6 +203,7 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
|||
inputAddress: inputAddress,
|
||||
amount: expectedSendAmount,
|
||||
state: state,
|
||||
payoutAddress: payoutAddress,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -231,6 +235,10 @@ class SimpleSwapExchangeProvider extends ExchangeProvider {
|
|||
return 'usdcpoly';
|
||||
case CryptoCurrency.usdcsol:
|
||||
return 'usdcspl';
|
||||
case CryptoCurrency.matic:
|
||||
return 'maticerc20';
|
||||
case CryptoCurrency.maticpoly:
|
||||
return 'matic';
|
||||
default:
|
||||
return currency.title.toLowerCase();
|
||||
}
|
||||
|
|
|
@ -21,7 +21,8 @@ class Trade extends HiveObject {
|
|||
this.extraId,
|
||||
this.outputTransaction,
|
||||
this.refundAddress,
|
||||
this.walletId}) {
|
||||
this.walletId,
|
||||
this.payoutAddress}) {
|
||||
if (provider != null) {
|
||||
providerRaw = provider.raw;
|
||||
}
|
||||
|
@ -88,6 +89,9 @@ class Trade extends HiveObject {
|
|||
@HiveField(12)
|
||||
String? walletId;
|
||||
|
||||
@HiveField(13)
|
||||
String? payoutAddress;
|
||||
|
||||
static Trade fromMap(Map<String, Object?> map) {
|
||||
return Trade(
|
||||
id: map['id'] as String,
|
||||
|
|
|
@ -1,22 +1,12 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:isolate';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/core/auth_service.dart';
|
||||
import 'package:cake_wallet/entities/language_service.dart';
|
||||
import 'package:cake_wallet/buy/order.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_category.dart';
|
||||
import 'package:cake_wallet/ionia/ionia_merchant.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/store/yat/yat_store.dart';
|
||||
import 'package:cake_wallet/themes/theme_list.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/utils/exception_handler.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_mailer/flutter_mailer.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
@ -56,14 +46,12 @@ Future<void> main() async {
|
|||
await runZonedGuarded(() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
FlutterError.onError = (errorDetails) {
|
||||
_onError(errorDetails);
|
||||
};
|
||||
FlutterError.onError = ExceptionHandler.onError;
|
||||
|
||||
/// A callback that is invoked when an unhandled error occurs in the root
|
||||
/// isolate.
|
||||
PlatformDispatcher.instance.onError = (error, stack) {
|
||||
_onError(FlutterErrorDetails(exception: error, stack: stack));
|
||||
ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack));
|
||||
|
||||
return true;
|
||||
};
|
||||
|
@ -154,85 +142,10 @@ Future<void> main() async {
|
|||
initialMigrationVersion: 19);
|
||||
runApp(App());
|
||||
}, (error, stackTrace) async {
|
||||
_onError(FlutterErrorDetails(exception: error, stack: stackTrace));
|
||||
ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stackTrace));
|
||||
});
|
||||
}
|
||||
|
||||
void _saveException(String? error, StackTrace? stackTrace) async {
|
||||
final appDocDir = await getApplicationDocumentsDirectory();
|
||||
|
||||
final file = File('${appDocDir.path}/error.txt');
|
||||
final exception = {
|
||||
"${DateTime.now()}": {
|
||||
"Error": error,
|
||||
"StackTrace": stackTrace.toString(),
|
||||
}
|
||||
};
|
||||
|
||||
const String separator =
|
||||
'''\n\n==========================================================
|
||||
==========================================================\n\n''';
|
||||
|
||||
await file.writeAsString(
|
||||
jsonEncode(exception) + separator,
|
||||
mode: FileMode.append,
|
||||
);
|
||||
}
|
||||
|
||||
void _sendExceptionFile() async {
|
||||
try {
|
||||
final appDocDir = await getApplicationDocumentsDirectory();
|
||||
|
||||
final file = File('${appDocDir.path}/error.txt');
|
||||
|
||||
final MailOptions mailOptions = MailOptions(
|
||||
subject: 'Mobile App Issue',
|
||||
recipients: ['support@cakewallet.com'],
|
||||
attachments: [file.path],
|
||||
);
|
||||
|
||||
final result = await FlutterMailer.send(mailOptions);
|
||||
|
||||
// Clear file content if the error was sent or saved.
|
||||
// On android we can't know if it was sent or saved
|
||||
if (result.name == MailerResponse.sent.name ||
|
||||
result.name == MailerResponse.saved.name ||
|
||||
result.name == MailerResponse.android.name) {
|
||||
file.writeAsString("", mode: FileMode.write);
|
||||
}
|
||||
} catch (e, s) {
|
||||
_saveException(e.toString(), s);
|
||||
}
|
||||
}
|
||||
|
||||
void _onError(FlutterErrorDetails errorDetails) {
|
||||
_saveException(errorDetails.exception.toString(), errorDetails.stack);
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback(
|
||||
(timeStamp) {
|
||||
showPopUp<void>(
|
||||
context: navigatorKey.currentContext!,
|
||||
builder: (context) {
|
||||
return AlertWithTwoActions(
|
||||
isDividerExist: true,
|
||||
alertTitle: S.of(context).error,
|
||||
alertContent: S.of(context).error_dialog_content,
|
||||
rightButtonText: S.of(context).send,
|
||||
leftButtonText: S.of(context).do_not_send,
|
||||
actionRightButton: () {
|
||||
Navigator.of(context).pop();
|
||||
_sendExceptionFile();
|
||||
},
|
||||
actionLeftButton: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> initialSetup(
|
||||
{required SharedPreferences sharedPreferences,
|
||||
required Box<Node> nodes,
|
||||
|
|
|
@ -165,14 +165,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
|||
.color!
|
||||
)
|
||||
),
|
||||
child: QrImage(
|
||||
data: trade.inputAddress ?? fetchingLabel,
|
||||
backgroundColor: Colors.transparent,
|
||||
foregroundColor: Theme.of(context)
|
||||
.accentTextTheme!
|
||||
.subtitle2!
|
||||
.color!,
|
||||
),
|
||||
child: QrImage(data: trade.inputAddress ?? fetchingLabel),
|
||||
)))),
|
||||
Spacer(flex: 3)
|
||||
]),
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import 'package:cake_wallet/src/screens/receive/widgets/qr_image.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
|
||||
class FullscreenQRPage extends BasePage {
|
||||
|
@ -69,14 +68,10 @@ class FullscreenQRPage extends BasePage {
|
|||
child: AspectRatio(
|
||||
aspectRatio: 1.0,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(5),
|
||||
padding: EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(width: 3, color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!)),
|
||||
child: QrImage(
|
||||
data: qrData,
|
||||
backgroundColor: isLight ? Colors.transparent : Colors.black,
|
||||
foregroundColor: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!,
|
||||
),
|
||||
child: QrImage(data: qrData),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -1,30 +1,29 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:qr/qr.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/widgets/qr_painter.dart';
|
||||
import 'package:qr_flutter/qr_flutter.dart' as qr;
|
||||
|
||||
class QrImage extends StatelessWidget {
|
||||
QrImage({
|
||||
required String data,
|
||||
required this.data,
|
||||
this.size = 100.0,
|
||||
this.backgroundColor,
|
||||
Color foregroundColor = Colors.black,
|
||||
int version = 9, // Previous value: 7 something happened after flutter upgrade monero wallets addresses are longer than ver. 7 ???
|
||||
int errorCorrectionLevel = QrErrorCorrectLevel.L,
|
||||
}) : _painter = QrPainter(data, foregroundColor, version, errorCorrectionLevel);
|
||||
this.version = 9, // Previous value: 7 something happened after flutter upgrade monero wallets addresses are longer than ver. 7 ???
|
||||
this.errorCorrectionLevel = qr.QrErrorCorrectLevel.L,
|
||||
});
|
||||
|
||||
final QrPainter _painter;
|
||||
final Color? backgroundColor;
|
||||
final double size;
|
||||
final String data;
|
||||
final int version;
|
||||
final int errorCorrectionLevel;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: size,
|
||||
height: size,
|
||||
color: backgroundColor,
|
||||
child: CustomPaint(
|
||||
painter: _painter,
|
||||
),
|
||||
return qr.QrImage(
|
||||
data: data,
|
||||
errorCorrectionLevel: errorCorrectionLevel,
|
||||
version: version,
|
||||
size: size,
|
||||
foregroundColor: Colors.black,
|
||||
backgroundColor: Colors.white,
|
||||
padding: EdgeInsets.zero,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:qr/qr.dart';
|
||||
|
||||
class QrPainter extends CustomPainter {
|
||||
QrPainter(
|
||||
String data,
|
||||
this.color,
|
||||
this.version,
|
||||
this.errorCorrectionLevel,
|
||||
) : this._qr = QrCode(version, errorCorrectionLevel)..addData(data) {
|
||||
_p.color = this.color;
|
||||
_qrImage = QrImage(_qr);
|
||||
}
|
||||
|
||||
final int version;
|
||||
final int errorCorrectionLevel;
|
||||
final Color color;
|
||||
|
||||
final QrCode _qr;
|
||||
final _p = Paint()..style = PaintingStyle.fill;
|
||||
late QrImage _qrImage;
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final squareSize = size.shortestSide / _qr.moduleCount;
|
||||
for (int x = 0; x < _qr.moduleCount; x++) {
|
||||
for (int y = 0; y < _qr.moduleCount; y++) {
|
||||
if (_qrImage.isDark(y, x)) {
|
||||
final squareRect = Rect.fromLTWH(
|
||||
x * squareSize, y * squareSize, squareSize, squareSize);
|
||||
canvas.drawRect(squareRect, _p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(CustomPainter oldDelegate) {
|
||||
if (oldDelegate is QrPainter) {
|
||||
return this.color != oldDelegate.color ||
|
||||
this.errorCorrectionLevel != oldDelegate.errorCorrectionLevel ||
|
||||
this.version != oldDelegate.version;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -89,11 +89,7 @@ class QRWidget extends StatelessWidget {
|
|||
color: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!,
|
||||
),
|
||||
),
|
||||
child: QrImage(
|
||||
data: addressListViewModel.uri.toString(),
|
||||
backgroundColor: isLight ? Colors.transparent : Colors.black,
|
||||
foregroundColor: Theme.of(context).accentTextTheme!.headline2!.backgroundColor!,
|
||||
),
|
||||
child: QrImage(data: addressListViewModel.uri.toString()),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -19,13 +19,18 @@ Future<String> extractAddressFromParsed(
|
|||
address = parsedAddress.addresses.first;
|
||||
break;
|
||||
case ParseFrom.openAlias:
|
||||
title = S.of(context).openalias_alert_title;
|
||||
content = S.of(context).openalias_alert_content(parsedAddress.name);
|
||||
title = S.of(context).address_detected;
|
||||
content = S.of(context).openalias_alert_content('${parsedAddress.name} (OpenAlias)');
|
||||
address = parsedAddress.addresses.first;
|
||||
break;
|
||||
case ParseFrom.fio:
|
||||
title = S.of(context).address_detected;
|
||||
content = S.of(context).openalias_alert_content(parsedAddress.name);
|
||||
content = S.of(context).openalias_alert_content('${parsedAddress.name} (FIO)');
|
||||
address = parsedAddress.addresses.first;
|
||||
break;
|
||||
case ParseFrom.twitter:
|
||||
title = S.of(context).address_detected;
|
||||
content = S.of(context).openalias_alert_content('${parsedAddress.name} (Twitter)');
|
||||
address = parsedAddress.addresses.first;
|
||||
break;
|
||||
case ParseFrom.yatRecord:
|
||||
|
|
|
@ -17,8 +17,6 @@ class AddressEditOrCreatePage extends BasePage {
|
|||
_labelController.addListener(
|
||||
() => addressEditOrCreateViewModel.label = _labelController.text);
|
||||
_labelController.text = addressEditOrCreateViewModel.label;
|
||||
print(_labelController.text);
|
||||
print(addressEditOrCreateViewModel.label);
|
||||
}
|
||||
|
||||
final WalletAddressEditOrCreateViewModel addressEditOrCreateViewModel;
|
||||
|
|
37
lib/twitter/twitter_api.dart
Normal file
37
lib/twitter/twitter_api.dart
Normal file
|
@ -0,0 +1,37 @@
|
|||
import 'dart:convert';
|
||||
import 'package:cake_wallet/twitter/twitter_user.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
|
||||
class TwitterApi {
|
||||
static const twitterBearerToken = secrets.twitterBearerToken;
|
||||
static const httpsScheme = 'https';
|
||||
static const apiHost = 'api.twitter.com';
|
||||
static const userPath = '/2/users/by/username/';
|
||||
|
||||
static Future<TwitterUser> lookupUserByName({required String userName}) async {
|
||||
final queryParams = {'user.fields': 'description'};
|
||||
|
||||
final headers = {'authorization': 'Bearer $twitterBearerToken'};
|
||||
|
||||
final uri = Uri(
|
||||
scheme: httpsScheme,
|
||||
host: apiHost,
|
||||
path: userPath + userName,
|
||||
queryParameters: queryParams,
|
||||
);
|
||||
|
||||
var response = await http.get(uri, headers: headers);
|
||||
|
||||
if (response.statusCode != 200) {
|
||||
throw Exception('Unexpected http status: ${response.statusCode}');
|
||||
}
|
||||
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||
|
||||
if (responseJSON['errors'] != null) {
|
||||
throw Exception(responseJSON['errors'][0]['detail']);
|
||||
}
|
||||
|
||||
return TwitterUser.fromJson(responseJSON['data'] as Map<String, dynamic>);
|
||||
}
|
||||
}
|
16
lib/twitter/twitter_user.dart
Normal file
16
lib/twitter/twitter_user.dart
Normal file
|
@ -0,0 +1,16 @@
|
|||
class TwitterUser {
|
||||
TwitterUser({required this.id, required this.username, required this.name, this.description});
|
||||
|
||||
final String id;
|
||||
final String username;
|
||||
final String name;
|
||||
final String? description;
|
||||
|
||||
factory TwitterUser.fromJson(Map<String, dynamic> json) {
|
||||
return TwitterUser(
|
||||
id: json['id'] as String,
|
||||
username: json['username'] as String,
|
||||
name: json['name'] as String,
|
||||
description: json['description'] as String?);
|
||||
}
|
||||
}
|
104
lib/utils/exception_handler.dart
Normal file
104
lib/utils/exception_handler.dart
Normal file
|
@ -0,0 +1,104 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/main.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mailer/flutter_mailer.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
class ExceptionHandler {
|
||||
static bool _hasError = false;
|
||||
|
||||
static void _saveException(String? error, StackTrace? stackTrace) async {
|
||||
final appDocDir = await getApplicationDocumentsDirectory();
|
||||
|
||||
final file = File('${appDocDir.path}/error.txt');
|
||||
final exception = {
|
||||
"${DateTime.now()}": {
|
||||
"Error": error,
|
||||
"StackTrace": stackTrace.toString(),
|
||||
}
|
||||
};
|
||||
|
||||
const String separator = '''\n\n==========================================================
|
||||
==========================================================\n\n''';
|
||||
|
||||
await file.writeAsString(
|
||||
jsonEncode(exception) + separator,
|
||||
mode: FileMode.append,
|
||||
);
|
||||
}
|
||||
|
||||
static void _sendExceptionFile() async {
|
||||
try {
|
||||
final appDocDir = await getApplicationDocumentsDirectory();
|
||||
|
||||
final file = File('${appDocDir.path}/error.txt');
|
||||
|
||||
final MailOptions mailOptions = MailOptions(
|
||||
subject: 'Mobile App Issue',
|
||||
recipients: ['support@cakewallet.com'],
|
||||
attachments: [file.path],
|
||||
);
|
||||
|
||||
final result = await FlutterMailer.send(mailOptions);
|
||||
|
||||
// Clear file content if the error was sent or saved.
|
||||
// On android we can't know if it was sent or saved
|
||||
if (result.name == MailerResponse.sent.name ||
|
||||
result.name == MailerResponse.saved.name ||
|
||||
result.name == MailerResponse.android.name) {
|
||||
file.writeAsString("", mode: FileMode.write);
|
||||
}
|
||||
} catch (e, s) {
|
||||
_saveException(e.toString(), s);
|
||||
}
|
||||
}
|
||||
|
||||
static void onError(FlutterErrorDetails errorDetails) {
|
||||
if (_isErrorFromUser(errorDetails.exception.toString())) {
|
||||
return;
|
||||
}
|
||||
|
||||
_saveException(errorDetails.exception.toString(), errorDetails.stack);
|
||||
|
||||
if (_hasError) {
|
||||
return;
|
||||
}
|
||||
_hasError = true;
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback(
|
||||
(timeStamp) async {
|
||||
await showPopUp<void>(
|
||||
context: navigatorKey.currentContext!,
|
||||
builder: (context) {
|
||||
return AlertWithTwoActions(
|
||||
isDividerExist: true,
|
||||
alertTitle: S.of(context).error,
|
||||
alertContent: S.of(context).error_dialog_content,
|
||||
rightButtonText: S.of(context).send,
|
||||
leftButtonText: S.of(context).do_not_send,
|
||||
actionRightButton: () {
|
||||
Navigator.of(context).pop();
|
||||
_sendExceptionFile();
|
||||
},
|
||||
actionLeftButton: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
_hasError = false;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// User related errors to be added as exceptions here to not report
|
||||
static bool _isErrorFromUser(String error) {
|
||||
return error.contains("Software caused connection abort"); // User connection issue
|
||||
}
|
||||
}
|
|
@ -18,19 +18,18 @@ import 'package:cake_wallet/generated/i18n.dart';
|
|||
|
||||
part 'exchange_trade_view_model.g.dart';
|
||||
|
||||
class ExchangeTradeViewModel = ExchangeTradeViewModelBase
|
||||
with _$ExchangeTradeViewModel;
|
||||
class ExchangeTradeViewModel = ExchangeTradeViewModelBase with _$ExchangeTradeViewModel;
|
||||
|
||||
abstract class ExchangeTradeViewModelBase with Store {
|
||||
ExchangeTradeViewModelBase(
|
||||
{required this.wallet,
|
||||
required this.trades,
|
||||
required this.tradesStore,
|
||||
required this.sendViewModel})
|
||||
: trade = tradesStore.trade!,
|
||||
isSendable = tradesStore.trade!.from == wallet.currency ||
|
||||
tradesStore.trade!.provider == ExchangeProviderDescription.xmrto,
|
||||
items = ObservableList<ExchangeTradeItem>() {
|
||||
required this.trades,
|
||||
required this.tradesStore,
|
||||
required this.sendViewModel})
|
||||
: trade = tradesStore.trade!,
|
||||
isSendable = tradesStore.trade!.from == wallet.currency ||
|
||||
tradesStore.trade!.provider == ExchangeProviderDescription.xmrto,
|
||||
items = ObservableList<ExchangeTradeItem>() {
|
||||
switch (trade.provider) {
|
||||
case ExchangeProviderDescription.xmrto:
|
||||
_provider = XMRTOExchangeProvider();
|
||||
|
@ -67,22 +66,20 @@ abstract class ExchangeTradeViewModelBase with Store {
|
|||
|
||||
@computed
|
||||
String get extraInfo => trade.from == CryptoCurrency.xlm
|
||||
? '\n\n' + S.current.xlm_extra_info
|
||||
: trade.from == CryptoCurrency.xrp
|
||||
? '\n\n' + S.current.xrp_extra_info
|
||||
: '';
|
||||
? '\n\n' + S.current.xlm_extra_info
|
||||
: trade.from == CryptoCurrency.xrp
|
||||
? '\n\n' + S.current.xrp_extra_info
|
||||
: '';
|
||||
|
||||
@computed
|
||||
String get pendingTransactionFiatAmountValueFormatted =>
|
||||
sendViewModel.isFiatDisabled
|
||||
? '' : sendViewModel.pendingTransactionFiatAmount
|
||||
+ ' ' + sendViewModel.fiat.title;
|
||||
String get pendingTransactionFiatAmountValueFormatted => sendViewModel.isFiatDisabled
|
||||
? ''
|
||||
: sendViewModel.pendingTransactionFiatAmount + ' ' + sendViewModel.fiat.title;
|
||||
|
||||
@computed
|
||||
String get pendingTransactionFeeFiatAmountFormatted =>
|
||||
sendViewModel.isFiatDisabled
|
||||
? '' : sendViewModel.pendingTransactionFeeFiatAmount
|
||||
+ ' ' + sendViewModel.fiat.title;
|
||||
String get pendingTransactionFeeFiatAmountFormatted => sendViewModel.isFiatDisabled
|
||||
? ''
|
||||
: sendViewModel.pendingTransactionFeeFiatAmount + ' ' + sendViewModel.fiat.title;
|
||||
|
||||
@observable
|
||||
ObservableList<ExchangeTradeItem> items;
|
||||
|
@ -122,6 +119,8 @@ abstract class ExchangeTradeViewModelBase with Store {
|
|||
}
|
||||
|
||||
void _updateItems() {
|
||||
final tagFrom = trade.from.tag != null ? '${trade.from.tag}' + ' ' : '';
|
||||
final tagTo = trade.to.tag != null ? '${trade.to.tag}' + ' ' : '';
|
||||
items.clear();
|
||||
items.add(ExchangeTradeItem(
|
||||
title: "${trade.provider.title} ${S.current.id}", data: '${trade.id}', isCopied: true));
|
||||
|
@ -130,22 +129,22 @@ abstract class ExchangeTradeViewModelBase with Store {
|
|||
final title = trade.from == CryptoCurrency.xrp
|
||||
? S.current.destination_tag
|
||||
: trade.from == CryptoCurrency.xlm
|
||||
? S.current.memo
|
||||
: S.current.extra_id;
|
||||
? S.current.memo
|
||||
: S.current.extra_id;
|
||||
|
||||
items.add(ExchangeTradeItem(
|
||||
title: title, data: '${trade.extraId}', isCopied: false));
|
||||
items.add(ExchangeTradeItem(title: title, data: '${trade.extraId}', isCopied: false));
|
||||
}
|
||||
|
||||
items.addAll([
|
||||
ExchangeTradeItem(title: S.current.amount, data: '${trade.amount}', isCopied: false),
|
||||
ExchangeTradeItem(
|
||||
title: S.current.amount, data: '${trade.amount}', isCopied: false),
|
||||
ExchangeTradeItem(
|
||||
title: S.current.status, data: '${trade.state}', isCopied: false),
|
||||
ExchangeTradeItem(
|
||||
title: S.current.widgets_address + ':',
|
||||
title: S.current.send_to_this_address('${trade.from}', tagFrom) + ':',
|
||||
data: trade.inputAddress ?? '',
|
||||
isCopied: true),
|
||||
ExchangeTradeItem(
|
||||
title: S.current.arrive_in_this_address('${trade.to}', tagTo) + ':',
|
||||
data: trade.payoutAddress ?? '',
|
||||
isCopied: true),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -180,7 +180,8 @@ abstract class SendViewModelBase with Store {
|
|||
|
||||
WalletType get walletType => _wallet.type;
|
||||
|
||||
String? get walletCurrencyName => _wallet.currency.name?.toLowerCase();
|
||||
String? get walletCurrencyName =>
|
||||
_wallet.currency.fullName?.toLowerCase() ?? _wallet.currency.name;
|
||||
|
||||
bool get hasCurrecyChanger => walletType == WalletType.haven;
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
|
@ -27,10 +28,10 @@ class AddressEditOrCreateStateFailure extends AddressEditOrCreateState {
|
|||
|
||||
abstract class WalletAddressEditOrCreateViewModelBase with Store {
|
||||
WalletAddressEditOrCreateViewModelBase(
|
||||
{required WalletBase wallet, dynamic item})
|
||||
{required WalletBase wallet, WalletAddressListItem? item})
|
||||
: isEdit = item != null,
|
||||
state = AddressEditOrCreateStateInitial(),
|
||||
label = item?.fullName as String? ?? '',
|
||||
label = item?.name ?? '',
|
||||
_item = item,
|
||||
_wallet = wallet;
|
||||
|
||||
|
@ -42,7 +43,7 @@ abstract class WalletAddressEditOrCreateViewModelBase with Store {
|
|||
|
||||
bool isEdit;
|
||||
|
||||
final dynamic _item;
|
||||
final WalletAddressListItem? _item;
|
||||
final WalletBase _wallet;
|
||||
|
||||
Future<void> save() async {
|
||||
|
@ -98,27 +99,20 @@ abstract class WalletAddressEditOrCreateViewModelBase with Store {
|
|||
await wallet.walletAddresses.updateAddress(_item.address as String);
|
||||
await wallet.save();
|
||||
}*/
|
||||
|
||||
if (wallet.type == WalletType.monero) {
|
||||
await monero
|
||||
!.getSubaddressList(wallet)
|
||||
.setLabelSubaddress(
|
||||
wallet,
|
||||
accountIndex: monero!.getCurrentAccount(wallet).id,
|
||||
addressIndex: _item.id as int,
|
||||
label: label);
|
||||
await wallet.save();
|
||||
}
|
||||
|
||||
if (wallet.type == WalletType.haven) {
|
||||
await haven
|
||||
!.getSubaddressList(wallet)
|
||||
.setLabelSubaddress(
|
||||
wallet,
|
||||
accountIndex: haven!.getCurrentAccount(wallet).id,
|
||||
addressIndex: _item.id as int,
|
||||
label: label);
|
||||
await wallet.save();
|
||||
final index = _item?.id;
|
||||
if (index != null) {
|
||||
if (wallet.type == WalletType.monero) {
|
||||
await monero!.getSubaddressList(wallet).setLabelSubaddress(wallet,
|
||||
accountIndex: monero!.getCurrentAccount(wallet).id, addressIndex: index, label: label);
|
||||
await wallet.save();
|
||||
}
|
||||
if (wallet.type == WalletType.haven) {
|
||||
await haven!.getSubaddressList(wallet).setLabelSubaddress(wallet,
|
||||
accountIndex: haven!.getCurrentAccount(wallet).id,
|
||||
addressIndex: index,
|
||||
label: label);
|
||||
await wallet.save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ dependencies:
|
|||
flutter_cupertino_localizations: ^1.0.1
|
||||
intl: ^0.17.0
|
||||
url_launcher: ^6.1.4
|
||||
qr: ^3.0.1
|
||||
qr_flutter: ^4.0.0
|
||||
uuid: 3.0.6
|
||||
shared_preferences: ^2.0.15
|
||||
flutter_secure_storage:
|
||||
|
|
|
@ -398,8 +398,7 @@
|
|||
"biometric_auth_reason":"امسح بصمة إصبعك للمصادقة",
|
||||
"version":"الإصدار ${currentVersion}",
|
||||
|
||||
"openalias_alert_title":"تم ايجاد العنوان",
|
||||
"openalias_alert_content":"سوف ترسل الأموال إلى\n${recipient_name}",
|
||||
"extracted_address_content":"سوف ترسل الأموال إلى\n${recipient_name}",
|
||||
|
||||
"card_address":"العنوان:",
|
||||
"buy":"اشتري",
|
||||
|
@ -679,5 +678,9 @@
|
|||
"tor_only":"Tor فقط",
|
||||
"unmatched_currencies": "عملة محفظتك الحالية لا تتطابق مع عملة QR الممسوحة ضوئيًا",
|
||||
"orbot_running_alert": "يرجى التأكد من تشغيل Orbot قبل الاتصال بهذه العقدة.",
|
||||
"bitcoin_payments_require_1_confirmation": "تتطلب مدفوعات Bitcoin تأكيدًا واحدًا ، والذي قد يستغرق 20 دقيقة أو أكثر. شكرا لصبرك! سيتم إرسال بريد إلكتروني إليك عند تأكيد الدفع."
|
||||
"bitcoin_payments_require_1_confirmation": "تتطلب مدفوعات Bitcoin تأكيدًا واحدًا ، والذي قد يستغرق 20 دقيقة أو أكثر. شكرا لصبرك! سيتم إرسال بريد إلكتروني إليك عند تأكيد الدفع.",
|
||||
"send_to_this_address" : "أرسل ${currency} ${tag}إلى هذا العنوان",
|
||||
"arrive_in_this_address" : "سيصل ${currency} ${tag}إلى هذا العنوان",
|
||||
"do_not_send": "لا ترسل",
|
||||
"error_dialog_content": "عفوًا ، لقد حصلنا على بعض الخطأ.\n\nيرجى إرسال تقرير التعطل إلى فريق الدعم لدينا لتحسين التطبيق."
|
||||
}
|
||||
|
|
|
@ -398,8 +398,7 @@
|
|||
"biometric_auth_reason" : "Scannen Sie Ihren Fingerabdruck zur Authentifizierung",
|
||||
"version" : "Version ${currentVersion}",
|
||||
|
||||
"openalias_alert_title" : "Adresse Erkannt",
|
||||
"openalias_alert_content" : "Sie senden Geld an\n${recipient_name}",
|
||||
"extracted_address_content" : "Sie senden Geld an\n${recipient_name}",
|
||||
|
||||
"card_address" : "Adresse:",
|
||||
"buy" : "Kaufen",
|
||||
|
@ -682,6 +681,8 @@
|
|||
"contact_list_contacts": "Kontakte",
|
||||
"contact_list_wallets": "Meine Geldbörsen",
|
||||
"bitcoin_payments_require_1_confirmation": "Bitcoin-Zahlungen erfordern 1 Bestätigung, was 20 Minuten oder länger dauern kann. Danke für Ihre Geduld! Sie erhalten eine E-Mail, wenn die Zahlung bestätigt ist.",
|
||||
"send_to_this_address" : "Senden Sie ${currency} ${tag}an diese Adresse",
|
||||
"arrive_in_this_address" : "${currency} ${tag}wird an dieser Adresse ankommen",
|
||||
"do_not_send": "Nicht senden",
|
||||
"error_dialog_content": "Hoppla, wir haben einen Fehler.\n\nBitte senden Sie den Absturzbericht an unser Support-Team, um die Anwendung zu verbessern."
|
||||
}
|
||||
|
|
|
@ -398,8 +398,7 @@
|
|||
"biometric_auth_reason" : "Scan your fingerprint to authenticate",
|
||||
"version" : "Version ${currentVersion}",
|
||||
|
||||
"openalias_alert_title" : "Address Detected",
|
||||
"openalias_alert_content" : "You will be sending funds to\n${recipient_name}",
|
||||
"extracted_address_content" : "You will be sending funds to\n${recipient_name}",
|
||||
|
||||
"card_address" : "Address:",
|
||||
"buy" : "Buy",
|
||||
|
@ -682,6 +681,8 @@
|
|||
"contact_list_contacts": "Contacts",
|
||||
"contact_list_wallets": "My Wallets",
|
||||
"bitcoin_payments_require_1_confirmation": "Bitcoin payments require 1 confirmation, which can take 20 minutes or longer. Thanks for your patience! You will be emailed when the payment is confirmed.",
|
||||
"send_to_this_address" : "Send ${currency} ${tag}to this address",
|
||||
"arrive_in_this_address" : "${currency} ${tag}will arrive in this address",
|
||||
"do_not_send": "Don't send",
|
||||
"error_dialog_content": "Oops, we got some error.\n\nPlease send the crash report to our support team to make the application better."
|
||||
}
|
||||
|
|
|
@ -398,8 +398,7 @@
|
|||
"biometric_auth_reason" : "Escanee su huella digital para autenticar",
|
||||
"version" : "Versión ${currentVersion}",
|
||||
|
||||
"openalias_alert_title" : "Destinatario detectado",
|
||||
"openalias_alert_content" : "Enviará fondos a\n${recipient_name}",
|
||||
"extracted_address_content" : "Enviará fondos a\n${recipient_name}",
|
||||
|
||||
"card_address" : "Dirección:",
|
||||
"buy" : "Comprar",
|
||||
|
@ -682,6 +681,8 @@
|
|||
"contact_list_contacts": "Contactos",
|
||||
"contact_list_wallets": "Mis billeteras",
|
||||
"bitcoin_payments_require_1_confirmation": "Los pagos de Bitcoin requieren 1 confirmación, que puede demorar 20 minutos o más. ¡Gracias por su paciencia! Se le enviará un correo electrónico cuando se confirme el pago.",
|
||||
"send_to_this_address" : "Enviar ${currency} ${tag}a esta dirección",
|
||||
"arrive_in_this_address" : "${currency} ${tag}llegará a esta dirección",
|
||||
"do_not_send": "no enviar",
|
||||
"error_dialog_content": "Vaya, tenemos un error.\n\nEnvíe el informe de bloqueo a nuestro equipo de soporte para mejorar la aplicación."
|
||||
}
|
||||
|
|
|
@ -396,8 +396,7 @@
|
|||
"biometric_auth_reason" : "Scannez votre empreinte digitale pour vous authentifier",
|
||||
"version" : "Version ${currentVersion}",
|
||||
|
||||
"openalias_alert_title" : "Adresse Détectée",
|
||||
"openalias_alert_content" : "Vous allez envoyer des fonds à\n${recipient_name}",
|
||||
"extracted_address_content" : "Vous allez envoyer des fonds à\n${recipient_name}",
|
||||
|
||||
"card_address" : "Adresse :",
|
||||
"buy" : "Acheter",
|
||||
|
@ -675,11 +674,13 @@
|
|||
"disabled": "Désactivé",
|
||||
"enabled": "Activé",
|
||||
"tor_only": "Tor uniquement",
|
||||
"orbot_running_alert": "Veuillez vous assurer qu'Orbot est en cours d'exécution avant de vous connecter à ce nœud.",
|
||||
"unmatched_currencies": "La devise de votre portefeuille (wallet) actuel ne correspond pas à celle du QR code scanné",
|
||||
"orbot_running_alert": "Veuillez vous assurer qu'Orbot est en cours d'exécution avant de vous connecter à ce nœud.",
|
||||
"contact_list_contacts": "Contacts",
|
||||
"contact_list_wallets": "Mes portefeuilles (wallets)",
|
||||
"bitcoin_payments_require_1_confirmation": "Les paiements Bitcoin nécessitent 1 confirmation, ce qui peut prendre 20 minutes ou plus. Merci pour votre patience! Vous serez averti par e-mail lorsque le paiement sera confirmé.",
|
||||
"send_to_this_address" : "Envoyez ${currency} ${tag}à cette adresse",
|
||||
"arrive_in_this_address" : "${currency} ${tag}arrivera à cette adresse",
|
||||
"do_not_send": "N'envoyez pas",
|
||||
"error_dialog_content": "Oups, nous avons eu une erreur.\n\nVeuillez envoyer le rapport de plantage à notre équipe d'assistance pour améliorer l'application."
|
||||
}
|
||||
|
|
|
@ -398,8 +398,7 @@
|
|||
"biometric_auth_reason" : "प्रमाणित करने के लिए अपने फ़िंगरप्रिंट को स्कैन करें",
|
||||
"version" : "संस्करण ${currentVersion}",
|
||||
|
||||
"openalias_alert_title" : "पता मिला",
|
||||
"openalias_alert_content" : "आपको धनराशि भेजी जाएगी\n${recipient_name}",
|
||||
"extracted_address_content" : "आपको धनराशि भेजी जाएगी\n${recipient_name}",
|
||||
|
||||
"card_address" : "पता:",
|
||||
"buy" : "खरीदें",
|
||||
|
@ -677,11 +676,13 @@
|
|||
"disabled": "अक्षम",
|
||||
"enabled": "सक्रिय",
|
||||
"tor_only": "Tor केवल",
|
||||
"orbot_running_alert": "कृपया सुनिश्चित करें कि इस नोड से कनेक्ट करने से पहले Orbot चल रहा है।",
|
||||
"unmatched_currencies": "आपके वर्तमान वॉलेट की मुद्रा स्कैन किए गए क्यूआर से मेल नहीं खाती" ,
|
||||
"orbot_running_alert": "कृपया सुनिश्चित करें कि इस नोड से कनेक्ट करने से पहले Orbot चल रहा है।",
|
||||
"contact_list_contacts": "संपर्क",
|
||||
"contact_list_wallets": "मेरा बटुआ",
|
||||
"bitcoin_payments_require_1_confirmation": "बिटकॉइन भुगतान के लिए 1 पुष्टिकरण की आवश्यकता होती है, जिसमें 20 मिनट या अधिक समय लग सकता है। आपके धैर्य के लिए धन्यवाद! भुगतान की पुष्टि होने पर आपको ईमेल किया जाएगा।",
|
||||
"send_to_this_address" : "इस पते पर ${currency} ${tag}भेजें",
|
||||
"arrive_in_this_address" : "${currency} ${tag}इस पते पर पहुंचेंगे",
|
||||
"do_not_send": "मत भेजो",
|
||||
"error_dialog_content": "ओह, हमसे कुछ गड़बड़ी हुई है.\n\nएप्लिकेशन को बेहतर बनाने के लिए कृपया क्रैश रिपोर्ट हमारी सहायता टीम को भेजें।"
|
||||
}
|
||||
|
|
|
@ -398,8 +398,7 @@
|
|||
"biometric_auth_reason" : "Skenirajte svoj otisak prsta za autentifikaciju",
|
||||
"version" : "Verzija ${currentVersion}",
|
||||
|
||||
"openalias_alert_title" : "Otkrivena je adresa",
|
||||
"openalias_alert_content" : "Poslat ćete sredstva primatelju\n${recipient_name}",
|
||||
"extracted_address_content" : "Poslat ćete sredstva primatelju\n${recipient_name}",
|
||||
|
||||
"card_address" : "Adresa:",
|
||||
"buy" : "Kupi",
|
||||
|
@ -682,6 +681,8 @@
|
|||
"contact_list_contacts": "Kontakti",
|
||||
"contact_list_wallets": "Moji novčanici",
|
||||
"bitcoin_payments_require_1_confirmation": "Bitcoin plaćanja zahtijevaju 1 potvrdu, što može potrajati 20 minuta ili dulje. Hvala na Vašem strpljenju! Dobit ćete e-poruku kada plaćanje bude potvrđeno.",
|
||||
"send_to_this_address" : "Pošaljite ${currency} ${tag}na ovu adresu",
|
||||
"arrive_in_this_address" : "${currency} ${tag}će stići na ovu adresu",
|
||||
"do_not_send": "Ne šalji",
|
||||
"error_dialog_content": "Ups, imamo grešku.\n\nPošaljite izvješće o padu našem timu za podršku kako bismo poboljšali aplikaciju."
|
||||
}
|
||||
|
|
|
@ -398,8 +398,7 @@
|
|||
"biometric_auth_reason" : "Scansiona la tua impronta per autenticarti",
|
||||
"version" : "Versione ${currentVersion}",
|
||||
|
||||
"openalias_alert_title" : "Indirizzo Rilevato",
|
||||
"openalias_alert_content" : "Invierai i tuoi fondi a\n${recipient_name}",
|
||||
"extracted_address_content" : "Invierai i tuoi fondi a\n${recipient_name}",
|
||||
|
||||
"card_address" : "Indirizzo:",
|
||||
"buy" : "Comprare",
|
||||
|
@ -682,6 +681,8 @@
|
|||
"contact_list_contacts": "Contatti",
|
||||
"contact_list_wallets": "I miei portafogli",
|
||||
"bitcoin_payments_require_1_confirmation": "I pagamenti in bitcoin richiedono 1 conferma, che può richiedere 20 minuti o più. Grazie per la vostra pazienza! Riceverai un'e-mail quando il pagamento sarà confermato.",
|
||||
"send_to_this_address" : "Invia ${currency} ${tag}a questo indirizzo",
|
||||
"arrive_in_this_address" : "${currency} ${tag}arriverà a questo indirizzo",
|
||||
"do_not_send": "Non inviare",
|
||||
"error_dialog_content": "Ups, imamo grešku.\n\nPošaljite izvješće o padu našem timu za podršku kako bismo poboljšali aplikaciju."
|
||||
}
|
||||
|
|
|
@ -398,8 +398,7 @@
|
|||
"biometric_auth_reason" : "प指紋をスキャンして認証する",
|
||||
"version" : "バージョン ${currentVersion}",
|
||||
|
||||
"openalias_alert_title" : "アドレスが検出されました",
|
||||
"openalias_alert_content" : "に送金します\n${recipient_name}",
|
||||
"extracted_address_content" : "に送金します\n${recipient_name}",
|
||||
|
||||
"card_address" : "住所:",
|
||||
"buy" : "購入",
|
||||
|
@ -682,6 +681,8 @@
|
|||
"contact_list_contacts": "連絡先",
|
||||
"contact_list_wallets": "マイウォレット",
|
||||
"bitcoin_payments_require_1_confirmation": "ビットコインの支払いには 1 回の確認が必要で、これには 20 分以上かかる場合があります。お待ち頂きまして、ありがとうございます!支払いが確認されると、メールが送信されます。",
|
||||
"send_to_this_address" : "${currency} ${tag}をこのアドレスに送金",
|
||||
"arrive_in_this_address" : "${currency} ${tag}はこの住所に到着します",
|
||||
"do_not_send": "送信しない",
|
||||
"error_dialog_content": "Spiacenti, abbiamo riscontrato un errore.\n\nSi prega di inviare il rapporto sull'arresto anomalo al nostro team di supporto per migliorare l'applicazione."
|
||||
}
|
||||
|
|
|
@ -398,8 +398,7 @@
|
|||
"biometric_auth_reason" : "지문을 스캔하여 인증",
|
||||
"version" : "버전 ${currentVersion}",
|
||||
|
||||
"openalias_alert_title" : "주소 감지됨",
|
||||
"openalias_alert_content" : "당신은에 자금을 보낼 것입니다\n${recipient_name}",
|
||||
"extracted_address_content" : "당신은에 자금을 보낼 것입니다\n${recipient_name}",
|
||||
|
||||
"card_address" : "주소:",
|
||||
"buy" : "구입",
|
||||
|
@ -682,6 +681,8 @@
|
|||
"contact_list_contacts": "콘택트 렌즈",
|
||||
"contact_list_wallets": "내 지갑",
|
||||
"bitcoin_payments_require_1_confirmation": "비트코인 결제는 1번의 확인이 필요하며 20분 이상이 소요될 수 있습니다. 기다려 주셔서 감사합니다! 결제가 확인되면 이메일이 전송됩니다.",
|
||||
"send_to_this_address" : "이 주소로 ${currency} ${tag}송금",
|
||||
"arrive_in_this_address" : "${currency} ${tag}이(가) 이 주소로 도착합니다",
|
||||
"do_not_send": "보내지 마세요",
|
||||
"error_dialog_content": "죄송합니다. 오류가 발생했습니다.\n\n응용 프로그램을 개선하려면 지원 팀에 충돌 보고서를 보내주십시오."
|
||||
}
|
||||
|
|
|
@ -398,8 +398,7 @@
|
|||
"biometric_auth_reason" : "စစ်မှန်ကြောင်းအထောက်အထားပြရန် သင့်လက်ဗွေကို စကန်ဖတ်ပါ။",
|
||||
"version" : "ဗားရှင်း ${currentVersion}",
|
||||
|
||||
"openalias_alert_title" : "လိပ်စာကို ရှာတွေ့သည်။",
|
||||
"openalias_alert_content" : "သင်သည် \n${recipient_name} သို့ ရန်ပုံငွေများ ပေးပို့ပါမည်",
|
||||
"extracted_address_content" : "သင်သည် \n${recipient_name} သို့ ရန်ပုံငွေများ ပေးပို့ပါမည်",
|
||||
|
||||
"card_address" : "လိပ်စာ-",
|
||||
"buy" : "ဝယ်ပါ။",
|
||||
|
@ -678,7 +677,12 @@
|
|||
"enabled" : "ဖွင့်ထားသည်။",
|
||||
"tor_only" : "Tor သာ",
|
||||
"unmatched_currencies" : "သင့်လက်ရှိပိုက်ဆံအိတ်၏ငွေကြေးသည် စကင်ဖတ်ထားသော QR နှင့် မကိုက်ညီပါ။",
|
||||
"orbot_running_alert": "ဤ node သို့မချိတ်ဆက်မီ Orbot အလုပ်လုပ်နေကြောင်း သေချာပါစေ။",
|
||||
"contact_list_contacts" : "အဆက်အသွယ်များ",
|
||||
"contact_list_wallets" : "ကျွန်ုပ်၏ ပိုက်ဆံအိတ်များ",
|
||||
"bitcoin_payments_require_1_confirmation": "Bitcoin ငွေပေးချေမှုများသည် မိနစ် 20 သို့မဟုတ် ထို့ထက်ပိုကြာနိုင်သည် 1 အတည်ပြုချက် လိုအပ်သည်။ မင်းရဲ့စိတ်ရှည်မှုအတွက် ကျေးဇူးတင်ပါတယ်။ ငွေပေးချေမှုကို အတည်ပြုပြီးသောအခါ သင့်ထံ အီးမေးလ်ပို့ပါမည်။"
|
||||
"bitcoin_payments_require_1_confirmation": "Bitcoin ငွေပေးချေမှုများသည် မိနစ် 20 သို့မဟုတ် ထို့ထက်ပိုကြာနိုင်သည် 1 အတည်ပြုချက် လိုအပ်သည်။ မင်းရဲ့စိတ်ရှည်မှုအတွက် ကျေးဇူးတင်ပါတယ်။ ငွေပေးချေမှုကို အတည်ပြုပြီးသောအခါ သင့်ထံ အီးမေးလ်ပို့ပါမည်။",
|
||||
"send_to_this_address" : "ဤလိပ်စာသို့ ${currency} ${tag}သို့ ပို့ပါ။",
|
||||
"arrive_in_this_address" : "${currency} ${tag}ဤလိပ်စာသို့ ရောက်ရှိပါမည်။",
|
||||
"do_not_send": "မပို့ပါနှင့်",
|
||||
"error_dialog_content": "အိုး၊ ကျွန်ုပ်တို့တွင် အမှားအယွင်းအချို့ရှိသည်။\n\nအပလီကေးရှင်းကို ပိုမိုကောင်းမွန်စေရန်အတွက် ပျက်စီးမှုအစီရင်ခံစာကို ကျွန်ုပ်တို့၏ပံ့ပိုးကူညီရေးအဖွဲ့ထံ ပေးပို့ပါ။"
|
||||
}
|
||||
|
|
|
@ -398,8 +398,7 @@
|
|||
"biometric_auth_reason" : "Scan uw vingerafdruk om te verifiëren",
|
||||
"version" : "Versie ${currentVersion}",
|
||||
|
||||
"openalias_alert_title" : "Adres Gedetecteerd",
|
||||
"openalias_alert_content" : "U stuurt geld naar\n${recipient_name}",
|
||||
"extracted_address_content" : "U stuurt geld naar\n${recipient_name}",
|
||||
|
||||
"card_address" : "Adres:",
|
||||
"buy" : "Kopen",
|
||||
|
@ -682,6 +681,8 @@
|
|||
"contact_list_contacts": "Contacten",
|
||||
"contact_list_wallets": "Mijn portefeuilles",
|
||||
"bitcoin_payments_require_1_confirmation": "Bitcoin-betalingen vereisen 1 bevestiging, wat 20 minuten of langer kan duren. Dank voor uw geduld! U ontvangt een e-mail wanneer de betaling is bevestigd.",
|
||||
"send_to_this_address" : "Stuur ${currency} ${tag}naar dit adres",
|
||||
"arrive_in_this_address" : "${currency} ${tag}komt aan op dit adres",
|
||||
"do_not_send": "Niet sturen",
|
||||
"error_dialog_content": "Oeps, er is een fout opgetreden.\n\nStuur het crashrapport naar ons ondersteuningsteam om de applicatie te verbeteren."
|
||||
}
|
||||
|
|
|
@ -398,8 +398,7 @@
|
|||
"biometric_auth_reason" : "Zeskanuj swój odcisk palca, aby uwierzytelnić",
|
||||
"version" : "Wersja ${currentVersion}",
|
||||
|
||||
"openalias_alert_title" : "Wykryto Adres",
|
||||
"openalias_alert_content" : "Wysyłasz środki na\n${recipient_name}",
|
||||
"extracted_address_content" : "Wysyłasz środki na\n${recipient_name}",
|
||||
|
||||
"card_address" : "Adres:",
|
||||
"buy" : "Kup",
|
||||
|
@ -675,13 +674,15 @@
|
|||
"disable_fiat": "Wyłącz waluty FIAT",
|
||||
"fiat_api": "API Walut FIAT",
|
||||
"disabled": "Wyłączone",
|
||||
"orbot_running_alert": "Upewnij się, że Orbot działa przed połączeniem z tym węzłem.",
|
||||
"enabled": "Włączone",
|
||||
"tor_only": "Tylko sieć Tor",
|
||||
"unmatched_currencies": "Waluta Twojego obecnego portfela nie zgadza się z waluctą zeskanowanego kodu QR",
|
||||
"orbot_running_alert": "Upewnij się, że Orbot działa przed połączeniem z tym węzłem.",
|
||||
"contact_list_contacts": "Łączność",
|
||||
"contact_list_wallets": "Moje portfele",
|
||||
"bitcoin_payments_require_1_confirmation": "Płatności Bitcoin wymagają 1 potwierdzenia, co może zająć 20 minut lub dłużej. Dziękuję za cierpliwość! Otrzymasz wiadomość e-mail, gdy płatność zostanie potwierdzona.",
|
||||
"send_to_this_address" : "Wyślij ${currency} ${tag}na ten adres",
|
||||
"arrive_in_this_address" : "${currency} ${tag}dotrze na ten adres",
|
||||
"do_not_send": "Nie wysyłaj",
|
||||
"error_dialog_content": "Ups, wystąpił błąd.\n\nPrześlij raport o awarii do naszego zespołu wsparcia, aby ulepszyć aplikację."
|
||||
}
|
||||
|
|
|
@ -398,8 +398,7 @@
|
|||
"biometric_auth_reason" : "Digitalize sua impressão digital para autenticar",
|
||||
"version" : "Versão ${currentVersion}",
|
||||
|
||||
"openalias_alert_title" : "Endereço Detectado",
|
||||
"openalias_alert_content" : "Você enviará fundos para\n${recipient_name}",
|
||||
"extracted_address_content" : "Você enviará fundos para\n${recipient_name}",
|
||||
|
||||
"card_address" : "Endereço:",
|
||||
"buy" : "Comprar",
|
||||
|
@ -681,6 +680,8 @@
|
|||
"contact_list_contacts": "Contatos",
|
||||
"contact_list_wallets": "minhas carteiras",
|
||||
"bitcoin_payments_require_1_confirmation": "Os pagamentos em Bitcoin exigem 1 confirmação, o que pode levar 20 minutos ou mais. Obrigado pela sua paciência! Você receberá um e-mail quando o pagamento for confirmado.",
|
||||
"send_to_this_address" : "Envie ${currency} ${tag}para este endereço",
|
||||
"arrive_in_this_address" : "${currency} ${tag}chegará neste endereço",
|
||||
"do_not_send": "não envie",
|
||||
"error_dialog_content": "Ops, houve algum erro.\n\nPor favor, envie o relatório de falha para nossa equipe de suporte para melhorar o aplicativo."
|
||||
}
|
||||
|
|
|
@ -398,8 +398,7 @@
|
|||
"biometric_auth_reason" : "Отсканируйте свой отпечаток пальца для аутентификации",
|
||||
"version" : "Версия ${currentVersion}",
|
||||
|
||||
"openalias_alert_title" : "Адрес Обнаружен",
|
||||
"openalias_alert_content" : "Вы будете отправлять средства\n${recipient_name}",
|
||||
"extracted_address_content" : "Вы будете отправлять средства\n${recipient_name}",
|
||||
|
||||
"card_address" : "Адрес:",
|
||||
"buy" : "Купить",
|
||||
|
@ -682,6 +681,8 @@
|
|||
"contact_list_contacts": "Контакты",
|
||||
"contact_list_wallets": "Мои кошельки",
|
||||
"bitcoin_payments_require_1_confirmation": "Биткойн-платежи требуют 1 подтверждения, что может занять 20 минут или дольше. Спасибо тебе за твое терпение! Вы получите электронное письмо, когда платеж будет подтвержден.",
|
||||
"send_to_this_address" : "Отправить ${currency} ${tag}на этот адрес",
|
||||
"arrive_in_this_address" : "${currency} ${tag}придет на этот адрес",
|
||||
"do_not_send": "Не отправлять",
|
||||
"error_dialog_content": "Ой, у нас какая-то ошибка.\n\nПожалуйста, отправьте отчет о сбое в нашу службу поддержки, чтобы сделать приложение лучше."
|
||||
}
|
||||
|
|
|
@ -396,8 +396,7 @@
|
|||
"biometric_auth_reason" : "สแกนลายนิ้วมือของคุณเพื่อยืนยันตัวตน",
|
||||
"version" : "เวอร์ชัน ${currentVersion}",
|
||||
|
||||
"openalias_alert_title" : "พบที่อยู่",
|
||||
"openalias_alert_content" : "คุณกำลังจะส่งเงินไปยัง\n${recipient_name}",
|
||||
"extracted_address_content" : "คุณกำลังจะส่งเงินไปยัง\n${recipient_name}",
|
||||
|
||||
"card_address" : "ที่อยู่:",
|
||||
"buy" : "ซื้อ",
|
||||
|
@ -680,6 +679,8 @@
|
|||
"contact_list_contacts": "ติดต่อ",
|
||||
"contact_list_wallets": "กระเป๋าเงินของฉัน",
|
||||
"bitcoin_payments_require_1_confirmation": "การชำระเงินด้วย Bitcoin ต้องการการยืนยัน 1 ครั้ง ซึ่งอาจใช้เวลา 20 นาทีหรือนานกว่านั้น ขอบคุณสำหรับความอดทนของคุณ! คุณจะได้รับอีเมลเมื่อการชำระเงินได้รับการยืนยัน",
|
||||
"send_to_this_address" : "ส่ง ${currency} ${tag}ไปยังที่อยู่นี้",
|
||||
"arrive_in_this_address" : "${currency} ${tag}จะมาถึงที่อยู่นี้",
|
||||
"do_not_send": "อย่าส่ง",
|
||||
"error_dialog_content": "อ๊ะ เราพบข้อผิดพลาดบางอย่าง\n\nโปรดส่งรายงานข้อขัดข้องไปยังทีมสนับสนุนของเราเพื่อปรับปรุงแอปพลิเคชันให้ดียิ่งขึ้น"
|
||||
}
|
||||
|
|
|
@ -398,8 +398,7 @@
|
|||
"biometric_auth_reason" : "Kimlik doğrulaması için parmak izini okutun",
|
||||
"version" : "Sürüm ${currentVersion}",
|
||||
|
||||
"openalias_alert_title" : "Adres tespit edildi",
|
||||
"openalias_alert_content" : "Parayı buraya gönderceksin:\n${recipient_name}",
|
||||
"extracted_address_content" : "Parayı buraya gönderceksin:\n${recipient_name}",
|
||||
|
||||
"card_address" : "Adres:",
|
||||
"buy" : "Alış",
|
||||
|
@ -678,7 +677,12 @@
|
|||
"enabled": "Etkin",
|
||||
"tor_only": "Yalnızca Tor",
|
||||
"unmatched_currencies": "Mevcut cüzdanınızın para birimi taranan QR ile eşleşmiyor",
|
||||
"orbot_running_alert": "Lütfen bu düğüme bağlanmadan önce Orbot'un çalıştığından emin olun.",
|
||||
"contact_list_contacts": "Rehberim",
|
||||
"contact_list_wallets": "Cüzdanlarım",
|
||||
"bitcoin_payments_require_1_confirmation": "Bitcoin ödemeleri, 20 dakika veya daha uzun sürebilen 1 onay gerektirir. Sabrınız için teşekkürler! Ödeme onaylandığında e-posta ile bilgilendirileceksiniz."
|
||||
"bitcoin_payments_require_1_confirmation": "Bitcoin ödemeleri, 20 dakika veya daha uzun sürebilen 1 onay gerektirir. Sabrınız için teşekkürler! Ödeme onaylandığında e-posta ile bilgilendirileceksiniz.",
|
||||
"send_to_this_address" : "Bu adrese ${currency} ${tag}gönder",
|
||||
"arrive_in_this_address" : "${currency} ${tag}bu adrese ulaşacak",
|
||||
"do_not_send": "Gönderme",
|
||||
"error_dialog_content": "Hay aksi, bir hatamız var.\n\nUygulamayı daha iyi hale getirmek için lütfen kilitlenme raporunu destek ekibimize gönderin."
|
||||
}
|
||||
|
|
|
@ -397,8 +397,7 @@
|
|||
"biometric_auth_reason" : "Відскануйте свій відбиток пальця для аутентифікації",
|
||||
"version" : "Версія ${currentVersion}",
|
||||
|
||||
"openalias_alert_title" : "Виявлено адресу",
|
||||
"openalias_alert_content" : "Ви будете відправляти кошти\n${recipient_name}",
|
||||
"extracted_address_content" : "Ви будете відправляти кошти\n${recipient_name}",
|
||||
|
||||
"card_address" : "Адреса:",
|
||||
"buy" : "Купити",
|
||||
|
@ -681,6 +680,8 @@
|
|||
"contact_list_contacts": "Контакти",
|
||||
"contact_list_wallets": "Мої гаманці",
|
||||
"bitcoin_payments_require_1_confirmation": "Платежі Bitcoin потребують 1 підтвердження, яке може зайняти 20 хвилин або більше. Дякую за Ваше терпіння! Ви отримаєте електронний лист, коли платіж буде підтверджено.",
|
||||
"send_to_this_address" : "Надіслати ${currency} ${tag}на цю адресу",
|
||||
"arrive_in_this_address" : "${currency} ${tag}надійде на цю адресу",
|
||||
"do_not_send": "Не надсилайте",
|
||||
"error_dialog_content": "На жаль, ми отримали помилку.\n\nБудь ласка, надішліть звіт про збій нашій команді підтримки, щоб покращити додаток."
|
||||
}
|
||||
|
|
|
@ -398,8 +398,7 @@
|
|||
"biometric_auth_reason" : "扫描指纹进行身份认证",
|
||||
"version" : "版本 ${currentVersion}",
|
||||
|
||||
"openalias_alert_title" : "检测到地址",
|
||||
"openalias_alert_content" : "您将汇款至\n${recipient_name}",
|
||||
"extracted_address_content" : "您将汇款至\n${recipient_name}",
|
||||
|
||||
"card_address" : "地址:",
|
||||
"buy" : "购买",
|
||||
|
@ -680,6 +679,8 @@
|
|||
"contact_list_contacts": "联系人",
|
||||
"contact_list_wallets": "我的钱包",
|
||||
"bitcoin_payments_require_1_confirmation": "比特币支付需要 1 次确认,这可能需要 20 分钟或更长时间。谢谢你的耐心!确认付款后,您将收到电子邮件。",
|
||||
"send_to_this_address" : "发送 ${currency} ${tag}到这个地址",
|
||||
"arrive_in_this_address" : "${currency} ${tag}将到达此地址",
|
||||
"do_not_send": "不要发送",
|
||||
"error_dialog_content": "糟糕,我们遇到了一些错误。\n\n请将崩溃报告发送给我们的支持团队,以改进应用程序。"
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ class SecretKey {
|
|||
SecretKey('anypayToken', () => ''),
|
||||
SecretKey('onramperApiKey', () => ''),
|
||||
SecretKey('ioniaClientId', () => ''),
|
||||
SecretKey('twitterBearerToken', () => ''),
|
||||
];
|
||||
|
||||
final String name;
|
||||
|
|
Loading…
Reference in a new issue