Merge branch 'main' of https://github.com/cake-tech/cake_wallet into CW-438-add-nano

This commit is contained in:
fosse 2023-08-15 12:10:23 -04:00
commit 1a516029e1
63 changed files with 685 additions and 183 deletions

View file

@ -128,6 +128,7 @@ jobs:
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
echo "const payfuraApiKey = '${{ secrets.PAYFURA_API_KEY }}';" >> lib/.secrets.g.dart
echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_ethereum/lib/.secrets.g.dart
echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart
- name: Rename app
run: echo -e "id=com.cakewallet.test\nname=$GITHUB_HEAD_REF" > /opt/android/cake_wallet/android/app.properties

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -0,0 +1,4 @@
import 'package:hive/hive.dart';
import 'package:hive/src/hive_impl.dart';
final HiveInterface CakeHive = HiveImpl();

View file

@ -1,4 +1,5 @@
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/hive_type_ids.dart';
import 'package:hive/hive.dart';
part 'erc20_token.g.dart';
@ -53,7 +54,7 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
iconPath: icon,
);
static const typeId = 12;
static const typeId = ERC20_TOKEN_TYPE_ID;
static const boxName = 'Erc20Tokens';
@override

View file

@ -0,0 +1,13 @@
const CONTACT_TYPE_ID = 0;
const NODE_TYPE_ID = 1;
const TRANSACTION_TYPE_ID = 2;
const TRADE_TYPE_ID = 3;
const WALLET_INFO_TYPE_ID = 4;
const WALLET_TYPE_TYPE_ID = 5;
const TEMPLATE_TYPE_ID = 6;
const EXCHANGE_TEMPLATE_TYPE_ID = 7;
const ORDER_TYPE_ID = 8;
const UNSPENT_COINS_INFO_TYPE_ID = 9;
const ANONPAY_INVOICE_INFO_TYPE_ID = 10;
const ERC20_TOKEN_TYPE_ID = 12;

View file

@ -3,6 +3,7 @@ import 'package:cw_core/keyable.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:hive/hive.dart';
import 'package:cw_core/hive_type_ids.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:http/io_client.dart' as ioc;
@ -36,7 +37,7 @@ class Node extends HiveObject with Keyable {
trusted = map['trusted'] as bool? ?? false,
socksProxyAddress = map['socksProxyPort'] as String?;
static const typeId = 1;
static const typeId = NODE_TYPE_ID;
static const boxName = 'Nodes';
@HiveField(0, defaultValue: '')

View file

@ -1,3 +1,4 @@
import 'package:cw_core/hive_type_ids.dart';
import 'package:hive/hive.dart';
part 'unspent_coins_info.g.dart';
@ -14,7 +15,7 @@ class UnspentCoinsInfo extends HiveObject {
required this.vout,
required this.value});
static const typeId = 9;
static const typeId = UNSPENT_COINS_INFO_TYPE_ID;
static const boxName = 'Unspent';
static const boxKey = 'unspentBoxKey';
@ -45,4 +46,4 @@ class UnspentCoinsInfo extends HiveObject {
String get note => noteRaw ?? '';
set note(String value) => noteRaw = value;
}
}

View file

@ -1,7 +1,7 @@
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:cw_core/wallet_type.dart';
import 'dart:async';
import 'package:cw_core/hive_type_ids.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:hive/hive.dart';
part 'wallet_info.g.dart';
@ -45,7 +45,7 @@ class WalletInfo extends HiveObject {
yatEid, yatLastUsedAddressRaw, showIntroCakePayCard, derivationType);
}
static const typeId = 4;
static const typeId = WALLET_INFO_TYPE_ID;
static const boxName = 'WalletInfo';
@HiveField(0, defaultValue: '')

View file

@ -1,4 +1,5 @@
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/hive_type_ids.dart';
import 'package:hive/hive.dart';
part 'wallet_type.g.dart';
@ -12,9 +13,8 @@ const walletTypes = [
WalletType.nano,
WalletType.banano,
];
const walletTypeTypeId = 5;
@HiveType(typeId: walletTypeTypeId)
@HiveType(typeId: WALLET_TYPE_TYPE_ID)
enum WalletType {
@HiveField(0)
monero,

View file

@ -4,6 +4,7 @@ import 'dart:io';
import 'dart:math';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/cake_hive.dart';
import 'package:cw_core/node.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/pending_transaction.dart';
@ -58,8 +59,8 @@ abstract class EthereumWalletBase
this.walletInfo = walletInfo;
transactionHistory = EthereumTransactionHistory(walletInfo: walletInfo, password: password);
if (!Hive.isAdapterRegistered(Erc20Token.typeId)) {
Hive.registerAdapter(Erc20TokenAdapter());
if (!CakeHive.isAdapterRegistered(Erc20Token.typeId)) {
CakeHive.registerAdapter(Erc20TokenAdapter());
}
_sharedPrefs.complete(SharedPreferences.getInstance());
@ -95,7 +96,7 @@ abstract class EthereumWalletBase
Completer<SharedPreferences> _sharedPrefs = Completer();
Future<void> init() async {
erc20TokensBox = await Hive.openBox<Erc20Token>(Erc20Token.boxName);
erc20TokensBox = await CakeHive.openBox<Erc20Token>(Erc20Token.boxName);
await walletAddresses.init();
await transactionHistory.init();
_privateKey = await getPrivateKey(_mnemonic, _password);

View file

@ -1,4 +1,5 @@
import 'package:cake_wallet/anonpay/anonpay_info_base.dart';
import 'package:cw_core/hive_type_ids.dart';
import 'package:cw_core/keyable.dart';
import 'package:hive/hive.dart';
@ -35,7 +36,7 @@ class AnonpayInvoiceInfo extends HiveObject with Keyable implements AnonpayInfoB
@HiveField(13)
final String provider;
static const typeId = 10;
static const typeId = ANONPAY_INVOICE_INFO_TYPE_ID;
static const boxName = 'AnonpayInvoiceInfo';
AnonpayInvoiceInfo({

View file

@ -1,7 +1,8 @@
import 'package:cake_wallet/buy/buy_provider_description.dart';
import 'package:hive/hive.dart';
import 'package:cake_wallet/exchange/trade_state.dart';
import 'package:cw_core/format_amount.dart';
import 'package:cw_core/hive_type_ids.dart';
import 'package:hive/hive.dart';
part 'order.g.dart';
@ -26,7 +27,7 @@ class Order extends HiveObject {
}
}
static const typeId = 8;
static const typeId = ORDER_TYPE_ID;
static const boxName = 'Orders';
static const boxKey = 'ordersBoxKey';
@ -66,4 +67,4 @@ class Order extends HiveObject {
BuyProviderDescription.deserialize(raw: providerRaw);
String amountFormatted() => formatAmount(amount);
}
}

View file

@ -1,7 +1,6 @@
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:cake_wallet/entities/cake_2fa_preset_options.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
@ -10,6 +9,7 @@ import 'package:path_provider/path_provider.dart';
import 'package:cryptography/cryptography.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:archive/archive_io.dart';
import 'package:cw_core/cake_hive.dart';
import 'package:cake_wallet/core/key_service.dart';
import 'package:cake_wallet/entities/encrypt.dart';
import 'package:cake_wallet/entities/preferences_key.dart';
@ -17,6 +17,7 @@ import 'package:cake_wallet/entities/secret_store_key.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets;
import 'package:cake_wallet/wallet_types.g.dart';
import 'package:cake_backup/backup.dart' as cake_backup;
class BackupService {
@ -170,14 +171,14 @@ class BackupService {
Future<Box<WalletInfo>> _reloadHiveWalletInfoBox() async {
final appDir = await getApplicationDocumentsDirectory();
await Hive.close();
Hive.init(appDir.path);
await CakeHive.close();
CakeHive.init(appDir.path);
if (!Hive.isAdapterRegistered(WalletInfo.typeId)) {
Hive.registerAdapter(WalletInfoAdapter());
if (!CakeHive.isAdapterRegistered(WalletInfo.typeId)) {
CakeHive.registerAdapter(WalletInfoAdapter());
}
return await Hive.openBox<WalletInfo>(WalletInfo.boxName);
return await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
}
Future<void> _importPreferencesDump() async {

View file

@ -42,6 +42,8 @@ import 'package:cake_wallet/src/screens/setup_2fa/modify_2fa_page.dart';
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_qr_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';
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/themes/theme_list.dart';
import 'package:cake_wallet/utils/device_info.dart';
@ -944,6 +946,12 @@ Future setup({
getIt.registerFactory(() => SupportPage(getIt.get<SupportViewModel>()));
getIt.registerFactory(() =>
SupportChatPage(
getIt.get<SupportViewModel>(), secureStorage: getIt.get<FlutterSecureStorage>()));
getIt.registerFactory(() => SupportOtherLinksPage(getIt.get<SupportViewModel>()));
getIt.registerFactory(() {
final wallet = getIt.get<AppStore>().wallet;

View file

@ -1,8 +1,7 @@
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/utils/mobx.dart';
import 'package:cw_core/hive_type_ids.dart';
import 'package:cw_core/keyable.dart';
import 'package:hive/hive.dart';
part 'contact.g.dart';
@ -14,7 +13,7 @@ class Contact extends HiveObject with Keyable {
}
}
static const typeId = 0;
static const typeId = CONTACT_TYPE_ID;
static const boxName = 'Contacts';
@HiveField(0, defaultValue: '')

View file

@ -1,23 +1,18 @@
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:hive/hive.dart';
import 'package:cw_core/cake_hive.dart';
Future<List<int>> getEncryptionKey(
{required String forKey, required FlutterSecureStorage secureStorage}) async {
final stringifiedKey =
await secureStorage.read(key: 'transactionDescriptionsBoxKey');
final stringifiedKey = await secureStorage.read(key: 'transactionDescriptionsBoxKey');
List<int> key;
if (stringifiedKey == null) {
key = Hive.generateSecureKey();
key = CakeHive.generateSecureKey();
final keyStringified = key.join(',');
await secureStorage.write(
key: 'transactionDescriptionsBoxKey', value: keyStringified);
await secureStorage.write(key: 'transactionDescriptionsBoxKey', value: keyStringified);
} else {
key = stringifiedKey
.split(',')
.map((i) => int.parse(i))
.toList();
key = stringifiedKey.split(',').map((i) => int.parse(i)).toList();
}
return key;
}
}

View file

@ -1,3 +1,4 @@
import 'package:cw_core/hive_type_ids.dart';
import 'package:hive/hive.dart';
part 'template.g.dart';
@ -14,7 +15,7 @@ class Template extends HiveObject {
required this.amountFiatRaw,
this.additionalRecipientsRaw});
static const typeId = 6;
static const typeId = TEMPLATE_TYPE_ID;
static const boxName = 'Template';
@HiveField(0)

View file

@ -1,3 +1,4 @@
import 'package:cw_core/hive_type_ids.dart';
import 'package:hive/hive.dart';
part 'transaction_description.g.dart';
@ -6,7 +7,7 @@ part 'transaction_description.g.dart';
class TransactionDescription extends HiveObject {
TransactionDescription({required this.id, this.recipientAddress, this.transactionNote});
static const typeId = 2;
static const typeId = TRANSACTION_TYPE_ID;
static const boxName = 'TransactionDescriptions';
static const boxKey = 'transactionDescriptionsBoxKey';

View file

@ -1,3 +1,4 @@
import 'package:cw_core/hive_type_ids.dart';
import 'package:hive/hive.dart';
part 'exchange_template.g.dart';
@ -14,7 +15,7 @@ class ExchangeTemplate extends HiveObject {
required this.depositCurrencyTitleRaw,
required this.receiveCurrencyTitleRaw});
static const typeId = 7;
static const typeId = EXCHANGE_TEMPLATE_TYPE_ID;
static const boxName = 'ExchangeTemplate';
@HiveField(0)

View file

@ -1,8 +1,9 @@
import 'package:hive/hive.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/exchange/trade_state.dart';
import 'package:cw_core/format_amount.dart';
import 'package:cw_core/hive_type_ids.dart';
import 'package:hive/hive.dart';
part 'trade.g.dart';
@ -41,7 +42,7 @@ class Trade extends HiveObject {
}
}
static const typeId = 3;
static const typeId = TRADE_TYPE_ID;
static const boxName = 'Trades';
static const boxKey = 'tradesBoxKey';

View file

@ -7,6 +7,7 @@ import 'package:cake_wallet/locales/locale.dart';
import 'package:cake_wallet/store/yat/yat_store.dart';
import 'package:cake_wallet/utils/exception_handler.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:cw_core/hive_type_ids.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -38,6 +39,7 @@ import 'package:uni_links/uni_links.dart';
import 'package:cw_core/unspent_coins_info.dart';
import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:cw_core/cake_hive.dart';
final navigatorKey = GlobalKey<NavigatorState>();
final rootKey = GlobalKey<RootState>();
@ -57,7 +59,7 @@ Future<void> main() async {
return true;
};
await Hive.close();
await CakeHive.close();
await initializeAppConfigs();
@ -69,54 +71,54 @@ Future<void> main() async {
Future<void> initializeAppConfigs() async {
final appDir = await getApplicationDocumentsDirectory();
Hive.init(appDir.path);
CakeHive.init(appDir.path);
if (!Hive.isAdapterRegistered(Contact.typeId)) {
Hive.registerAdapter(ContactAdapter());
if (!CakeHive.isAdapterRegistered(Contact.typeId)) {
CakeHive.registerAdapter(ContactAdapter());
}
if (!Hive.isAdapterRegistered(Node.typeId)) {
Hive.registerAdapter(NodeAdapter());
if (!CakeHive.isAdapterRegistered(Node.typeId)) {
CakeHive.registerAdapter(NodeAdapter());
}
if (!Hive.isAdapterRegistered(TransactionDescription.typeId)) {
Hive.registerAdapter(TransactionDescriptionAdapter());
if (!CakeHive.isAdapterRegistered(TransactionDescription.typeId)) {
CakeHive.registerAdapter(TransactionDescriptionAdapter());
}
if (!Hive.isAdapterRegistered(Trade.typeId)) {
Hive.registerAdapter(TradeAdapter());
if (!CakeHive.isAdapterRegistered(Trade.typeId)) {
CakeHive.registerAdapter(TradeAdapter());
}
if (!Hive.isAdapterRegistered(WalletInfo.typeId)) {
Hive.registerAdapter(WalletInfoAdapter());
if (!CakeHive.isAdapterRegistered(WalletInfo.typeId)) {
CakeHive.registerAdapter(WalletInfoAdapter());
}
if (!Hive.isAdapterRegistered(derivationTypeTypeId)) {
if (!Hive.isAdapterRegistered(DERIVATION_TYPE_TYPE_ID)) {
Hive.registerAdapter(DerivationTypeAdapter());
}
if (!Hive.isAdapterRegistered(walletTypeTypeId)) {
Hive.registerAdapter(WalletTypeAdapter());
if (!CakeHive.isAdapterRegistered(WALLET_TYPE_TYPE_ID)) {
CakeHive.registerAdapter(WalletTypeAdapter());
}
if (!Hive.isAdapterRegistered(Template.typeId)) {
Hive.registerAdapter(TemplateAdapter());
if (!CakeHive.isAdapterRegistered(Template.typeId)) {
CakeHive.registerAdapter(TemplateAdapter());
}
if (!Hive.isAdapterRegistered(ExchangeTemplate.typeId)) {
Hive.registerAdapter(ExchangeTemplateAdapter());
if (!CakeHive.isAdapterRegistered(ExchangeTemplate.typeId)) {
CakeHive.registerAdapter(ExchangeTemplateAdapter());
}
if (!Hive.isAdapterRegistered(Order.typeId)) {
Hive.registerAdapter(OrderAdapter());
if (!CakeHive.isAdapterRegistered(Order.typeId)) {
CakeHive.registerAdapter(OrderAdapter());
}
if (!isMoneroOnly && !Hive.isAdapterRegistered(UnspentCoinsInfo.typeId)) {
Hive.registerAdapter(UnspentCoinsInfoAdapter());
if (!isMoneroOnly && !CakeHive.isAdapterRegistered(UnspentCoinsInfo.typeId)) {
CakeHive.registerAdapter(UnspentCoinsInfoAdapter());
}
if (!Hive.isAdapterRegistered(AnonpayInvoiceInfo.typeId)) {
Hive.registerAdapter(AnonpayInvoiceInfoAdapter());
if (!CakeHive.isAdapterRegistered(AnonpayInvoiceInfo.typeId)) {
CakeHive.registerAdapter(AnonpayInvoiceInfoAdapter());
}
final secureStorage = FlutterSecureStorage();
@ -124,21 +126,21 @@ Future<void> initializeAppConfigs() async {
await getEncryptionKey(secureStorage: secureStorage, forKey: TransactionDescription.boxKey);
final tradesBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Trade.boxKey);
final ordersBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Order.boxKey);
final contacts = await Hive.openBox<Contact>(Contact.boxName);
final nodes = await Hive.openBox<Node>(Node.boxName);
final transactionDescriptions = await Hive.openBox<TransactionDescription>(
final contacts = await CakeHive.openBox<Contact>(Contact.boxName);
final nodes = await CakeHive.openBox<Node>(Node.boxName);
final transactionDescriptions = await CakeHive.openBox<TransactionDescription>(
TransactionDescription.boxName,
encryptionKey: transactionDescriptionsBoxKey);
final trades = await Hive.openBox<Trade>(Trade.boxName, encryptionKey: tradesBoxKey);
final orders = await Hive.openBox<Order>(Order.boxName, encryptionKey: ordersBoxKey);
final walletInfoSource = await Hive.openBox<WalletInfo>(WalletInfo.boxName);
final templates = await Hive.openBox<Template>(Template.boxName);
final exchangeTemplates = await Hive.openBox<ExchangeTemplate>(ExchangeTemplate.boxName);
final anonpayInvoiceInfo = await Hive.openBox<AnonpayInvoiceInfo>(AnonpayInvoiceInfo.boxName);
final trades = await CakeHive.openBox<Trade>(Trade.boxName, encryptionKey: tradesBoxKey);
final orders = await CakeHive.openBox<Order>(Order.boxName, encryptionKey: ordersBoxKey);
final walletInfoSource = await CakeHive.openBox<WalletInfo>(WalletInfo.boxName);
final templates = await CakeHive.openBox<Template>(Template.boxName);
final exchangeTemplates = await CakeHive.openBox<ExchangeTemplate>(ExchangeTemplate.boxName);
final anonpayInvoiceInfo = await CakeHive.openBox<AnonpayInvoiceInfo>(AnonpayInvoiceInfo.boxName);
Box<UnspentCoinsInfo>? unspentCoinsInfoSource;
if (!isMoneroOnly) {
unspentCoinsInfoSource = await Hive.openBox<UnspentCoinsInfo>(UnspentCoinsInfo.boxName);
unspentCoinsInfoSource = await CakeHive.openBox<UnspentCoinsInfo>(UnspentCoinsInfo.boxName);
}
await initialSetup(

View file

@ -45,6 +45,8 @@ import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_qr_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';
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/unspent_coins/unspent_coins_details_page.dart';
import 'package:cake_wallet/src/screens/unspent_coins/unspent_coins_list_page.dart';
import 'package:cake_wallet/utils/payment_request.dart';
@ -52,7 +54,6 @@ import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.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/advanced_privacy_settings_view_model.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:cw_core/nano_account.dart';
import 'package:flutter/cupertino.dart';
@ -420,7 +421,16 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.support:
return CupertinoPageRoute<void>(
fullscreenDialog: true, builder: (_) => getIt.get<SupportPage>());
builder: (_) => getIt.get<SupportPage>());
case Routes.supportLiveChat:
return CupertinoPageRoute<void>(
builder: (_) => getIt.get<SupportChatPage>());
case Routes.supportOtherLinks:
return CupertinoPageRoute<void>(
fullscreenDialog: true,
builder: (_) => getIt.get<SupportOtherLinksPage>());
case Routes.unspentCoinsList:
return MaterialPageRoute<void>(builder: (_) => getIt.get<UnspentCoinsListPage>());

View file

@ -51,6 +51,8 @@ class Routes {
static const editBackupPassword = '/edit_backup_passowrd';
static const restoreFromBackup = '/restore_from_backup';
static const support = '/support';
static const supportLiveChat = '/support/live_chat';
static const supportOtherLinks = '/support/other';
static const orderDetails = '/order_details';
static const preOrder = '/pre_order';
static const buyWebView = '/buy_web_view';

View file

@ -2,12 +2,10 @@ import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/utils/language_list.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/restore/restore_from_qr_vm.dart';
import 'package:cake_wallet/view_model/restore/wallet_restore_from_qr_code.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/routes.dart';
import 'package:flutter/cupertino.dart';

View file

@ -1,12 +1,11 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class RestoreButton extends StatelessWidget {
const RestoreButton({
required this.onPressed,
required this.image,
required this.title,
required this.description});
const RestoreButton(
{required this.onPressed,
required this.image,
required this.title,
required this.description});
final VoidCallback onPressed;
final Image image;
@ -24,10 +23,7 @@ class RestoreButton extends StatelessWidget {
alignment: Alignment.topLeft,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(12)),
color: Theme.of(context)
.accentTextTheme!
.bodySmall!
.color!,
color: Theme.of(context).accentTextTheme.bodySmall!.color!,
),
child: Row(
mainAxisSize: MainAxisSize.max,
@ -49,7 +45,7 @@ class RestoreButton extends StatelessWidget {
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context)
.primaryTextTheme!
.primaryTextTheme
.titleLarge!
.color!),
),
@ -61,7 +57,7 @@ class RestoreButton extends StatelessWidget {
fontSize: 14,
fontWeight: FontWeight.normal,
color: Theme.of(context)
.primaryTextTheme!
.primaryTextTheme
.labelSmall!
.color!),
),

View file

@ -6,7 +6,6 @@ class SettingsCellWithArrow extends StandardListRow {
: super(title: title, isSelected: false, onTap: handler);
@override
Widget buildTrailing(BuildContext context) =>
Image.asset('assets/images/select_arrow.png',
color: Theme.of(context).primaryTextTheme!.labelSmall!.color!);
}
Widget buildTrailing(BuildContext context) => Image.asset('assets/images/select_arrow.png',
color: Theme.of(context).primaryTextTheme.labelSmall!.color!);
}

View file

@ -1,55 +1,78 @@
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_link_provider_cell.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:cake_wallet/view_model/settings/link_list_item.dart';
import 'package:cake_wallet/view_model/settings/regular_list_item.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/support/widgets/support_tiles.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/utils/device_info.dart';
import 'package:cake_wallet/view_model/support_view_model.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:url_launcher/url_launcher.dart';
class SupportPage extends BasePage {
SupportPage(this.supportViewModel);
final SupportViewModel supportViewModel;
final imageLiveSupport = Image.asset('assets/images/live_support.png');
final imageWalletGuides = Image.asset('assets/images/wallet_guides.png');
final imageMoreLinks = Image.asset('assets/images/more_links.png');
@override
String get title => S.current.settings_support;
@override
AppBarStyle get appBarStyle => AppBarStyle.regular;
@override
Widget body(BuildContext context) {
final iconColor = Theme.of(context)
.accentTextTheme!
.displayLarge!
.backgroundColor!;
// FIX-ME: Added `context` it was not used here before, maby bug ?
return Center(
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: 500),
child: SectionStandardList(
context: context,
sectionCount: 1,
itemCounter: (int _) => supportViewModel.items.length,
itemBuilder: (_, __, index) {
final item = supportViewModel.items[index];
if (item is RegularListItem) {
return SettingsCellWithArrow(title: item.title, handler: item.handler);
}
if (item is LinkListItem) {
return SettingsLinkProviderCell(
title: item.title,
icon: item.icon,
iconColor: item.hasIconColor ? iconColor : null,
link: item.link,
linkTitle: item.linkTitle);
}
return Container();
}),
return Container(
child: Center(
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: 330),
child: Column(
children: [
Padding(
padding: EdgeInsets.only(top: 24),
child: SupportTile(
image: imageLiveSupport,
title: S.of(context).support_title_live_chat,
description: S.of(context).support_description_live_chat,
onPressed: () {
if (DeviceInfo.instance.isDesktop) {
_launchUrl(supportViewModel.fetchUrl());
} else {
Navigator.pushNamed(context, Routes.supportLiveChat);
}
},
),
),
Padding(
padding: EdgeInsets.only(top: 24),
child: SupportTile(
image: imageWalletGuides,
title: S.of(context).support_title_guides,
description: S.of(context).support_description_guides,
onPressed: () => _launchUrl(supportViewModel.guidesUrl),
),
),
Padding(
padding: EdgeInsets.only(top: 24),
child: SupportTile(
image: imageMoreLinks,
title: S.of(context).support_title_other_links,
description: S.of(context).support_description_other_links,
onPressed: () => Navigator.pushNamed(context, Routes.supportOtherLinks),
),
),
],
),
),
),
);
}
void _launchUrl(String url) async {
try {
await launchUrl(Uri.parse(url), mode: LaunchMode.externalApplication);
} catch (e) {}
}
}

View file

@ -0,0 +1,69 @@
import 'package:flutter/material.dart';
class SupportTile extends StatelessWidget {
const SupportTile(
{required this.onPressed,
required this.image,
required this.title,
required this.description});
final VoidCallback onPressed;
final Image image;
final String title;
final String description;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onPressed,
child: Container(
width: double.infinity,
padding: EdgeInsets.all(24),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(12)),
color: Theme.of(context).accentTextTheme.bodySmall!.color!,
),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
image,
Expanded(
child: Padding(
padding: EdgeInsets.only(left: 16),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
title,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
color: Theme.of(context).primaryTextTheme.titleLarge!.color!,
),
),
Padding(
padding: EdgeInsets.only(top: 5),
child: Text(
description,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.normal,
color: Theme.of(context).primaryTextTheme.labelSmall!.color!,
),
),
)
],
),
),
)
],
),
),
);
}
}

View file

@ -0,0 +1,38 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/screens/support_chat/widgets/chatwoot_widget.dart';
import 'package:cake_wallet/view_model/support_view_model.dart';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class SupportChatPage extends BasePage {
SupportChatPage(this.supportViewModel, {required this.secureStorage});
final SupportViewModel supportViewModel;
final FlutterSecureStorage secureStorage;
@override
String get title => S.current.settings_support;
@override
AppBarStyle get appBarStyle => AppBarStyle.regular;
@override
Widget body(BuildContext context) => FutureBuilder<String>(
future: getCookie(),
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
print(snapshot.data);
if (snapshot.hasData)
return ChatwootWidget(
secureStorage,
supportUrl: supportViewModel.fetchUrl(authToken: snapshot.data!)
);
return Container();
},
);
Future<String> getCookie() async {
return await secureStorage.read(key: COOKIE_KEY) ?? "";
}
}

View file

@ -0,0 +1,62 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
const COOKIE_KEY = 'chatwootCookie';
class ChatwootWidget extends StatefulWidget {
ChatwootWidget(this.secureStorage, {required this.supportUrl});
final FlutterSecureStorage secureStorage;
final String supportUrl;
@override
ChatwootWidgetState createState() => ChatwootWidgetState();
}
class ChatwootWidgetState extends State<ChatwootWidget> {
final GlobalKey _webViewkey = GlobalKey();
@override
Widget build(BuildContext context) => InAppWebView(
key: _webViewkey,
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(transparentBackground: true),
),
initialUrlRequest: URLRequest(url: Uri.tryParse(widget.supportUrl)),
onWebViewCreated: (InAppWebViewController controller) {
controller.addWebMessageListener(
WebMessageListener(
jsObjectName: 'ReactNativeWebView',
onPostMessage: (String? message, Uri? sourceOrigin, bool isMainFrame,
JavaScriptReplyProxy replyProxy) {
final shortenedMessage = message?.substring(16);
if (shortenedMessage != null && isJsonString(shortenedMessage)) {
final parsedMessage = jsonDecode(shortenedMessage);
final eventType = parsedMessage["event"];
if (eventType == 'loaded') {
final authToken = parsedMessage["config"]["authToken"];
print(authToken);
storeCookie(authToken as String);
}
}
},
),
);
},
);
bool isJsonString(String str) {
try {
jsonDecode(str);
} catch (e) {
return false;
}
return true;
}
Future<void> storeCookie(String value) async =>
await widget.secureStorage.write(key: COOKIE_KEY, value: value);
}

View file

@ -0,0 +1,58 @@
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
import 'package:cake_wallet/src/screens/settings/widgets/settings_link_provider_cell.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:cake_wallet/view_model/settings/link_list_item.dart';
import 'package:cake_wallet/view_model/settings/regular_list_item.dart';
import 'package:cake_wallet/view_model/support_view_model.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/generated/i18n.dart';
class SupportOtherLinksPage extends BasePage {
SupportOtherLinksPage(this.supportViewModel);
final SupportViewModel supportViewModel;
@override
String get title => S.current.settings_support;
@override
AppBarStyle get appBarStyle => AppBarStyle.transparent;
@override
Widget body(BuildContext context) {
final iconColor =
Theme.of(context).accentTextTheme.displayLarge!.backgroundColor!;
return Container(
child: Center(
child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: 500),
child: SectionStandardList(
context: context,
sectionCount: 1,
itemCounter: (int _) => supportViewModel.items.length,
itemBuilder: (_, __, index) {
final item = supportViewModel.items[index];
if (item is RegularListItem) {
return SettingsCellWithArrow(
title: item.title, handler: item.handler);
}
if (item is LinkListItem) {
return SettingsLinkProviderCell(
title: item.title,
icon: item.icon,
iconColor: item.hasIconColor ? iconColor : null,
link: item.link,
linkTitle: item.linkTitle);
}
return Container();
}),
),
),
);
}
}

View file

@ -1,12 +1,9 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/view_model/settings/link_list_item.dart';
import 'package:cake_wallet/view_model/settings/regular_list_item.dart';
import 'package:cake_wallet/view_model/settings/settings_list_item.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:mobx/mobx.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/.secrets.g.dart' as secrets;
part 'support_view_model.g.dart';
@ -15,14 +12,6 @@ class SupportViewModel = SupportViewModelBase with _$SupportViewModel;
abstract class SupportViewModelBase with Store {
SupportViewModelBase()
: items = [
RegularListItem(
title: S.current.faq,
handler: (BuildContext context) async {
try {
await launch(url);
} catch (e) {}
},
),
LinkListItem(
title: 'Email',
linkTitle: 'support@cakewallet.com',
@ -85,7 +74,17 @@ abstract class SupportViewModelBase with Store {
// link: 'mailto:support@y.at')
];
static const url = 'https://guides.cakewallet.com';
final guidesUrl = 'https://guides.cakewallet.com';
String fetchUrl({String locale = "en", String authToken = ""}) {
var supportUrl =
"https://app.chatwoot.com/widget?website_token=${secrets.chatwootWebsiteToken}&locale=${locale}";
if (authToken.isNotEmpty)
supportUrl += "&cw_conversation=$authToken";
return supportUrl;
}
List<SettingsListItem> items;
}
}

View file

@ -100,6 +100,7 @@ dev_dependencies:
# check flutter_launcher_icons for usage
pedantic: ^1.8.0
# replace https://github.com/dart-lang/lints#migrating-from-packagepedantic
translator: ^0.1.7
flutter_icons:
image_path: "assets/images/app_logo.png"

View file

@ -671,6 +671,12 @@
"change_rep": "ﺏﻭﺪﻨﻣ ﺮﻴﻴﻐﺗ",
"change_rep_message": "؟ﻦﻴﻠﺜﻤﻤﻟﺍ ﺮﻴﻴﻐﺗ ﺪﻳﺮﺗ ﻚﻧﺃ ﺪﻛﺄﺘﻣ ﺖﻧﺃ ﻞﻫ",
"manage_nodes": "ﺪﻘﻌﻟﺍ ﺓﺭﺍﺩﺇ",
"unsupported_asset": " .ﻡﻮﻋﺪﻣ ﻞﺻﺃ ﻉﻮﻧ ﻦﻣ ﺔﻈﻔﺤﻣ ﻰﻟﺇ ﻞﻳﺪﺒﺘﻟﺍ ﻭﺃ ءﺎﺸﻧﺇ ﻰﺟﺮﻳ .ﻞﺻﻷﺍ ﺍﺬﻬﻟ ءﺍﺮﺟﻹﺍ ﺍﺬﻫ ﻢﻋﺪﻧ ﻻ ﻦﺤﻧ",
"manage_pow_nodes": " PoW ﻁﺎﻘﻧ ﺓﺭﺍﺩﺇ"
"unsupported_asset": ".ﻡﻮﻋﺪﻣ ﻞﺻﺃ ﻉﻮﻧ ﻦﻣ ﺔﻈﻔﺤﻣ ﻰﻟﺇ ﻞﻳﺪﺒﺘﻟﺍ ﻭﺃ ءﺎﺸﻧﺇ ﻰﺟﺮﻳ .ﻞﺻﻷﺍ ﺍﺬﻬﻟ ءﺍﺮﺟﻹﺍ ﺍﺬﻫ ﻢﻋﺪﻧ ﻻ ﻦﺤﻧ",
"manage_pow_nodes": "PoW ﻁﺎﻘﻧ ﺓﺭﺍﺩﺇ",
"support_title_live_chat": "الدعم المباشر",
"support_description_live_chat": "حرة وسريعة! ممثلو الدعم المدربين متاحون للمساعدة",
"support_title_guides": "أدلة محفظة كعكة",
"support_description_guides": "توثيق ودعم القضايا المشتركة",
"support_title_other_links": "روابط دعم أخرى",
"support_description_other_links": "انضم إلى مجتمعاتنا أو تصل إلينا شركائنا من خلال أساليب أخرى"
}

View file

@ -668,5 +668,11 @@
"change_rep_message": "Сигурни ли сте, че искате да смените представителите?",
"manage_nodes": "Управление на възли",
"unsupported_asset": "Не поддържаме това действие за този актив. Моля, създайте или преминете към портфейл от поддържан тип актив.",
"manage_pow_nodes": "Управление на PoW възли"
"manage_pow_nodes": "Управление на PoW възли",
"support_title_live_chat": "Подкрепа на живо",
"support_description_live_chat": "Безплатно и бързо! Обучени представители на подкрепата са на разположение за подпомагане",
"support_title_guides": "Ръководства за портфейл за торта",
"support_description_guides": "Документация и подкрепа за общи проблеми",
"support_title_other_links": "Други връзки за поддръжка",
"support_description_other_links": "Присъединете се към нашите общности или се свържете с нас нашите партньори чрез други методи"
}

View file

@ -668,5 +668,11 @@
"change_rep": "Změna zástupce",
"change_rep_message": "Jste si jisti, že chcete změnit zástupce?",
"unsupported_asset": "Tuto akci u tohoto díla nepodporujeme. Vytvořte nebo přepněte na peněženku podporovaného typu aktiv.",
"manage_pow_nodes": "Správa uzlů PoW"
"manage_pow_nodes": "Správa uzlů PoW",
"support_title_live_chat": "Živá podpora",
"support_description_live_chat": "Zdarma a rychle! K dispozici jsou zástupci vyškolených podpůrných podpory",
"support_title_guides": "Průvodce peněženkami dortu",
"support_description_guides": "Dokumentace a podpora běžných otázek",
"support_title_other_links": "Další odkazy na podporu",
"support_description_other_links": "Připojte se k našim komunitám nebo se k nám oslovte další metody"
}

View file

@ -211,7 +211,7 @@
"settings_only_trades": "Nur Handel",
"settings_only_transactions": "Nur Transaktionen",
"settings_none": "Keiner",
"settings_support": "Unterstützen",
"settings_support": "Hilfe",
"settings_terms_and_conditions": "Geschäftsbedingungen",
"pin_is_incorrect": "PIN ist falsch",
"setup_pin": "PIN einrichten",
@ -676,5 +676,11 @@
"change_rep": "Change-Beauftragter",
"change_rep_message": "Sind Sie sicher, dass Sie den Vertreter wechseln möchten?",
"unsupported_asset": "Wir unterstützen diese Aktion für dieses Asset nicht. Bitte erstellen Sie eine Wallet eines unterstützten Asset-Typs oder wechseln Sie zu einer Wallet.",
"manage_pow_nodes": "PoW-Knoten verwalten"
"manage_pow_nodes": "PoW-Knoten verwalten",
"support_title_live_chat": "Live Support",
"support_description_live_chat": "Kostenlos und schnell! Ausgebildete Mitarbeiter stehen zur Unterstützung bereit, um zu helfen",
"support_title_guides": "Cake Wallet Guides",
"support_description_guides": "Dokumentation und Hilfe für bekannte Probleme",
"support_title_other_links": "Andere Support-Links",
"support_description_other_links": "Treten Sie unseren Communities bei oder erreichen Sie uns oder unsere Partner über andere Methoden"
}

View file

@ -676,5 +676,11 @@
"change_rep": "Change Representative",
"change_rep_message": "Are you sure that you want to change representatives?",
"unsupported_asset": "We don't support this action for this asset. Please create or switch to a wallet of a supported asset type.",
"manage_pow_nodes": "Manage PoW nodes"
"manage_pow_nodes": "Manage PoW nodes",
"support_title_live_chat": "Live support",
"support_description_live_chat": "Free and fast! Trained support representatives are available to assist",
"support_title_guides": "Cake Wallet guides",
"support_description_guides": "Documentation and support for common issues",
"support_title_other_links": "Other support links",
"support_description_other_links": "Join our communities or reach us our our partners through other methods"
}

View file

@ -676,5 +676,11 @@
"change_rep": "Representante de cambio",
"change_rep_message": "¿Estás seguro de que quieres cambiar de representante?",
"unsupported_asset": "No admitimos esta acción para este activo. Cree o cambie a una billetera de un tipo de activo admitido.",
"manage_pow_nodes": "Administrar nodos PoW"
"manage_pow_nodes": "Administrar nodos PoW",
"support_title_live_chat": "Soporte vital",
"support_description_live_chat": "¡GRATIS y RÁPIDO! Los representantes de apoyo capacitado están disponibles para ayudar",
"support_title_guides": "Guías de billetera para pastel",
"support_description_guides": "Documentación y apoyo para problemas comunes",
"support_title_other_links": "Otros enlaces de soporte",
"support_description_other_links": "Únase a nuestras comunidades o comuníquese con nosotros nuestros socios a través de otros métodos"
}

View file

@ -676,5 +676,11 @@
"change_rep": "Changer de représentant",
"change_rep_message": "Êtes-vous sûr de vouloir changer de représentant ?",
"unsupported_asset": "Nous ne prenons pas en charge cette action pour cet élément. Veuillez créer ou passer à un portefeuille d'un type d'actif pris en charge.",
"manage_pow_nodes": "Gérer les nœuds PoW"
"manage_pow_nodes": "Gérer les nœuds PoW",
"support_title_live_chat": "Support en direct",
"support_description_live_chat": "GRATUIT ET RAPIDE! Des représentants de soutien formé sont disponibles pour aider",
"support_title_guides": "Guides de portefeuille à gâteau",
"support_description_guides": "Documentation et soutien aux problèmes communs",
"support_title_other_links": "Autres liens d'assistance",
"support_description_other_links": "Rejoignez nos communautés ou contactez-nous nos partenaires à travers d'autres méthodes"
}

View file

@ -654,5 +654,11 @@
"change_rep_message": "Shin kun tabbata kuna son canza wakilai?",
"manage_nodes": "Sarrafa nodes",
"unsupported_asset": "Ba mu goyi bayan wannan aikin don wannan kadara. Da fatan za a ƙirƙira ko canza zuwa walat na nau'in kadara mai tallafi.",
"manage_pow_nodes": "Sarrafa PoW Nodes"
"manage_pow_nodes": "Sarrafa PoW Nodes",
"support_title_live_chat": "Tallafi na Live",
"support_description_live_chat": "Kyauta da sauri! An horar da wakilan tallafi na tallafi don taimakawa",
"support_title_guides": "Jagorar Cake",
"support_description_guides": "Tallafi da tallafi don batutuwa na yau da kullun",
"support_title_other_links": "Sauran hanyoyin tallafi",
"support_description_other_links": "Kasance tare da al'ummominmu ko kuma ka kai mu abokanmu ta hanyar wasu hanyoyi"
}

View file

@ -676,5 +676,11 @@
"change_rep": "प्रतिनिधि बदलें",
"change_rep_message": "क्या आप वाकई प्रतिनिधियों को बदलना चाहते हैं?",
"unsupported_asset": "हम इस संपत्ति के लिए इस कार्रवाई का समर्थन नहीं करते हैं. कृपया समर्थित परिसंपत्ति प्रकार का वॉलेट बनाएं या उस पर स्विच करें।",
"manage_pow_nodes": "PoW नोड्स प्रबंधित करें"
"manage_pow_nodes": "PoW नोड्स प्रबंधित करें",
"support_title_live_chat": "लाइव सहायता",
"support_description_live_chat": "मुक्त और तेजी से! प्रशिक्षित सहायता प्रतिनिधि सहायता के लिए उपलब्ध हैं",
"support_title_guides": "केक वॉलेट गाइड",
"support_description_guides": "सामान्य मुद्दों के लिए प्रलेखन और समर्थन",
"support_title_other_links": "अन्य समर्थन लिंक",
"support_description_other_links": "हमारे समुदायों में शामिल हों या अन्य तरीकों के माध्यम से हमारे साथी तक पहुंचें"
}

View file

@ -673,8 +673,12 @@
"manage_nodes": "Upravljanje čvorovima",
"etherscan_history": "Etherscan povijest",
"template_name": "Naziv predloška",
"change_rep": "Promjena predstavnika",
"change_rep_message": "Jeste li sigurni da želite promijeniti predstavnika?",
"unsupported_asset": "Ne podržavamo ovu radnju za ovaj materijal. Izradite ili prijeđite na novčanik podržane vrste sredstava.",
"manage_pow_nodes": "Upravljanje PoW čvorovima"
"manage_pow_nodes": "Upravljanje PoW čvorovima",
"support_title_live_chat": "Podrška uživo",
"support_title_guides": "Vodiči za torte",
"support_description_guides": "Dokumentacija i podrška za uobičajena pitanja",
"support_title_other_links": "Ostale veze za podršku",
"support_description_other_links": "Pridružite se našim zajednicama ili nam dosegnu naše partnere drugim metodama"
}

View file

@ -664,5 +664,11 @@
"change_rep": "Ubah Perwakilan",
"change_rep_message": "Apakah Anda yakin ingin mengubah perwakilan?",
"unsupported_asset": "Kami tidak mendukung tindakan ini untuk aset ini. Harap buat atau alihkan ke dompet dari jenis aset yang didukung.",
"manage_pow_nodes": "Kelola Node PoW"
"manage_pow_nodes": "Kelola Node PoW",
"support_title_live_chat": "Dukungan langsung",
"support_description_live_chat": "Gratis dan Cepat! Perwakilan dukungan terlatih tersedia untuk membantu",
"support_title_guides": "Panduan Dompet Kue",
"support_description_guides": "Dokumentasi dan dukungan untuk masalah umum",
"support_title_other_links": "Tautan dukungan lainnya",
"support_description_other_links": "Bergabunglah dengan komunitas kami atau hubungi kami mitra kami melalui metode lain"
}

View file

@ -676,5 +676,11 @@
"change_rep": "Cambia rappresentante",
"change_rep_message": "Sei sicuro di voler cambiare rappresentante?",
"unsupported_asset": "Non supportiamo questa azione per questa risorsa. Crea o passa a un portafoglio di un tipo di asset supportato.",
"manage_pow_nodes": "Gestisci i nodi PoW"
"manage_pow_nodes": "Gestisci i nodi PoW",
"support_title_live_chat": "Supporto dal vivo",
"support_description_live_chat": "Gratuito e veloce! I rappresentanti di supporto qualificati sono disponibili per assistere",
"support_title_guides": "Guide del portafoglio per torte",
"support_description_guides": "Documentazione e supporto per problemi comuni",
"support_title_other_links": "Altri collegamenti di supporto",
"support_description_other_links": "Unisciti alle nostre comunità o raggiungici i nostri partner attraverso altri metodi"
}

View file

@ -676,5 +676,11 @@
"change_rep": "代表者の変更",
"change_rep_message": "代表者を変更してもよろしいですか?",
"unsupported_asset": "このアセットに対するこのアクションはサポートされていません。サポートされているアセットタイプのウォレットを作成するか、ウォレットに切り替えてください。",
"manage_pow_nodes": "PoWードの管理"
"manage_pow_nodes": "PoWードの管理",
"support_title_live_chat": "ライブサポート",
"support_description_live_chat": "無料で速い!訓練されたサポート担当者が支援することができます",
"support_title_guides": "ケーキウォレットガイド",
"support_description_guides": "一般的な問題のドキュメントとサポート",
"support_title_other_links": "その他のサポートリンク",
"support_description_other_links": "私たちのコミュニティに参加するか、他の方法を通して私たちのパートナーに連絡してください"
}

View file

@ -674,5 +674,11 @@
"etherscan_history": "이더스캔 역사",
"template_name": "템플릿 이름",
"unsupported_asset": "이 저작물에 대해 이 작업을 지원하지 않습니다. 지원되는 자산 유형의 지갑을 생성하거나 전환하십시오.",
"manage_pow_nodes": "PoW 노드 관리"
"manage_pow_nodes": "PoW 노드 관리",
"support_title_live_chat": "실시간 지원",
"support_description_live_chat": "자유롭고 빠릅니다! 훈련 된 지원 담당자가 지원할 수 있습니다",
"support_title_guides": "케이크 지갑 가이드",
"support_description_guides": "일반적인 문제에 대한 문서화 및 지원",
"support_title_other_links": "다른 지원 링크",
"support_description_other_links": "다른 방법을 통해 커뮤니티에 가입하거나 파트너에게 연락하십시오."
}

View file

@ -674,5 +674,11 @@
"change_rep": "ကိုယ်စားလှယ်ပြောင်းပါ။",
"change_rep_message": "ကိုယ်စားလှယ်ပြောင်းလိုသည်မှာ သေချာပါသလား။",
"unsupported_asset": "ဤပိုင်ဆိုင်မှုအတွက် ဤလုပ်ဆောင်ချက်ကို ကျွန်ုပ်တို့ မပံ့ပိုးပါ။ ကျေးဇူးပြု၍ ပံ့ပိုးပေးထားသော ပိုင်ဆိုင်မှုအမျိုးအစား၏ ပိုက်ဆံအိတ်ကို ဖန်တီးပါ သို့မဟုတ် ပြောင်းပါ။",
"manage_pow_nodes": "PoW Nodes ကို စီမံပါ။"
"manage_pow_nodes": "PoW Nodes ကို စီမံပါ။",
"support_title_live_chat": "တိုက်ရိုက်ပံ့ပိုးမှု",
"support_description_live_chat": "အခမဲ့နှင့်အစာရှောင်ခြင်း! လေ့ကျင့်ထားသောထောက်ခံသူကိုယ်စားလှယ်များသည်ကူညီနိုင်သည်",
"support_title_guides": "ကိတ်မုန့်ပိုက်ဆံအိတ်လမ်းညွှန်များ",
"support_description_guides": "ဘုံပြ issues နာများအတွက်စာရွက်စာတမ်းများနှင့်ထောက်ခံမှု",
"support_title_other_links": "အခြားအထောက်အပံ့လင့်များ",
"support_description_other_links": "ကျွန်ုပ်တို့၏လူမှုအသိုင်းအဝိုင်းများသို့ 0 င်ရောက်ပါ"
}

View file

@ -676,5 +676,11 @@
"change_rep": "Vertegenwoordiger wijzigen",
"change_rep_message": "Weet u zeker dat u van vertegenwoordiger wilt veranderen?",
"unsupported_asset": "We ondersteunen deze actie niet voor dit item. Maak of schakel over naar een portemonnee van een ondersteund activatype.",
"manage_pow_nodes": "PoW-knooppunten beheren"
"manage_pow_nodes": "PoW-knooppunten beheren",
"support_title_live_chat": "Live ondersteuning",
"support_description_live_chat": "Gratis en snel! Getrainde ondersteuningsvertegenwoordigers zijn beschikbaar om te helpen",
"support_title_guides": "Cake -portemonnee gidsen",
"support_description_guides": "Documentatie en ondersteuning voor gemeenschappelijke problemen",
"support_title_other_links": "Andere ondersteuningslinks",
"support_description_other_links": "Word lid van onze gemeenschappen of bereik ons onze partners via andere methoden"
}

View file

@ -676,5 +676,11 @@
"change_rep": "Zmień przedstawiciela",
"change_rep_message": "Czy na pewno chcesz zmienić przedstawiciela?",
"unsupported_asset": "Nie obsługujemy tego działania w przypadku tego zasobu. Utwórz lub przełącz się na portfel obsługiwanego typu aktywów.",
"manage_pow_nodes": "Zarządzaj węzłami PoW"
"manage_pow_nodes": "Zarządzaj węzłami PoW",
"support_title_live_chat": "Wsparcie na żywo",
"support_description_live_chat": "Darmowe i szybkie! Do pomocy są dostępni przeszkoleni przedstawiciele wsparcia",
"support_title_guides": "Przewodniki portfela ciasta",
"support_description_guides": "Dokumentacja i wsparcie dla typowych problemów",
"support_title_other_links": "Inne linki wsparcia",
"support_description_other_links": "Dołącz do naszych społeczności lub skontaktuj się z nami naszymi partnerami za pomocą innych metod"
}

View file

@ -675,5 +675,11 @@
"change_rep": "Alterar representante",
"change_rep_message": "Tem certeza de que deseja alterar os representantes?",
"unsupported_asset": "Não oferecemos suporte a esta ação para este recurso. Crie ou mude para uma carteira de um tipo de ativo compatível.",
"manage_pow_nodes": "Gerenciar nós PoW"
"manage_pow_nodes": "Gerenciar nós PoW",
"support_title_live_chat": "Apoio ao vivo",
"support_description_live_chat": "Livre e rápido! Representantes de suporte treinado estão disponíveis para ajudar",
"support_title_guides": "Guias da carteira de bolo",
"support_description_guides": "Documentação e suporte para problemas comuns",
"support_title_other_links": "Outros links de suporte",
"support_description_other_links": "Junte -se às nossas comunidades ou chegue a nós nossos parceiros por meio de outros métodos"
}

View file

@ -676,5 +676,11 @@
"change_rep": "Изменить представителя",
"change_rep_message": "Вы уверены, что хотите сменить представителя?",
"unsupported_asset": "Мы не поддерживаем это действие для этого объекта. Пожалуйста, создайте или переключитесь на кошелек поддерживаемого типа активов.",
"manage_pow_nodes": "Управление узлами PoW"
"manage_pow_nodes": "Управление узлами PoW",
"support_title_live_chat": "Живая поддержка",
"support_description_live_chat": "Бесплатно и быстро! Обученные представители поддержки доступны для оказания помощи",
"support_title_guides": "Корт -гиды",
"support_description_guides": "Документация и поддержка общих вопросов",
"support_title_other_links": "Другие ссылки на поддержку",
"support_description_other_links": "Присоединяйтесь к нашим сообществам или охватите нас наших партнеров с помощью других методов"
}

View file

@ -674,5 +674,11 @@
"change_rep": "เปลี่ยนผู้แทน",
"change_rep_message": "คุณแน่ใจหรือไม่ว่าต้องการเปลี่ยนตัวแทน",
"unsupported_asset": "เราไม่สนับสนุนการกระทำนี้สำหรับเนื้อหานี้ โปรดสร้างหรือเปลี่ยนเป็นกระเป๋าเงินประเภทสินทรัพย์ที่รองรับ",
"manage_pow_nodes": "จัดการโหนด PoW"
"manage_pow_nodes": "จัดการโหนด PoW",
"support_title_live_chat": "การสนับสนุนสด",
"support_description_live_chat": "ฟรีและรวดเร็ว! ตัวแทนฝ่ายสนับสนุนที่ผ่านการฝึกอบรมพร้อมให้ความช่วยเหลือ",
"support_title_guides": "คู่มือกระเป๋าเงินเค้ก",
"support_description_guides": "เอกสารและการสนับสนุนสำหรับปัญหาทั่วไป",
"support_title_other_links": "ลิงค์สนับสนุนอื่น ๆ",
"support_description_other_links": "เข้าร่วมชุมชนของเราหรือเข้าถึงเราพันธมิตรของเราผ่านวิธีการอื่น ๆ"
}

View file

@ -674,5 +674,11 @@
"change_rep": "Temsilciyi Değiştir",
"change_rep_message": "Temsilcileri değiştirmek istediğinizden emin misiniz?",
"unsupported_asset": "Bu öğe için bu eylemi desteklemiyoruz. Lütfen desteklenen bir varlık türünde bir cüzdan oluşturun veya cüzdana geçiş yapın.",
"manage_pow_nodes": "PoW Düğümlerini Yönet"
"manage_pow_nodes": "PoW Düğümlerini Yönet",
"support_title_live_chat": "Canlı destek",
"support_description_live_chat": "Ücretsiz ve hızlı! Eğitimli destek temsilcileri yardımcı olmak için mevcuttur",
"support_title_guides": "Kek Cüzdan Kılavuzları",
"support_description_guides": "Ortak sorunlara belge ve destek",
"support_title_other_links": "Diğer destek bağlantıları",
"support_description_other_links": "Topluluklarımıza katılın veya ortaklarımıza diğer yöntemlerle bize ulaşın"
}

View file

@ -676,5 +676,11 @@
"change_rep": "Зміна представника",
"change_rep_message": "Ви впевнені, що хочете змінити представника?",
"unsupported_asset": "Ми не підтримуємо цю дію для цього ресурсу. Створіть або перейдіть на гаманець підтримуваного типу активів.",
"manage_pow_nodes": "Керуйте вузлами PoW"
"manage_pow_nodes": "Керуйте вузлами PoW",
"support_title_live_chat": "Жива підтримка",
"support_description_live_chat": "Безкоштовно і швидко! Навчені представники підтримки доступні для надання допомоги",
"support_title_guides": "Поклики для гаманців тортів",
"support_description_guides": "Документація та підтримка загальних питань",
"support_title_other_links": "Інші посилання на підтримку",
"support_description_other_links": "Приєднуйтесь до наших спільнот або досягайте нас нашими партнерами іншими методами"
}

View file

@ -667,6 +667,12 @@
"template_name": "ٹیمپلیٹ کا نام",
"change_rep": "۔ﮟﯾﺮﮐ ﻞﯾﺪﺒﺗ ﮦﺪﻨﺋﺎﻤﻧ",
"change_rep_message": "؟ﮟﯿﮨ ﮯﺘﮨﺎﭼ ﺎﻧﺮﮐ ﻞﯾﺪﺒﺗ ﻮﮐ ﮞﻭﺪﻨﺋﺎﻤﻧ ﯽﻌﻗﺍﻭ ﭖﺁ ﺎﯿﮐ",
"unsupported_asset": " ۔ﮟﯾﺮﮐ ﭻﺋﻮﺳ ﺮﭘ ﺱﺍ ﺎﯾ ﮟﯿﺋﺎﻨﺑ ﺱﺮﭘ ﺎﮐ ﻢﺴﻗ ﯽﮐ ﮧﺛﺎﺛﺍ ﮧﺘﻓﺎﯾ ﻥﻭﺎﻌﺗ ﻡﺮﮐ ﮦﺍﺮﺑ ۔ﮟﯿﮨ ﮯﺗﺮﮐ ﮟﯿﮩﻧ ﺖﯾﺎﻤﺣ ﯽﮐ ﯽﺋﺍﻭﺭﺭﺎﮐ ﺱﺍ ﮯﯿﻟ ﮯﮐ ﮧﺛﺎﺛﺍ ﺱﺍ ﻢﮨ",
"manage_pow_nodes": "PoW ۔ﮟﯾﺮﮐ ﻢﻈﻧ ﺎﮐ ﺱﮈﻮﻧ"
"unsupported_asset": "۔ﮟﯾﺮﮐ ﭻﺋﻮﺳ ﺮﭘ ﺱﺍ ﺎﯾ ﮟﯿﺋﺎﻨﺑ ﺱﺮﭘ ﺎﮐ ﻢﺴﻗ ﯽﮐ ﮧﺛﺎﺛﺍ ﮧﺘﻓﺎﯾ ﻥﻭﺎﻌﺗ ﻡﺮﮐ ﮦﺍﺮﺑ ۔ﮟﯿﮨ ﮯﺗﺮﮐ ﮟﯿﮩﻧ ﺖﯾﺎﻤﺣ ﯽﮐ ﯽﺋﺍﻭﺭﺭﺎﮐ ﺱﺍ ﮯﯿﻟ ﮯﮐ ﮧﺛﺎﺛﺍ ﺱﺍ ﻢﮨ",
"manage_pow_nodes": "PoW ۔ﮟﯾﺮﮐ ﻢﻈﻧ ﺎﮐ ﺱﮈﻮﻧ",
"support_title_live_chat": "براہ راست مدد",
"support_description_live_chat": "مفت اور تیز! تربیت یافتہ معاون نمائندے مدد کے لئے دستیاب ہیں",
"support_title_guides": "کیک پرس گائڈز",
"support_description_guides": "عام مسائل کے لئے دستاویزات اور مدد",
"support_title_other_links": "دوسرے سپورٹ لنکس",
"support_description_other_links": "ہماری برادریوں میں شامل ہوں یا دوسرے طریقوں سے ہمارے شراکت داروں تک پہنچیں"
}

View file

@ -670,5 +670,11 @@
"change_rep": "Yi Aṣoju",
"change_rep_message": "Ṣe o da ọ loju pe o fẹ yi awọn aṣoju pada?",
"unsupported_asset": "A ko ṣe atilẹyin iṣẹ yii fun dukia yii. Jọwọ ṣẹda tabi yipada si apamọwọ iru dukia atilẹyin.",
"manage_pow_nodes": "Ṣakoso awọn Nodes PoW"
"manage_pow_nodes": "Ṣakoso awọn Nodes PoW",
"support_title_live_chat": "Atilẹyin ifiwe",
"support_description_live_chat": "Free ati sare! Ti oṣiṣẹ awọn aṣoju wa lati ṣe iranlọwọ",
"support_title_guides": "Akara oyinbo Awọn Itọsọna Awọki oyinbo",
"support_description_guides": "Iwe ati atilẹyin fun awọn ọran ti o wọpọ",
"support_title_other_links": "Awọn ọna asopọ atilẹyin miiran",
"support_description_other_links": "Darapọ mọ awọn agbegbe wa tabi de wa awọn alabaṣepọ wa nipasẹ awọn ọna miiran"
}

View file

@ -675,5 +675,11 @@
"change_rep": "变革代表",
"change_rep_message": "您确定要更换代表吗?",
"unsupported_asset": "我们不支持针对该资产采取此操作。请创建或切换到支持的资产类型的钱包。",
"manage_pow_nodes": "管理 PoW 节点"
"manage_pow_nodes": "管理 PoW 节点",
"support_title_live_chat": "实时支持",
"support_description_live_chat": "免费快速!训练有素的支持代表可以协助",
"support_title_guides": "蛋糕钱包指南",
"support_description_guides": "对常见问题的文档和支持",
"support_title_other_links": "其他支持链接",
"support_description_other_links": "加入我们的社区或通过其他方法与我们联系我们的合作伙伴"
}

View file

@ -0,0 +1,66 @@
import 'dart:convert';
import 'dart:io';
import 'package:translator/translator.dart';
const defaultLang = "en";
const langs = [
"ar", "bg", "cs", "de", "en", "es", "fr", "ha", "hi", "hr", "id", "it",
"ja", "ko", "my", "nl", "pl", "pt", "ru", "th", "tr", "uk", "ur", "yo",
"zh-cn" // zh, but Google Translate uses zh-cn for Chinese (Simplified)
];
final translator = GoogleTranslator();
void main(List<String> args) async {
if (args.length != 2) {
throw Exception(
'Insufficient arguments!\n\nTry to run `./append_translation.dart greetings "Hello World!"`');
}
final name = args.first;
final text = args.last;
print('Appending "$name": "$text"');
for (var lang in langs) {
final fileName = getFileName(lang);
final translation = await getTranslation(text, lang);
appendArbFile(fileName, name, translation);
}
}
void appendArbFile(String fileName, String name, String text) {
final file = File(fileName);
final inputContent = file.readAsStringSync();
final arbObj = json.decode(inputContent) as Map<String, dynamic>;
if (arbObj.containsKey(name)) {
print("String $name already exists in $fileName!");
return;
}
arbObj.addAll({name: text});
final outputContent = json
.encode(arbObj)
.replaceAll('","', '",\n "')
.replaceAll('{"', '{\n "')
.replaceAll('"}', '"\n}')
.replaceAll('":"', '": "');
file.writeAsStringSync(outputContent);
}
Future<String> getTranslation(String text, String lang) async {
if (lang == defaultLang) return text;
return (await translator.translate(text, from: defaultLang, to: lang)).text;
}
String getFileName(String lang) {
final shortLang = lang
.split("-")
.first;
return "./res/values/strings_$shortLang.arb";
}

View file

@ -33,8 +33,7 @@ Future<void> updateSecretsConfig(List<String> args) async {
});
final fileConfig =
json.decode(configFile.readAsStringSync()) as Map<String, dynamic> ??
<String, dynamic>{};
json.decode(configFile.readAsStringSync()) as Map<String, dynamic>;
fileConfig.forEach((key, dynamic value) {
if (secrets[key] == null) {
secrets[key] = value;

View file

@ -31,6 +31,7 @@ class SecretKey {
SecretKey('anonPayReferralCode', () => ''),
SecretKey('fiatApiKey', () => ''),
SecretKey('payfuraApiKey', () => ''),
SecretKey('chatwootWebsiteToken', () => ''),
];
static final ethereumSecrets = [