mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2025-03-12 09:32:33 +00:00
Merge branch 'cw-linux' into CW-385-linux-change-wallet-screen-not-responding
This commit is contained in:
commit
254aeceafe
122 changed files with 2290 additions and 1242 deletions
3
.github/workflows/pr_test_build.yml
vendored
3
.github/workflows/pr_test_build.yml
vendored
|
@ -55,7 +55,7 @@ jobs:
|
|||
/opt/android/cake_wallet/cw_monero/android/.cxx
|
||||
/opt/android/cake_wallet/cw_monero/ios/External
|
||||
/opt/android/cake_wallet/cw_shared_external/ios/External
|
||||
key: ${{ hashFiles('**/build_monero.sh', '**/build_haven.sh') }}
|
||||
key: ${{ hashFiles('**/build_monero.sh', '**/build_haven.sh', '**/monero_api.cpp') }}
|
||||
|
||||
- if: ${{ steps.cache-externals.outputs.cache-hit != 'true' }}
|
||||
name: Generate Externals
|
||||
|
@ -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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
class BitcoinTransactionNoInputsException implements Exception {
|
||||
@override
|
||||
String toString() => 'Not enough inputs available';
|
||||
String toString() => 'Not enough inputs available. Please select more under Coin Control';
|
||||
}
|
||||
|
|
|
@ -2,24 +2,31 @@ import 'package:cw_core/balance.dart';
|
|||
import 'package:cw_core/monero_amount_format.dart';
|
||||
|
||||
class MoneroBalance extends Balance {
|
||||
MoneroBalance({required this.fullBalance, required this.unlockedBalance})
|
||||
MoneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0})
|
||||
: formattedFullBalance = moneroAmountToString(amount: fullBalance),
|
||||
formattedUnlockedBalance =
|
||||
moneroAmountToString(amount: unlockedBalance),
|
||||
formattedUnlockedBalance = moneroAmountToString(amount: unlockedBalance),
|
||||
frozenFormatted = moneroAmountToString(amount: frozenBalance),
|
||||
super(unlockedBalance, fullBalance);
|
||||
|
||||
MoneroBalance.fromString(
|
||||
{required this.formattedFullBalance,
|
||||
required this.formattedUnlockedBalance})
|
||||
required this.formattedUnlockedBalance,
|
||||
this.frozenFormatted = '0.0'})
|
||||
: fullBalance = moneroParseAmount(amount: formattedFullBalance),
|
||||
unlockedBalance = moneroParseAmount(amount: formattedUnlockedBalance),
|
||||
frozenBalance = moneroParseAmount(amount: frozenFormatted),
|
||||
super(moneroParseAmount(amount: formattedUnlockedBalance),
|
||||
moneroParseAmount(amount: formattedFullBalance));
|
||||
|
||||
final int fullBalance;
|
||||
final int unlockedBalance;
|
||||
final int frozenBalance;
|
||||
final String formattedFullBalance;
|
||||
final String formattedUnlockedBalance;
|
||||
final String frozenFormatted;
|
||||
|
||||
@override
|
||||
String get formattedFrozenBalance => frozenFormatted == '0.0' ? '' : frozenFormatted;
|
||||
|
||||
@override
|
||||
String get formattedAvailableBalance => formattedUnlockedBalance;
|
||||
|
|
|
@ -12,7 +12,9 @@ class UnspentCoinsInfo extends HiveObject {
|
|||
required this.noteRaw,
|
||||
required this.address,
|
||||
required this.vout,
|
||||
required this.value});
|
||||
required this.value,
|
||||
this.keyImage = null
|
||||
});
|
||||
|
||||
static const typeId = 9;
|
||||
static const boxName = 'Unspent';
|
||||
|
@ -42,6 +44,9 @@ class UnspentCoinsInfo extends HiveObject {
|
|||
@HiveField(7, defaultValue: 0)
|
||||
int vout;
|
||||
|
||||
@HiveField(8, defaultValue: null)
|
||||
String? keyImage;
|
||||
|
||||
String get note => noteRaw ?? '';
|
||||
|
||||
set note(String value) => noteRaw = value;
|
||||
|
|
|
@ -42,7 +42,9 @@ abstract class WalletBase<
|
|||
|
||||
set syncStatus(SyncStatus status);
|
||||
|
||||
String get seed;
|
||||
String? get seed;
|
||||
|
||||
String? get privateKey => null;
|
||||
|
||||
Object get keys;
|
||||
|
||||
|
|
|
@ -44,13 +44,15 @@ abstract class EthereumWalletBase
|
|||
with Store {
|
||||
EthereumWalletBase({
|
||||
required WalletInfo walletInfo,
|
||||
required String mnemonic,
|
||||
String? mnemonic,
|
||||
String? privateKey,
|
||||
required String password,
|
||||
required EncryptionFileUtils encryptionFileUtils,
|
||||
ERC20Balance? initialBalance,
|
||||
}) : syncStatus = NotConnectedSyncStatus(),
|
||||
_password = password,
|
||||
_mnemonic = mnemonic,
|
||||
_hexPrivateKey = privateKey,
|
||||
_isTransactionUpdating = false,
|
||||
_encryptionFileUtils = encryptionFileUtils,
|
||||
_client = EthereumClient(),
|
||||
|
@ -72,14 +74,15 @@ abstract class EthereumWalletBase
|
|||
_sharedPrefs.complete(SharedPreferences.getInstance());
|
||||
}
|
||||
|
||||
final String _mnemonic;
|
||||
final String? _mnemonic;
|
||||
final String? _hexPrivateKey;
|
||||
final String _password;
|
||||
|
||||
final EncryptionFileUtils _encryptionFileUtils;
|
||||
|
||||
late final Box<Erc20Token> erc20TokensBox;
|
||||
|
||||
late final EthPrivateKey _privateKey;
|
||||
late final EthPrivateKey _ethPrivateKey;
|
||||
|
||||
late EthereumClient _client;
|
||||
|
||||
|
@ -107,8 +110,12 @@ abstract class EthereumWalletBase
|
|||
erc20TokensBox = await Hive.openBox<Erc20Token>(Erc20Token.boxName);
|
||||
await walletAddresses.init();
|
||||
await transactionHistory.init();
|
||||
_privateKey = await getPrivateKey(_mnemonic, _password);
|
||||
walletAddresses.address = _privateKey.address.toString();
|
||||
_ethPrivateKey = await getPrivateKey(
|
||||
mnemonic: _mnemonic,
|
||||
privateKey: _hexPrivateKey,
|
||||
password: _password,
|
||||
);
|
||||
walletAddresses.address = _ethPrivateKey.address.toString();
|
||||
await save();
|
||||
}
|
||||
|
||||
|
@ -116,8 +123,7 @@ abstract class EthereumWalletBase
|
|||
int calculateEstimatedFee(TransactionPriority priority, int? amount) {
|
||||
try {
|
||||
if (priority is EthereumTransactionPriority) {
|
||||
final priorityFee =
|
||||
EtherAmount.fromUnitAndValue(EtherUnit.gwei, priority.tip).getInWei.toInt();
|
||||
final priorityFee = EtherAmount.fromInt(EtherUnit.gwei, priority.tip).getInWei.toInt();
|
||||
return (_gasPrice! + priorityFee) * (_estimatedGas ?? 0);
|
||||
}
|
||||
|
||||
|
@ -150,7 +156,7 @@ abstract class EthereumWalletBase
|
|||
throw Exception("Ethereum Node connection failed");
|
||||
}
|
||||
|
||||
_client.setListeners(_privateKey.address, _onNewTransaction);
|
||||
_client.setListeners(_ethPrivateKey.address, _onNewTransaction);
|
||||
|
||||
_setTransactionUpdateTimer();
|
||||
|
||||
|
@ -210,7 +216,7 @@ abstract class EthereumWalletBase
|
|||
}
|
||||
|
||||
final pendingEthereumTransaction = await _client.signTransaction(
|
||||
privateKey: _privateKey,
|
||||
privateKey: _ethPrivateKey,
|
||||
toAddress: _credentials.outputs.first.isParsedAddress
|
||||
? _credentials.outputs.first.extractedAddress!
|
||||
: _credentials.outputs.first.address,
|
||||
|
@ -248,7 +254,7 @@ abstract class EthereumWalletBase
|
|||
|
||||
@override
|
||||
Future<Map<String, EthereumTransactionInfo>> fetchTransactions() async {
|
||||
final address = _privateKey.address.hex;
|
||||
final address = _ethPrivateKey.address.hex;
|
||||
final transactions = await _client.fetchTransactions(address);
|
||||
|
||||
final List<Future<List<EthereumTransactionModel>>> erc20TokensTransactions = [];
|
||||
|
@ -308,7 +314,10 @@ abstract class EthereumWalletBase
|
|||
}
|
||||
|
||||
@override
|
||||
String get seed => _mnemonic;
|
||||
String? get seed => _mnemonic;
|
||||
|
||||
@override
|
||||
String get privateKey => HEX.encode(_ethPrivateKey.privateKey);
|
||||
|
||||
@action
|
||||
@override
|
||||
|
@ -335,6 +344,7 @@ abstract class EthereumWalletBase
|
|||
|
||||
String toJSON() => json.encode({
|
||||
'mnemonic': _mnemonic,
|
||||
'private_key': privateKey,
|
||||
'balance': balance[currency]!.toJSON(),
|
||||
});
|
||||
|
||||
|
@ -347,13 +357,15 @@ abstract class EthereumWalletBase
|
|||
final path = await pathForWallet(name: name, type: walletInfo.type);
|
||||
final jsonSource = await encryptionFileUtils.read(path: path, password: password);
|
||||
final data = json.decode(jsonSource) as Map;
|
||||
final mnemonic = data['mnemonic'] as String;
|
||||
final mnemonic = data['mnemonic'] as String?;
|
||||
final privateKey = data['private_key'] as String?;
|
||||
final balance = ERC20Balance.fromJSON(data['balance'] as String) ?? ERC20Balance(BigInt.zero);
|
||||
|
||||
return EthereumWallet(
|
||||
walletInfo: walletInfo,
|
||||
password: password,
|
||||
mnemonic: mnemonic,
|
||||
privateKey: privateKey,
|
||||
initialBalance: balance,
|
||||
encryptionFileUtils: encryptionFileUtils,
|
||||
);
|
||||
|
@ -367,7 +379,7 @@ abstract class EthereumWalletBase
|
|||
}
|
||||
|
||||
Future<ERC20Balance> _fetchEthBalance() async {
|
||||
final balance = await _client.getBalance(_privateKey.address);
|
||||
final balance = await _client.getBalance(_ethPrivateKey.address);
|
||||
return ERC20Balance(balance.getInWei);
|
||||
}
|
||||
|
||||
|
@ -376,7 +388,7 @@ abstract class EthereumWalletBase
|
|||
try {
|
||||
if (token.enabled) {
|
||||
balance[token] = await _client.fetchERC20Balances(
|
||||
_privateKey.address,
|
||||
_ethPrivateKey.address,
|
||||
token.contractAddress,
|
||||
);
|
||||
} else {
|
||||
|
@ -386,8 +398,15 @@ abstract class EthereumWalletBase
|
|||
}
|
||||
}
|
||||
|
||||
Future<EthPrivateKey> getPrivateKey(String mnemonic, String password) async {
|
||||
final seed = bip39.mnemonicToSeed(mnemonic);
|
||||
Future<EthPrivateKey> getPrivateKey(
|
||||
{String? mnemonic, String? privateKey, required String password}) async {
|
||||
assert(mnemonic != null || privateKey != null);
|
||||
|
||||
if (privateKey != null) {
|
||||
return EthPrivateKey.fromHex(privateKey);
|
||||
}
|
||||
|
||||
final seed = bip39.mnemonicToSeed(mnemonic!);
|
||||
|
||||
final root = bip32.BIP32.fromSeed(seed);
|
||||
|
||||
|
@ -423,7 +442,7 @@ abstract class EthereumWalletBase
|
|||
|
||||
if (_token.enabled) {
|
||||
balance[_token] = await _client.fetchERC20Balances(
|
||||
_privateKey.address,
|
||||
_ethPrivateKey.address,
|
||||
_token.contractAddress,
|
||||
);
|
||||
} else {
|
||||
|
|
|
@ -8,16 +8,22 @@ class EthereumNewWalletCredentials extends WalletCredentials {
|
|||
|
||||
class EthereumRestoreWalletFromSeedCredentials extends WalletCredentials {
|
||||
EthereumRestoreWalletFromSeedCredentials(
|
||||
{required String name, required String password, required this.mnemonic, WalletInfo? walletInfo})
|
||||
{required String name,
|
||||
required String password,
|
||||
required this.mnemonic,
|
||||
WalletInfo? walletInfo})
|
||||
: super(name: name, password: password, walletInfo: walletInfo);
|
||||
|
||||
final String mnemonic;
|
||||
}
|
||||
|
||||
class EthereumRestoreWalletFromWIFCredentials extends WalletCredentials {
|
||||
EthereumRestoreWalletFromWIFCredentials(
|
||||
{required String name, required String password, required this.wif, WalletInfo? walletInfo})
|
||||
class EthereumRestoreWalletFromPrivateKey extends WalletCredentials {
|
||||
EthereumRestoreWalletFromPrivateKey(
|
||||
{required String name,
|
||||
required String password,
|
||||
required this.privateKey,
|
||||
WalletInfo? walletInfo})
|
||||
: super(name: name, password: password, walletInfo: walletInfo);
|
||||
|
||||
final String wif;
|
||||
final String privateKey;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import 'package:bip39/bip39.dart' as bip39;
|
|||
import 'package:collection/collection.dart';
|
||||
|
||||
class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
|
||||
EthereumRestoreWalletFromSeedCredentials, EthereumRestoreWalletFromWIFCredentials> {
|
||||
EthereumRestoreWalletFromSeedCredentials, EthereumRestoreWalletFromPrivateKey> {
|
||||
EthereumWalletService(this.walletInfoSource, this.isDirect);
|
||||
|
||||
final Box<WalletInfo> walletInfoSource;
|
||||
|
@ -70,8 +70,18 @@ class EthereumWalletService extends WalletService<EthereumNewWalletCredentials,
|
|||
}
|
||||
|
||||
@override
|
||||
Future<EthereumWallet> restoreFromKeys(credentials) {
|
||||
throw UnimplementedError();
|
||||
Future<EthereumWallet> restoreFromKeys(EthereumRestoreWalletFromPrivateKey credentials) async {
|
||||
final wallet = EthereumWallet(
|
||||
password: credentials.password!,
|
||||
privateKey: credentials.privateKey,
|
||||
walletInfo: credentials.walletInfo!,
|
||||
);
|
||||
|
||||
await wallet.init();
|
||||
wallet.addInitialTokens();
|
||||
await wallet.save();
|
||||
|
||||
return wallet;
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <fstream>
|
||||
#include <unistd.h>
|
||||
#include <mutex>
|
||||
#include <list>
|
||||
#include "thread"
|
||||
#include "CwWalletListener.h"
|
||||
#if __APPLE__
|
||||
|
@ -189,6 +190,62 @@ extern "C"
|
|||
}
|
||||
};
|
||||
|
||||
struct CoinsInfoRow
|
||||
{
|
||||
uint64_t blockHeight;
|
||||
char *hash;
|
||||
uint64_t internalOutputIndex;
|
||||
uint64_t globalOutputIndex;
|
||||
bool spent;
|
||||
bool frozen;
|
||||
uint64_t spentHeight;
|
||||
uint64_t amount;
|
||||
bool rct;
|
||||
bool keyImageKnown;
|
||||
uint64_t pkIndex;
|
||||
uint32_t subaddrIndex;
|
||||
uint32_t subaddrAccount;
|
||||
char *address;
|
||||
char *addressLabel;
|
||||
char *keyImage;
|
||||
uint64_t unlockTime;
|
||||
bool unlocked;
|
||||
char *pubKey;
|
||||
bool coinbase;
|
||||
char *description;
|
||||
|
||||
CoinsInfoRow(Monero::CoinsInfo *coinsInfo)
|
||||
{
|
||||
blockHeight = coinsInfo->blockHeight();
|
||||
std::string *hash_str = new std::string(coinsInfo->hash());
|
||||
hash = strdup(hash_str->c_str());
|
||||
internalOutputIndex = coinsInfo->internalOutputIndex();
|
||||
globalOutputIndex = coinsInfo->globalOutputIndex();
|
||||
spent = coinsInfo->spent();
|
||||
frozen = coinsInfo->frozen();
|
||||
spentHeight = coinsInfo->spentHeight();
|
||||
amount = coinsInfo->amount();
|
||||
rct = coinsInfo->rct();
|
||||
keyImageKnown = coinsInfo->keyImageKnown();
|
||||
pkIndex = coinsInfo->pkIndex();
|
||||
subaddrIndex = coinsInfo->subaddrIndex();
|
||||
subaddrAccount = coinsInfo->subaddrAccount();
|
||||
address = strdup(coinsInfo->address().c_str()) ;
|
||||
addressLabel = strdup(coinsInfo->addressLabel().c_str());
|
||||
keyImage = strdup(coinsInfo->keyImage().c_str());
|
||||
unlockTime = coinsInfo->unlockTime();
|
||||
unlocked = coinsInfo->unlocked();
|
||||
pubKey = strdup(coinsInfo->pubKey().c_str());
|
||||
coinbase = coinsInfo->coinbase();
|
||||
description = strdup(coinsInfo->description().c_str());
|
||||
}
|
||||
|
||||
void setUnlocked(bool unlocked);
|
||||
|
||||
};
|
||||
|
||||
Monero::Coins *m_coins;
|
||||
|
||||
Monero::Wallet *m_wallet;
|
||||
Monero::TransactionHistory *m_transaction_history;
|
||||
MoneroWalletListener *m_listener;
|
||||
|
@ -196,6 +253,7 @@ extern "C"
|
|||
Monero::SubaddressAccount *m_account;
|
||||
uint64_t m_last_known_wallet_height;
|
||||
uint64_t m_cached_syncing_blockchain_height = 0;
|
||||
std::list<Monero::CoinsInfo*> m_coins_info;
|
||||
std::mutex store_lock;
|
||||
bool is_storing = false;
|
||||
|
||||
|
@ -232,6 +290,17 @@ extern "C"
|
|||
{
|
||||
m_subaddress = nullptr;
|
||||
}
|
||||
|
||||
m_coins_info = std::list<Monero::CoinsInfo*>();
|
||||
|
||||
if (wallet != nullptr)
|
||||
{
|
||||
m_coins = wallet->coins();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_coins = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Monero::Wallet *get_current_wallet()
|
||||
|
@ -520,10 +589,19 @@ extern "C"
|
|||
|
||||
FUNCTION_VISABILITY_ATTRIBUTE
|
||||
bool transaction_create(char *address, char *payment_id, char *amount,
|
||||
uint8_t priority_raw, uint32_t subaddr_account, Utf8Box &error, PendingTransactionRaw &pendingTransaction)
|
||||
uint8_t priority_raw, uint32_t subaddr_account,
|
||||
char **preferred_inputs, uint32_t preferred_inputs_size,
|
||||
Utf8Box &error, PendingTransactionRaw &pendingTransaction)
|
||||
{
|
||||
nice(19);
|
||||
|
||||
std::set<std::string> _preferred_inputs;
|
||||
|
||||
for (int i = 0; i < preferred_inputs_size; i++) {
|
||||
_preferred_inputs.insert(std::string(*preferred_inputs));
|
||||
preferred_inputs++;
|
||||
}
|
||||
|
||||
auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw);
|
||||
std::string _payment_id;
|
||||
Monero::PendingTransaction *transaction;
|
||||
|
@ -536,11 +614,11 @@ extern "C"
|
|||
if (amount != nullptr)
|
||||
{
|
||||
uint64_t _amount = Monero::Wallet::amountFromString(std::string(amount));
|
||||
transaction = m_wallet->createTransaction(std::string(address), _payment_id, _amount, m_wallet->defaultMixin(), priority, subaddr_account);
|
||||
transaction = m_wallet->createTransaction(std::string(address), _payment_id, _amount, m_wallet->defaultMixin(), priority, subaddr_account, {}, _preferred_inputs);
|
||||
}
|
||||
else
|
||||
{
|
||||
transaction = m_wallet->createTransaction(std::string(address), _payment_id, Monero::optional<uint64_t>(), m_wallet->defaultMixin(), priority, subaddr_account);
|
||||
transaction = m_wallet->createTransaction(std::string(address), _payment_id, Monero::optional<uint64_t>(), m_wallet->defaultMixin(), priority, subaddr_account, {}, _preferred_inputs);
|
||||
}
|
||||
|
||||
int status = transaction->status();
|
||||
|
@ -561,7 +639,9 @@ extern "C"
|
|||
|
||||
FUNCTION_VISABILITY_ATTRIBUTE
|
||||
bool transaction_create_mult_dest(char **addresses, char *payment_id, char **amounts, uint32_t size,
|
||||
uint8_t priority_raw, uint32_t subaddr_account, Utf8Box &error, PendingTransactionRaw &pendingTransaction)
|
||||
uint8_t priority_raw, uint32_t subaddr_account,
|
||||
char **preferred_inputs, uint32_t preferred_inputs_size,
|
||||
Utf8Box &error, PendingTransactionRaw &pendingTransaction)
|
||||
{
|
||||
nice(19);
|
||||
|
||||
|
@ -575,6 +655,13 @@ extern "C"
|
|||
amounts++;
|
||||
}
|
||||
|
||||
std::set<std::string> _preferred_inputs;
|
||||
|
||||
for (int i = 0; i < preferred_inputs_size; i++) {
|
||||
_preferred_inputs.insert(std::string(*preferred_inputs));
|
||||
preferred_inputs++;
|
||||
}
|
||||
|
||||
auto priority = static_cast<Monero::PendingTransaction::Priority>(priority_raw);
|
||||
std::string _payment_id;
|
||||
Monero::PendingTransaction *transaction;
|
||||
|
@ -861,6 +948,91 @@ extern "C"
|
|||
return m_wallet->trustedDaemon();
|
||||
}
|
||||
|
||||
CoinsInfoRow* coin(int index)
|
||||
{
|
||||
if (index >= 0 && index < m_coins_info.size()) {
|
||||
std::list<Monero::CoinsInfo*>::iterator it = m_coins_info.begin();
|
||||
std::advance(it, index);
|
||||
Monero::CoinsInfo* element = *it;
|
||||
std::cout << "Element at index " << index << ": " << element << std::endl;
|
||||
return new CoinsInfoRow(element);
|
||||
} else {
|
||||
std::cout << "Invalid index." << std::endl;
|
||||
return nullptr; // Return a default value (nullptr) for invalid index
|
||||
}
|
||||
}
|
||||
|
||||
void refresh_coins(uint32_t accountIndex)
|
||||
{
|
||||
m_coins_info.clear();
|
||||
|
||||
m_coins->refresh();
|
||||
for (const auto i : m_coins->getAll()) {
|
||||
if (i->subaddrAccount() == accountIndex && !(i->spent())) {
|
||||
m_coins_info.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t coins_count()
|
||||
{
|
||||
return m_coins_info.size();
|
||||
}
|
||||
|
||||
CoinsInfoRow** coins_from_account(uint32_t accountIndex)
|
||||
{
|
||||
std::vector<CoinsInfoRow*> matchingCoins;
|
||||
|
||||
for (int i = 0; i < coins_count(); i++) {
|
||||
CoinsInfoRow* coinInfo = coin(i);
|
||||
if (coinInfo->subaddrAccount == accountIndex) {
|
||||
matchingCoins.push_back(coinInfo);
|
||||
}
|
||||
}
|
||||
|
||||
CoinsInfoRow** result = new CoinsInfoRow*[matchingCoins.size()];
|
||||
std::copy(matchingCoins.begin(), matchingCoins.end(), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
CoinsInfoRow** coins_from_txid(const char* txid, size_t* count)
|
||||
{
|
||||
std::vector<CoinsInfoRow*> matchingCoins;
|
||||
|
||||
for (int i = 0; i < coins_count(); i++) {
|
||||
CoinsInfoRow* coinInfo = coin(i);
|
||||
if (std::string(coinInfo->hash) == txid) {
|
||||
matchingCoins.push_back(coinInfo);
|
||||
}
|
||||
}
|
||||
|
||||
*count = matchingCoins.size();
|
||||
CoinsInfoRow** result = new CoinsInfoRow*[*count];
|
||||
std::copy(matchingCoins.begin(), matchingCoins.end(), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
CoinsInfoRow** coins_from_key_image(const char** keyimages, size_t keyimageCount, size_t* count)
|
||||
{
|
||||
std::vector<CoinsInfoRow*> matchingCoins;
|
||||
|
||||
for (int i = 0; i < coins_count(); i++) {
|
||||
CoinsInfoRow* coinsInfoRow = coin(i);
|
||||
for (size_t j = 0; j < keyimageCount; j++) {
|
||||
if (coinsInfoRow->keyImageKnown && std::string(coinsInfoRow->keyImage) == keyimages[j]) {
|
||||
matchingCoins.push_back(coinsInfoRow);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*count = matchingCoins.size();
|
||||
CoinsInfoRow** result = new CoinsInfoRow*[*count];
|
||||
std::copy(matchingCoins.begin(), matchingCoins.end(), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
23
cw_monero/lib/api/coins_info.dart
Normal file
23
cw_monero/lib/api/coins_info.dart
Normal file
|
@ -0,0 +1,23 @@
|
|||
import 'dart:ffi';
|
||||
import 'package:cw_monero/api/signatures.dart';
|
||||
import 'package:cw_monero/api/structs/coins_info_row.dart';
|
||||
import 'package:cw_monero/api/types.dart';
|
||||
import 'package:cw_monero/api/monero_api.dart';
|
||||
|
||||
final refreshCoinsNative = moneroApi
|
||||
.lookup<NativeFunction<refresh_coins>>('refresh_coins')
|
||||
.asFunction<RefreshCoins>();
|
||||
|
||||
final coinsCountNative = moneroApi
|
||||
.lookup<NativeFunction<coins_count>>('coins_count')
|
||||
.asFunction<CoinsCount>();
|
||||
|
||||
final coinNative = moneroApi
|
||||
.lookup<NativeFunction<coin>>('coin')
|
||||
.asFunction<GetCoin>();
|
||||
|
||||
void refreshCoins(int accountIndex) => refreshCoinsNative(accountIndex);
|
||||
|
||||
int countOfCoins() => coinsCountNative();
|
||||
|
||||
CoinsInfoRow getCoin(int index) => coinNative(index).ref;
|
|
@ -1,4 +1,5 @@
|
|||
import 'dart:ffi';
|
||||
import 'package:cw_monero/api/structs/coins_info_row.dart';
|
||||
import 'package:cw_monero/api/structs/pending_transaction.dart';
|
||||
import 'package:cw_monero/api/structs/ut8_box.dart';
|
||||
import 'package:ffi/ffi.dart';
|
||||
|
@ -9,8 +10,8 @@ typedef create_wallet = Int8 Function(
|
|||
typedef restore_wallet_from_seed = Int8 Function(
|
||||
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);
|
||||
|
||||
typedef restore_wallet_from_keys = Int8 Function(Pointer<Utf8>, Pointer<Utf8>,
|
||||
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);
|
||||
typedef restore_wallet_from_keys = Int8 Function(Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>,
|
||||
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);
|
||||
|
||||
typedef is_wallet_exist = Int8 Function(Pointer<Utf8>);
|
||||
|
||||
|
@ -63,8 +64,7 @@ typedef subaddrress_refresh = Void Function(Int32);
|
|||
|
||||
typedef subaddress_get_all = Pointer<Int64> Function();
|
||||
|
||||
typedef subaddress_add_new = Void Function(
|
||||
Int32 accountIndex, Pointer<Utf8> label);
|
||||
typedef subaddress_add_new = Void Function(Int32 accountIndex, Pointer<Utf8> label);
|
||||
|
||||
typedef subaddress_set_label = Void Function(
|
||||
Int32 accountIndex, Int32 addressIndex, Pointer<Utf8> label);
|
||||
|
@ -77,8 +77,7 @@ typedef account_get_all = Pointer<Int64> Function();
|
|||
|
||||
typedef account_add_new = Void Function(Pointer<Utf8> label);
|
||||
|
||||
typedef account_set_label = Void Function(
|
||||
Int32 accountIndex, Pointer<Utf8> label);
|
||||
typedef account_set_label = Void Function(Int32 accountIndex, Pointer<Utf8> label);
|
||||
|
||||
typedef transactions_refresh = Void Function();
|
||||
|
||||
|
@ -94,6 +93,8 @@ typedef transaction_create = Int8 Function(
|
|||
Pointer<Utf8> amount,
|
||||
Int8 priorityRaw,
|
||||
Int32 subaddrAccount,
|
||||
Pointer<Pointer<Utf8>> preferredInputs,
|
||||
Int32 preferredInputsSize,
|
||||
Pointer<Utf8Box> error,
|
||||
Pointer<PendingTransactionRaw> pendingTransaction);
|
||||
|
||||
|
@ -104,6 +105,8 @@ typedef transaction_create_mult_dest = Int8 Function(
|
|||
Int32 size,
|
||||
Int8 priorityRaw,
|
||||
Int32 subaddrAccount,
|
||||
Pointer<Pointer<Utf8>> preferredInputs,
|
||||
Int32 preferredInputsSize,
|
||||
Pointer<Utf8Box> error,
|
||||
Pointer<PendingTransactionRaw> pendingTransaction);
|
||||
|
||||
|
@ -123,10 +126,16 @@ typedef on_startup = Void Function();
|
|||
|
||||
typedef rescan_blockchain = Void Function();
|
||||
|
||||
typedef get_subaddress_label = Pointer<Utf8> Function(
|
||||
Int32 accountIndex,
|
||||
Int32 addressIndex);
|
||||
typedef get_subaddress_label = Pointer<Utf8> Function(Int32 accountIndex, Int32 addressIndex);
|
||||
|
||||
typedef set_trusted_daemon = Void Function(Int8 trusted);
|
||||
|
||||
typedef trusted_daemon = Int8 Function();
|
||||
|
||||
typedef refresh_coins = Void Function(Int32 accountIndex);
|
||||
|
||||
typedef coins_count = Int64 Function();
|
||||
|
||||
// typedef coins_from_txid = Pointer<CoinsInfoRow> Function(Pointer<Utf8> txid);
|
||||
|
||||
typedef coin = Pointer<CoinsInfoRow> Function(Int32 index);
|
||||
|
|
73
cw_monero/lib/api/structs/coins_info_row.dart
Normal file
73
cw_monero/lib/api/structs/coins_info_row.dart
Normal file
|
@ -0,0 +1,73 @@
|
|||
import 'dart:ffi';
|
||||
import 'package:ffi/ffi.dart';
|
||||
|
||||
class CoinsInfoRow extends Struct {
|
||||
@Int64()
|
||||
external int blockHeight;
|
||||
|
||||
external Pointer<Utf8> hash;
|
||||
|
||||
@Uint64()
|
||||
external int internalOutputIndex;
|
||||
|
||||
@Uint64()
|
||||
external int globalOutputIndex;
|
||||
|
||||
@Int8()
|
||||
external int spent;
|
||||
|
||||
@Int8()
|
||||
external int frozen;
|
||||
|
||||
@Uint64()
|
||||
external int spentHeight;
|
||||
|
||||
@Uint64()
|
||||
external int amount;
|
||||
|
||||
@Int8()
|
||||
external int rct;
|
||||
|
||||
@Int8()
|
||||
external int keyImageKnown;
|
||||
|
||||
@Uint64()
|
||||
external int pkIndex;
|
||||
|
||||
@Uint32()
|
||||
external int subaddrIndex;
|
||||
|
||||
@Uint32()
|
||||
external int subaddrAccount;
|
||||
|
||||
external Pointer<Utf8> address;
|
||||
|
||||
external Pointer<Utf8> addressLabel;
|
||||
|
||||
external Pointer<Utf8> keyImage;
|
||||
|
||||
@Uint64()
|
||||
external int unlockTime;
|
||||
|
||||
@Int8()
|
||||
external int unlocked;
|
||||
|
||||
external Pointer<Utf8> pubKey;
|
||||
|
||||
@Int8()
|
||||
external int coinbase;
|
||||
|
||||
external Pointer<Utf8> description;
|
||||
|
||||
String getHash() => hash.toDartString();
|
||||
|
||||
String getAddress() => address.toDartString();
|
||||
|
||||
String getAddressLabel() => addressLabel.toDartString();
|
||||
|
||||
String getKeyImage() => keyImage.toDartString();
|
||||
|
||||
String getPubKey() => pubKey.toDartString();
|
||||
|
||||
String getDescription() => description.toDartString();
|
||||
}
|
|
@ -35,9 +35,8 @@ final transactionCommitNative = moneroApi
|
|||
.lookup<NativeFunction<transaction_commit>>('transaction_commit')
|
||||
.asFunction<TransactionCommit>();
|
||||
|
||||
final getTxKeyNative = moneroApi
|
||||
.lookup<NativeFunction<get_tx_key>>('get_tx_key')
|
||||
.asFunction<GetTxKey>();
|
||||
final getTxKeyNative =
|
||||
moneroApi.lookup<NativeFunction<get_tx_key>>('get_tx_key').asFunction<GetTxKey>();
|
||||
|
||||
String getTxKey(String txId) {
|
||||
final txIdPointer = txId.toNativeUtf8();
|
||||
|
@ -71,10 +70,21 @@ PendingTransactionDescription createTransactionSync(
|
|||
required String paymentId,
|
||||
required int priorityRaw,
|
||||
String? amount,
|
||||
int accountIndex = 0}) {
|
||||
int accountIndex = 0,
|
||||
List<String> preferredInputs = const []}) {
|
||||
final addressPointer = address.toNativeUtf8();
|
||||
final paymentIdPointer = paymentId.toNativeUtf8();
|
||||
final amountPointer = amount != null ? amount.toNativeUtf8() : nullptr;
|
||||
|
||||
final int preferredInputsSize = preferredInputs.length;
|
||||
final List<Pointer<Utf8>> preferredInputsPointers =
|
||||
preferredInputs.map((output) => output.toNativeUtf8()).toList();
|
||||
final Pointer<Pointer<Utf8>> preferredInputsPointerPointer = calloc(preferredInputsSize);
|
||||
|
||||
for (int i = 0; i < preferredInputsSize; i++) {
|
||||
preferredInputsPointerPointer[i] = preferredInputsPointers[i];
|
||||
}
|
||||
|
||||
final errorMessagePointer = calloc<Utf8Box>();
|
||||
final pendingTransactionRawPointer = calloc<PendingTransactionRaw>();
|
||||
final created = transactionCreateNative(
|
||||
|
@ -83,10 +93,16 @@ PendingTransactionDescription createTransactionSync(
|
|||
amountPointer,
|
||||
priorityRaw,
|
||||
accountIndex,
|
||||
preferredInputsPointerPointer,
|
||||
preferredInputsSize,
|
||||
errorMessagePointer,
|
||||
pendingTransactionRawPointer) !=
|
||||
0;
|
||||
|
||||
calloc.free(preferredInputsPointerPointer);
|
||||
|
||||
preferredInputsPointers.forEach((element) => calloc.free(element));
|
||||
|
||||
calloc.free(addressPointer);
|
||||
calloc.free(paymentIdPointer);
|
||||
|
||||
|
@ -113,13 +129,14 @@ PendingTransactionDescription createTransactionMultDestSync(
|
|||
{required List<MoneroOutput> outputs,
|
||||
required String paymentId,
|
||||
required int priorityRaw,
|
||||
int accountIndex = 0}) {
|
||||
int accountIndex = 0,
|
||||
List<String> preferredInputs = const []}) {
|
||||
final int size = outputs.length;
|
||||
final List<Pointer<Utf8>> addressesPointers = outputs.map((output) =>
|
||||
output.address.toNativeUtf8()).toList();
|
||||
final List<Pointer<Utf8>> addressesPointers =
|
||||
outputs.map((output) => output.address.toNativeUtf8()).toList();
|
||||
final Pointer<Pointer<Utf8>> addressesPointerPointer = calloc(size);
|
||||
final List<Pointer<Utf8>> amountsPointers = outputs.map((output) =>
|
||||
output.amount.toNativeUtf8()).toList();
|
||||
final List<Pointer<Utf8>> amountsPointers =
|
||||
outputs.map((output) => output.amount.toNativeUtf8()).toList();
|
||||
final Pointer<Pointer<Utf8>> amountsPointerPointer = calloc(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
|
@ -127,6 +144,15 @@ PendingTransactionDescription createTransactionMultDestSync(
|
|||
amountsPointerPointer[i] = amountsPointers[i];
|
||||
}
|
||||
|
||||
final int preferredInputsSize = preferredInputs.length;
|
||||
final List<Pointer<Utf8>> preferredInputsPointers =
|
||||
preferredInputs.map((output) => output.toNativeUtf8()).toList();
|
||||
final Pointer<Pointer<Utf8>> preferredInputsPointerPointer = calloc(preferredInputsSize);
|
||||
|
||||
for (int i = 0; i < preferredInputsSize; i++) {
|
||||
preferredInputsPointerPointer[i] = preferredInputsPointers[i];
|
||||
}
|
||||
|
||||
final paymentIdPointer = paymentId.toNativeUtf8();
|
||||
final errorMessagePointer = calloc<Utf8Box>();
|
||||
final pendingTransactionRawPointer = calloc<PendingTransactionRaw>();
|
||||
|
@ -137,15 +163,19 @@ PendingTransactionDescription createTransactionMultDestSync(
|
|||
size,
|
||||
priorityRaw,
|
||||
accountIndex,
|
||||
preferredInputsPointerPointer,
|
||||
preferredInputsSize,
|
||||
errorMessagePointer,
|
||||
pendingTransactionRawPointer) !=
|
||||
0;
|
||||
|
||||
calloc.free(addressesPointerPointer);
|
||||
calloc.free(amountsPointerPointer);
|
||||
calloc.free(preferredInputsPointerPointer);
|
||||
|
||||
addressesPointers.forEach((element) => calloc.free(element));
|
||||
amountsPointers.forEach((element) => calloc.free(element));
|
||||
preferredInputsPointers.forEach((element) => calloc.free(element));
|
||||
|
||||
calloc.free(paymentIdPointer);
|
||||
|
||||
|
@ -164,13 +194,12 @@ PendingTransactionDescription createTransactionMultDestSync(
|
|||
pointerAddress: pendingTransactionRawPointer.address);
|
||||
}
|
||||
|
||||
void commitTransactionFromPointerAddress({required int address}) => commitTransaction(
|
||||
transactionPointer: Pointer<PendingTransactionRaw>.fromAddress(address));
|
||||
void commitTransactionFromPointerAddress({required int address}) =>
|
||||
commitTransaction(transactionPointer: Pointer<PendingTransactionRaw>.fromAddress(address));
|
||||
|
||||
void commitTransaction({required Pointer<PendingTransactionRaw> transactionPointer}) {
|
||||
final errorMessagePointer = calloc<Utf8Box>();
|
||||
final isCommited =
|
||||
transactionCommitNative(transactionPointer, errorMessagePointer) != 0;
|
||||
final isCommited = transactionCommitNative(transactionPointer, errorMessagePointer) != 0;
|
||||
|
||||
if (!isCommited) {
|
||||
final message = errorMessagePointer.ref.getValue();
|
||||
|
@ -185,13 +214,15 @@ PendingTransactionDescription _createTransactionSync(Map args) {
|
|||
final amount = args['amount'] as String?;
|
||||
final priorityRaw = args['priorityRaw'] as int;
|
||||
final accountIndex = args['accountIndex'] as int;
|
||||
final preferredInputs = args['preferredInputs'] as List<String>;
|
||||
|
||||
return createTransactionSync(
|
||||
address: address,
|
||||
paymentId: paymentId,
|
||||
amount: amount,
|
||||
priorityRaw: priorityRaw,
|
||||
accountIndex: accountIndex);
|
||||
accountIndex: accountIndex,
|
||||
preferredInputs: preferredInputs);
|
||||
}
|
||||
|
||||
PendingTransactionDescription _createTransactionMultDestSync(Map args) {
|
||||
|
@ -199,12 +230,14 @@ PendingTransactionDescription _createTransactionMultDestSync(Map args) {
|
|||
final paymentId = args['paymentId'] as String;
|
||||
final priorityRaw = args['priorityRaw'] as int;
|
||||
final accountIndex = args['accountIndex'] as int;
|
||||
final preferredInputs = args['preferredInputs'] as List<String>;
|
||||
|
||||
return createTransactionMultDestSync(
|
||||
outputs: outputs,
|
||||
paymentId: paymentId,
|
||||
priorityRaw: priorityRaw,
|
||||
accountIndex: accountIndex);
|
||||
accountIndex: accountIndex,
|
||||
preferredInputs: preferredInputs);
|
||||
}
|
||||
|
||||
Future<PendingTransactionDescription> createTransaction(
|
||||
|
@ -212,23 +245,27 @@ Future<PendingTransactionDescription> createTransaction(
|
|||
required int priorityRaw,
|
||||
String? amount,
|
||||
String paymentId = '',
|
||||
int accountIndex = 0}) =>
|
||||
int accountIndex = 0,
|
||||
List<String> preferredInputs = const []}) =>
|
||||
compute(_createTransactionSync, {
|
||||
'address': address,
|
||||
'paymentId': paymentId,
|
||||
'amount': amount,
|
||||
'priorityRaw': priorityRaw,
|
||||
'accountIndex': accountIndex
|
||||
'accountIndex': accountIndex,
|
||||
'preferredInputs': preferredInputs
|
||||
});
|
||||
|
||||
Future<PendingTransactionDescription> createTransactionMultDest(
|
||||
{required List<MoneroOutput> outputs,
|
||||
required int priorityRaw,
|
||||
String paymentId = '',
|
||||
int accountIndex = 0}) =>
|
||||
int accountIndex = 0,
|
||||
List<String> preferredInputs = const []}) =>
|
||||
compute(_createTransactionMultDestSync, {
|
||||
'outputs': outputs,
|
||||
'paymentId': paymentId,
|
||||
'priorityRaw': priorityRaw,
|
||||
'accountIndex': accountIndex
|
||||
'accountIndex': accountIndex,
|
||||
'preferredInputs': preferredInputs
|
||||
});
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'dart:ffi';
|
||||
import 'package:cw_monero/api/structs/coins_info_row.dart';
|
||||
import 'package:cw_monero/api/structs/pending_transaction.dart';
|
||||
import 'package:cw_monero/api/structs/ut8_box.dart';
|
||||
import 'package:ffi/ffi.dart';
|
||||
|
@ -92,6 +93,8 @@ typedef TransactionCreate = int Function(
|
|||
Pointer<Utf8> amount,
|
||||
int priorityRaw,
|
||||
int subaddrAccount,
|
||||
Pointer<Pointer<Utf8>> preferredInputs,
|
||||
int preferredInputsSize,
|
||||
Pointer<Utf8Box> error,
|
||||
Pointer<PendingTransactionRaw> pendingTransaction);
|
||||
|
||||
|
@ -102,6 +105,8 @@ typedef TransactionCreateMultDest = int Function(
|
|||
int size,
|
||||
int priorityRaw,
|
||||
int subaddrAccount,
|
||||
Pointer<Pointer<Utf8>> preferredInputs,
|
||||
int preferredInputsSize,
|
||||
Pointer<Utf8Box> error,
|
||||
Pointer<PendingTransactionRaw> pendingTransaction);
|
||||
|
||||
|
@ -128,3 +133,9 @@ typedef GetSubaddressLabel = Pointer<Utf8> Function(
|
|||
typedef SetTrustedDaemon = void Function(int);
|
||||
|
||||
typedef TrustedDaemon = int Function();
|
||||
|
||||
typedef RefreshCoins = void Function(int);
|
||||
|
||||
typedef CoinsCount = int Function();
|
||||
|
||||
typedef GetCoin = Pointer<CoinsInfoRow> Function(int);
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
class MoneroTransactionNoInputsException implements Exception {
|
||||
@override
|
||||
String toString() => 'Not enough inputs available. Please select more under Coin Control';
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:cw_monero/api/structs/subaddress_row.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cw_monero/api/coins_info.dart';
|
||||
import 'package:cw_monero/api/subaddress_list.dart' as subaddress_list;
|
||||
import 'package:cw_core/subaddress.dart';
|
||||
|
||||
|
@ -22,6 +22,8 @@ abstract class MoneroSubaddressListBase with Store {
|
|||
bool _isUpdating;
|
||||
|
||||
void update({required int accountIndex}) {
|
||||
// refreshCoins(accountIndex);
|
||||
|
||||
if (_isUpdating) {
|
||||
return;
|
||||
}
|
||||
|
|
28
cw_monero/lib/monero_unspent.dart
Normal file
28
cw_monero/lib/monero_unspent.dart
Normal file
|
@ -0,0 +1,28 @@
|
|||
import 'package:cw_monero/api/structs/coins_info_row.dart';
|
||||
|
||||
class MoneroUnspent {
|
||||
MoneroUnspent(this.address, this.hash, this.keyImage, this.value, this.isFrozen, this.isUnlocked)
|
||||
: isSending = true,
|
||||
note = '';
|
||||
|
||||
MoneroUnspent.fromCoinsInfoRow(CoinsInfoRow coinsInfoRow)
|
||||
: address = coinsInfoRow.getAddress(),
|
||||
hash = coinsInfoRow.getHash(),
|
||||
keyImage = coinsInfoRow.getKeyImage(),
|
||||
value = coinsInfoRow.amount,
|
||||
isFrozen = coinsInfoRow.frozen == 1,
|
||||
isUnlocked = coinsInfoRow.unlocked == 1,
|
||||
isSending = true,
|
||||
note = '';
|
||||
|
||||
final String address;
|
||||
final String hash;
|
||||
final String keyImage;
|
||||
final int value;
|
||||
|
||||
final bool isUnlocked;
|
||||
|
||||
bool isFrozen;
|
||||
bool isSending;
|
||||
String note;
|
||||
}
|
|
@ -1,33 +1,35 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'package:cw_core/pathForWallet.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cw_core/monero_amount_format.dart';
|
||||
import 'package:cw_monero/monero_transaction_creation_exception.dart';
|
||||
import 'package:cw_monero/monero_transaction_info.dart';
|
||||
import 'package:cw_monero/monero_wallet_addresses.dart';
|
||||
import 'package:cw_core/monero_wallet_utils.dart';
|
||||
import 'package:cw_monero/api/structs/pending_transaction.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cw_monero/api/transaction_history.dart'
|
||||
as monero_transaction_history;
|
||||
import 'package:cw_monero/api/wallet.dart';
|
||||
import 'package:cw_monero/api/wallet.dart' as monero_wallet;
|
||||
import 'package:cw_monero/api/transaction_history.dart' as transaction_history;
|
||||
import 'package:cw_monero/api/monero_output.dart';
|
||||
import 'package:cw_monero/monero_transaction_creation_credentials.dart';
|
||||
import 'package:cw_monero/pending_monero_transaction.dart';
|
||||
import 'package:cw_core/monero_wallet_keys.dart';
|
||||
import 'package:cw_core/monero_balance.dart';
|
||||
import 'package:cw_monero/monero_transaction_history.dart';
|
||||
import 'package:cw_core/account.dart';
|
||||
import 'package:cw_core/pending_transaction.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/sync_status.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cw_core/monero_transaction_priority.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/monero_amount_format.dart';
|
||||
import 'package:cw_core/monero_balance.dart';
|
||||
import 'package:cw_core/monero_transaction_priority.dart';
|
||||
import 'package:cw_core/monero_wallet_keys.dart';
|
||||
import 'package:cw_core/monero_wallet_utils.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cw_core/pathForWallet.dart';
|
||||
import 'package:cw_core/pending_transaction.dart';
|
||||
import 'package:cw_core/sync_status.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
import 'package:cw_core/unspent_coins_info.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_monero/api/coins_info.dart';
|
||||
import 'package:cw_monero/api/monero_output.dart';
|
||||
import 'package:cw_monero/api/structs/pending_transaction.dart';
|
||||
import 'package:cw_monero/api/transaction_history.dart' as transaction_history;
|
||||
import 'package:cw_monero/api/wallet.dart' as monero_wallet;
|
||||
import 'package:cw_monero/exceptions/monero_transaction_creation_exception.dart';
|
||||
import 'package:cw_monero/exceptions/monero_transaction_no_inputs_exception.dart';
|
||||
import 'package:cw_monero/pending_monero_transaction.dart';
|
||||
import 'package:cw_monero/monero_transaction_creation_credentials.dart';
|
||||
import 'package:cw_monero/monero_transaction_history.dart';
|
||||
import 'package:cw_monero/monero_transaction_info.dart';
|
||||
import 'package:cw_monero/monero_unspent.dart';
|
||||
import 'package:cw_monero/monero_wallet_addresses.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
|
||||
part 'monero_wallet.g.dart';
|
||||
|
||||
|
@ -39,6 +41,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
MoneroTransactionHistory, MoneroTransactionInfo> with Store {
|
||||
MoneroWalletBase({
|
||||
required WalletInfo walletInfo,
|
||||
required Box<UnspentCoinsInfo> unspentCoinsInfo,
|
||||
required String password})
|
||||
: balance = ObservableMap<CryptoCurrency, MoneroBalance>.of({
|
||||
CryptoCurrency.xmr: MoneroBalance(
|
||||
|
@ -50,20 +53,19 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
_password = password,
|
||||
walletAddresses = MoneroWalletAddresses(walletInfo),
|
||||
syncStatus = NotConnectedSyncStatus(),
|
||||
unspentCoins = [],
|
||||
this.unspentCoinsInfo = unspentCoinsInfo,
|
||||
super(walletInfo) {
|
||||
transactionHistory = MoneroTransactionHistory();
|
||||
_onAccountChangeReaction = reaction((_) => walletAddresses.account,
|
||||
(Account? account) {
|
||||
_onAccountChangeReaction = reaction((_) => walletAddresses.account, (Account? account) {
|
||||
if (account == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
balance = ObservableMap<CryptoCurrency, MoneroBalance>.of(
|
||||
<CryptoCurrency, MoneroBalance>{
|
||||
balance = ObservableMap<CryptoCurrency, MoneroBalance>.of(<CryptoCurrency, MoneroBalance>{
|
||||
currency: MoneroBalance(
|
||||
fullBalance: monero_wallet.getFullBalance(accountIndex: account.id),
|
||||
unlockedBalance:
|
||||
monero_wallet.getUnlockedBalance(accountIndex: account.id))
|
||||
unlockedBalance: monero_wallet.getUnlockedBalance(accountIndex: account.id))
|
||||
});
|
||||
walletAddresses.updateSubaddressList(accountIndex: account.id);
|
||||
});
|
||||
|
@ -71,6 +73,8 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
|
||||
static const int _autoSaveInterval = 30;
|
||||
|
||||
Box<UnspentCoinsInfo> unspentCoinsInfo;
|
||||
|
||||
@override
|
||||
MoneroWalletAddresses walletAddresses;
|
||||
|
||||
|
@ -95,11 +99,12 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
publicSpendKey: monero_wallet.getPublicSpendKey(),
|
||||
publicViewKey: monero_wallet.getPublicViewKey());
|
||||
|
||||
SyncListener? _listener;
|
||||
monero_wallet.SyncListener? _listener;
|
||||
ReactionDisposer? _onAccountChangeReaction;
|
||||
bool _isTransactionUpdating;
|
||||
bool _hasSyncAfterStartup;
|
||||
Timer? _autoSaveTimer;
|
||||
List<MoneroUnspent> unspentCoins;
|
||||
String _password;
|
||||
|
||||
Future<void> init() async {
|
||||
|
@ -177,10 +182,12 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
@override
|
||||
Future<PendingTransaction> createTransaction(Object credentials) async {
|
||||
final _credentials = credentials as MoneroTransactionCreationCredentials;
|
||||
final inputs = <String>[];
|
||||
final outputs = _credentials.outputs;
|
||||
final hasMultiDestination = outputs.length > 1;
|
||||
final unlockedBalance =
|
||||
monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id);
|
||||
var allInputsAmount = 0;
|
||||
|
||||
PendingTransactionDescription pendingTransactionDescription;
|
||||
|
||||
|
@ -188,6 +195,21 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
throw MoneroTransactionCreationException('The wallet is not synced.');
|
||||
}
|
||||
|
||||
if (unspentCoins.isEmpty) {
|
||||
await updateUnspent();
|
||||
}
|
||||
|
||||
for (final utx in unspentCoins) {
|
||||
if (utx.isSending) {
|
||||
allInputsAmount += utx.value;
|
||||
inputs.add(utx.keyImage);
|
||||
}
|
||||
}
|
||||
|
||||
if (inputs.isEmpty) {
|
||||
throw MoneroTransactionNoInputsException();
|
||||
}
|
||||
|
||||
if (hasMultiDestination) {
|
||||
if (outputs.any((item) => item.sendAll
|
||||
|| (item.formattedCryptoAmount ?? 0) <= 0)) {
|
||||
|
@ -215,7 +237,8 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
await transaction_history.createTransactionMultDest(
|
||||
outputs: moneroOutputs,
|
||||
priorityRaw: _credentials.priority.serialize(),
|
||||
accountIndex: walletAddresses.account!.id);
|
||||
accountIndex: walletAddresses.account!.id,
|
||||
preferredInputs: inputs);
|
||||
} else {
|
||||
final output = outputs.first;
|
||||
final address = output.isParsedAddress
|
||||
|
@ -236,12 +259,12 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
'You do not have enough unlocked balance. Unlocked: $formattedBalance. Transaction amount: ${output.cryptoAmount}.');
|
||||
}
|
||||
|
||||
pendingTransactionDescription =
|
||||
await transaction_history.createTransaction(
|
||||
pendingTransactionDescription = await transaction_history.createTransaction(
|
||||
address: address!,
|
||||
amount: amount,
|
||||
priorityRaw: _credentials.priority.serialize(),
|
||||
accountIndex: walletAddresses.account!.id);
|
||||
accountIndex: walletAddresses.account!.id,
|
||||
preferredInputs: inputs);
|
||||
}
|
||||
|
||||
return PendingMoneroTransaction(pendingTransactionDescription);
|
||||
|
@ -362,6 +385,85 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
await walletInfo.save();
|
||||
}
|
||||
|
||||
Future<void> updateUnspent() async {
|
||||
// refreshCoins(walletAddresses.account!.id);
|
||||
|
||||
unspentCoins.clear();
|
||||
|
||||
final coinCount = countOfCoins();
|
||||
for (var i = 0; i < coinCount; i++) {
|
||||
final coin = getCoin(i);
|
||||
if (coin.spent == 0) {
|
||||
unspentCoins.add(MoneroUnspent.fromCoinsInfoRow(coin));
|
||||
}
|
||||
}
|
||||
|
||||
if (unspentCoinsInfo.isEmpty) {
|
||||
unspentCoins.forEach((coin) => _addCoinInfo(coin));
|
||||
return;
|
||||
}
|
||||
|
||||
if (unspentCoins.isNotEmpty) {
|
||||
unspentCoins.forEach((coin) {
|
||||
final coinInfoList = unspentCoinsInfo.values.where((element) =>
|
||||
element.walletId.contains(id) && element.hash.contains(coin.hash));
|
||||
|
||||
if (coinInfoList.isNotEmpty) {
|
||||
final coinInfo = coinInfoList.first;
|
||||
|
||||
coin.isFrozen = coinInfo.isFrozen;
|
||||
coin.isSending = coinInfo.isSending;
|
||||
coin.note = coinInfo.note;
|
||||
} else {
|
||||
_addCoinInfo(coin);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
await _refreshUnspentCoinsInfo();
|
||||
_askForUpdateBalance();
|
||||
}
|
||||
|
||||
Future<void> _addCoinInfo(MoneroUnspent coin) async {
|
||||
final newInfo = UnspentCoinsInfo(
|
||||
walletId: id,
|
||||
hash: coin.hash,
|
||||
isFrozen: coin.isFrozen,
|
||||
isSending: coin.isSending,
|
||||
noteRaw: coin.note,
|
||||
address: coin.address,
|
||||
value: coin.value,
|
||||
vout: 0,
|
||||
keyImage: coin.keyImage
|
||||
);
|
||||
|
||||
await unspentCoinsInfo.add(newInfo);
|
||||
}
|
||||
|
||||
Future<void> _refreshUnspentCoinsInfo() async {
|
||||
try {
|
||||
final List<dynamic> keys = <dynamic>[];
|
||||
final currentWalletUnspentCoins = unspentCoinsInfo.values
|
||||
.where((element) => element.walletId.contains(id));
|
||||
|
||||
if (currentWalletUnspentCoins.isNotEmpty) {
|
||||
currentWalletUnspentCoins.forEach((element) {
|
||||
final existUnspentCoins = unspentCoins.where((coin) => element.hash.contains(coin.hash));
|
||||
|
||||
if (existUnspentCoins.isEmpty) {
|
||||
keys.add(element.key);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (keys.isNotEmpty) {
|
||||
await unspentCoinsInfo.deleteAll(keys);
|
||||
}
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
String getTransactionAddress(int accountIndex, int addressIndex) =>
|
||||
monero_wallet.getAddress(
|
||||
accountIndex: accountIndex,
|
||||
|
@ -369,7 +471,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
|
||||
@override
|
||||
Future<Map<String, MoneroTransactionInfo>> fetchTransactions() async {
|
||||
monero_transaction_history.refreshTransactions();
|
||||
transaction_history.refreshTransactions();
|
||||
return _getAllTransactions(null).fold<Map<String, MoneroTransactionInfo>>(
|
||||
<String, MoneroTransactionInfo>{},
|
||||
(Map<String, MoneroTransactionInfo> acc, MoneroTransactionInfo tx) {
|
||||
|
@ -400,7 +502,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
}
|
||||
|
||||
List<MoneroTransactionInfo> _getAllTransactions(dynamic _) =>
|
||||
monero_transaction_history
|
||||
transaction_history
|
||||
.getAllTransations()
|
||||
.map((row) => MoneroTransactionInfo.fromRow(row))
|
||||
.toList();
|
||||
|
@ -415,7 +517,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
return;
|
||||
}
|
||||
|
||||
final currentHeight = getCurrentHeight();
|
||||
final currentHeight = monero_wallet.getCurrentHeight();
|
||||
|
||||
if (currentHeight <= 1) {
|
||||
final height = _getHeightByDate(walletInfo.date);
|
||||
|
@ -447,11 +549,13 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
void _askForUpdateBalance() {
|
||||
final unlockedBalance = _getUnlockedBalance();
|
||||
final fullBalance = _getFullBalance();
|
||||
final frozenBalance = _getFrozenBalance();
|
||||
|
||||
if (balance[currency]!.fullBalance != fullBalance ||
|
||||
balance[currency]!.unlockedBalance != unlockedBalance) {
|
||||
balance[currency]!.unlockedBalance != unlockedBalance ||
|
||||
balance[currency]!.frozenBalance != frozenBalance) {
|
||||
balance[currency] = MoneroBalance(
|
||||
fullBalance: fullBalance, unlockedBalance: unlockedBalance);
|
||||
fullBalance: fullBalance, unlockedBalance: unlockedBalance, frozenBalance: frozenBalance);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -464,6 +568,17 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
|
|||
int _getUnlockedBalance() =>
|
||||
monero_wallet.getUnlockedBalance(accountIndex: walletAddresses.account!.id);
|
||||
|
||||
int _getFrozenBalance() {
|
||||
var frozenBalance = 0;
|
||||
|
||||
for (var coin in unspentCoinsInfo.values) {
|
||||
if (coin.isFrozen)
|
||||
frozenBalance += coin.value;
|
||||
}
|
||||
|
||||
return frozenBalance;
|
||||
}
|
||||
|
||||
void _onNewBlock(int height, int blocksLeft, double ptc) async {
|
||||
try {
|
||||
if (walletInfo.isRecovery) {
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
import 'dart:io';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/monero_wallet_utils.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:cw_monero/api/wallet_manager.dart' as monero_wallet_manager;
|
||||
import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart';
|
||||
import 'package:cw_monero/monero_wallet.dart';
|
||||
import 'package:cw_core/wallet_credentials.dart';
|
||||
import 'package:cw_core/wallet_service.dart';
|
||||
import 'package:cw_core/pathForWallet.dart';
|
||||
import 'package:cw_core/unspent_coins_info.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_credentials.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_service.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cw_monero/api/exceptions/wallet_opening_exception.dart';
|
||||
import 'package:cw_monero/api/wallet_manager.dart' as monero_wallet_manager;
|
||||
import 'package:cw_monero/monero_wallet.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
|
||||
class MoneroNewWalletCredentials extends WalletCredentials {
|
||||
MoneroNewWalletCredentials({required String name, required this.language, String? password})
|
||||
|
@ -52,9 +53,10 @@ class MoneroWalletService extends WalletService<
|
|||
MoneroNewWalletCredentials,
|
||||
MoneroRestoreWalletFromSeedCredentials,
|
||||
MoneroRestoreWalletFromKeysCredentials> {
|
||||
MoneroWalletService(this.walletInfoSource);
|
||||
MoneroWalletService(this.walletInfoSource, this.unspentCoinsInfoSource);
|
||||
|
||||
final Box<WalletInfo> walletInfoSource;
|
||||
final Box<UnspentCoinsInfo> unspentCoinsInfoSource;
|
||||
|
||||
static bool walletFilesExist(String path) =>
|
||||
!File(path).existsSync() && !File('$path.keys').existsSync();
|
||||
|
@ -71,8 +73,9 @@ class MoneroWalletService extends WalletService<
|
|||
password: credentials.password!,
|
||||
language: credentials.language);
|
||||
final wallet = MoneroWallet(
|
||||
|
||||
walletInfo: credentials.walletInfo!,
|
||||
password: credentials.password!);
|
||||
password: credentials.password!, unspentCoinsInfo: unspentCoinsInfoSource);
|
||||
await wallet.init();
|
||||
|
||||
return wallet;
|
||||
|
@ -109,7 +112,7 @@ class MoneroWalletService extends WalletService<
|
|||
final walletInfo = walletInfoSource.values.firstWhere(
|
||||
(info) => info.id == WalletBase.idFor(name, getType()));
|
||||
final wallet = MoneroWallet(
|
||||
walletInfo: walletInfo,
|
||||
walletInfo: walletInfo, unspentCoinsInfo: unspentCoinsInfoSource,
|
||||
password: password);
|
||||
final isValid = wallet.walletAddresses.validate();
|
||||
|
||||
|
@ -160,7 +163,8 @@ class MoneroWalletService extends WalletService<
|
|||
String currentName, String password, String newName) async {
|
||||
final currentWalletInfo = walletInfoSource.values.firstWhere(
|
||||
(info) => info.id == WalletBase.idFor(currentName, getType()));
|
||||
final currentWallet = MoneroWallet(walletInfo: currentWalletInfo, password: password);
|
||||
final currentWallet =
|
||||
MoneroWallet(walletInfo: currentWalletInfo, unspentCoinsInfo: unspentCoinsInfoSource, password: password);
|
||||
|
||||
await currentWallet.renameWalletFiles(newName);
|
||||
|
||||
|
@ -185,8 +189,9 @@ class MoneroWalletService extends WalletService<
|
|||
viewKey: credentials.viewKey,
|
||||
spendKey: credentials.spendKey);
|
||||
final wallet = MoneroWallet(
|
||||
|
||||
walletInfo: credentials.walletInfo!,
|
||||
password: credentials.password!);
|
||||
password: credentials.password!, unspentCoinsInfo: unspentCoinsInfoSource);
|
||||
await wallet.init();
|
||||
|
||||
return wallet;
|
||||
|
@ -208,8 +213,9 @@ class MoneroWalletService extends WalletService<
|
|||
seed: credentials.mnemonic,
|
||||
restoreHeight: credentials.height!);
|
||||
final wallet = MoneroWallet(
|
||||
|
||||
walletInfo: credentials.walletInfo!,
|
||||
password: credentials.password!);
|
||||
password: credentials.password!, unspentCoinsInfo: unspentCoinsInfoSource);
|
||||
await wallet.init();
|
||||
|
||||
return wallet;
|
||||
|
|
|
@ -174,12 +174,12 @@ DEPENDENCIES:
|
|||
- in_app_review (from `.symlinks/plugins/in_app_review/ios`)
|
||||
- local_auth_ios (from `.symlinks/plugins/local_auth_ios/ios`)
|
||||
- package_info (from `.symlinks/plugins/package_info/ios`)
|
||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`)
|
||||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
|
||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||
- platform_device_id (from `.symlinks/plugins/platform_device_id/ios`)
|
||||
- sensitive_clipboard (from `.symlinks/plugins/sensitive_clipboard/ios`)
|
||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
- uni_links (from `.symlinks/plugins/uni_links/ios`)
|
||||
- UnstoppableDomainsResolution (~> 4.0.0)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
|
@ -236,7 +236,7 @@ EXTERNAL SOURCES:
|
|||
package_info:
|
||||
:path: ".symlinks/plugins/package_info/ios"
|
||||
path_provider_foundation:
|
||||
:path: ".symlinks/plugins/path_provider_foundation/ios"
|
||||
:path: ".symlinks/plugins/path_provider_foundation/darwin"
|
||||
permission_handler_apple:
|
||||
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||
platform_device_id:
|
||||
|
@ -246,7 +246,7 @@ EXTERNAL SOURCES:
|
|||
share_plus:
|
||||
:path: ".symlinks/plugins/share_plus/ios"
|
||||
shared_preferences_foundation:
|
||||
:path: ".symlinks/plugins/shared_preferences_foundation/ios"
|
||||
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
|
||||
uni_links:
|
||||
:path: ".symlinks/plugins/uni_links/ios"
|
||||
url_launcher_ios:
|
||||
|
|
|
@ -129,7 +129,8 @@ class CWBitcoin extends Bitcoin {
|
|||
bitcoinUnspent.address.address,
|
||||
bitcoinUnspent.hash,
|
||||
bitcoinUnspent.value,
|
||||
bitcoinUnspent.vout))
|
||||
bitcoinUnspent.vout,
|
||||
null))
|
||||
.toList();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import 'package:cake_wallet/.secrets.g.dart' as secrets;
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class OnRamperBuyProvider {
|
||||
OnRamperBuyProvider({required SettingsStore settingsStore, required WalletBase wallet})
|
||||
|
@ -27,7 +29,11 @@ class OnRamperBuyProvider {
|
|||
}
|
||||
}
|
||||
|
||||
Uri requestUrl() {
|
||||
String getColorStr(Color color) {
|
||||
return color.value.toRadixString(16).replaceAll(RegExp(r'^ff'), "");
|
||||
}
|
||||
|
||||
Uri requestUrl(BuildContext context) {
|
||||
String primaryColor,
|
||||
secondaryColor,
|
||||
primaryTextColor,
|
||||
|
@ -35,31 +41,16 @@ class OnRamperBuyProvider {
|
|||
containerColor,
|
||||
cardColor;
|
||||
|
||||
switch (_settingsStore.currentTheme.type) {
|
||||
case ThemeType.bright:
|
||||
primaryColor = '815dfbff';
|
||||
secondaryColor = 'ffffff';
|
||||
primaryTextColor = '141519';
|
||||
secondaryTextColor = '6b6f80';
|
||||
containerColor = 'ffffff';
|
||||
cardColor = 'f2f0faff';
|
||||
break;
|
||||
case ThemeType.light:
|
||||
primaryColor = '2194ffff';
|
||||
secondaryColor = 'ffffff';
|
||||
primaryTextColor = '141519';
|
||||
secondaryTextColor = '6b6f80';
|
||||
containerColor = 'ffffff';
|
||||
cardColor = 'e5f7ff';
|
||||
break;
|
||||
case ThemeType.dark:
|
||||
primaryColor = '456effff';
|
||||
secondaryColor = '1b2747ff';
|
||||
primaryTextColor = 'ffffff';
|
||||
secondaryTextColor = 'ffffff';
|
||||
containerColor = '19233C';
|
||||
cardColor = '232f4fff';
|
||||
break;
|
||||
primaryColor = getColorStr(Theme.of(context).primaryColor);
|
||||
secondaryColor = getColorStr(Theme.of(context).colorScheme.background);
|
||||
primaryTextColor = getColorStr(Theme.of(context).extension<CakeTextTheme>()!.titleColor);
|
||||
secondaryTextColor =
|
||||
getColorStr(Theme.of(context).extension<CakeTextTheme>()!.secondaryTextColor);
|
||||
containerColor = getColorStr(Theme.of(context).colorScheme.background);
|
||||
cardColor = getColorStr(Theme.of(context).cardColor);
|
||||
|
||||
if (_settingsStore.currentTheme.title == S.current.high_contrast_theme) {
|
||||
cardColor = getColorStr(Colors.white);
|
||||
}
|
||||
|
||||
final networkName = _wallet.currency.fullName?.toUpperCase().replaceAll(" ", "");
|
||||
|
|
33
lib/di.dart
33
lib/di.dart
|
@ -180,8 +180,6 @@ import 'package:hive/hive.dart';
|
|||
import 'package:mobx/mobx.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:cake_wallet/core/secure_storage.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_restoration_from_seed_vm.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_restoration_from_keys_vm.dart';
|
||||
import 'package:cake_wallet/core/wallet_creation_service.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
@ -222,10 +220,10 @@ late Box<Template> _templates;
|
|||
late Box<ExchangeTemplate> _exchangeTemplates;
|
||||
late Box<TransactionDescription> _transactionDescriptionBox;
|
||||
late Box<Order> _ordersSource;
|
||||
late Box<UnspentCoinsInfo>? _unspentCoinsInfoSource;
|
||||
late Box<UnspentCoinsInfo> _unspentCoinsInfoSource;
|
||||
late Box<AnonpayInvoiceInfo> _anonpayInvoiceInfoSource;
|
||||
|
||||
Future setup({
|
||||
Future<void> setup({
|
||||
required Box<WalletInfo> walletInfoSource,
|
||||
required Box<Node> nodeSource,
|
||||
required Box<Contact> contactSource,
|
||||
|
@ -234,7 +232,7 @@ Future setup({
|
|||
required Box<ExchangeTemplate> exchangeTemplates,
|
||||
required Box<TransactionDescription> transactionDescriptionBox,
|
||||
required Box<Order> ordersSource,
|
||||
Box<UnspentCoinsInfo>? unspentCoinsInfoSource,
|
||||
required Box<UnspentCoinsInfo> unspentCoinsInfoSource,
|
||||
required Box<AnonpayInvoiceInfo> anonpayInvoiceInfoSource,
|
||||
}) async {
|
||||
_walletInfoSource = walletInfoSource;
|
||||
|
@ -322,25 +320,6 @@ Future setup({
|
|||
getIt.get<AppStore>(), getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
|
||||
type: type));
|
||||
|
||||
getIt.registerFactoryParam<WalletRestorationFromSeedVM, List, void>((args, _) {
|
||||
final type = args.first as WalletType;
|
||||
final language = args[1] as String;
|
||||
final mnemonic = args[2] as String;
|
||||
|
||||
return WalletRestorationFromSeedVM(
|
||||
getIt.get<AppStore>(), getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
|
||||
type: type, language: language, seed: mnemonic);
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<WalletRestorationFromKeysVM, List, void>((args, _) {
|
||||
final type = args.first as WalletType;
|
||||
final language = args[1] as String;
|
||||
|
||||
return WalletRestorationFromKeysVM(
|
||||
getIt.get<AppStore>(), getIt.get<WalletCreationService>(param1: type), _walletInfoSource,
|
||||
type: type, language: language);
|
||||
});
|
||||
|
||||
getIt.registerFactoryParam<WalletRestorationFromQRVM, WalletType, void>((WalletType type, _) {
|
||||
return WalletRestorationFromQRVM(getIt.get<AppStore>(),
|
||||
getIt.get<WalletCreationService>(param1: type), _walletInfoSource, type);
|
||||
|
@ -737,12 +716,12 @@ Future setup({
|
|||
case WalletType.haven:
|
||||
return haven!.createHavenWalletService(_walletInfoSource);
|
||||
case WalletType.monero:
|
||||
return monero!.createMoneroWalletService(_walletInfoSource);
|
||||
return monero!.createMoneroWalletService(_walletInfoSource, _unspentCoinsInfoSource);
|
||||
case WalletType.bitcoin:
|
||||
return bitcoin!.createBitcoinWalletService(_walletInfoSource, _unspentCoinsInfoSource!,
|
||||
return bitcoin!.createBitcoinWalletService(_walletInfoSource, _unspentCoinsInfoSource,
|
||||
SettingsStoreBase.walletPasswordDirectInput);
|
||||
case WalletType.litecoin:
|
||||
return bitcoin!.createLitecoinWalletService(_walletInfoSource, _unspentCoinsInfoSource!,
|
||||
return bitcoin!.createLitecoinWalletService(_walletInfoSource, _unspentCoinsInfoSource,
|
||||
SettingsStoreBase.walletPasswordDirectInput);
|
||||
case WalletType.ethereum:
|
||||
return ethereum!.createEthereumWalletService(
|
||||
|
|
|
@ -49,7 +49,7 @@ class MainActions {
|
|||
case WalletType.ethereum:
|
||||
case WalletType.monero:
|
||||
if (viewModel.isEnabledBuyAction) {
|
||||
final uri = getIt.get<OnRamperBuyProvider>().requestUrl();
|
||||
final uri = getIt.get<OnRamperBuyProvider>().requestUrl(context);
|
||||
if (DeviceInfo.instance.isMobile) {
|
||||
Navigator.of(context)
|
||||
.pushNamed(Routes.webViewPage, arguments: [S.of(context).buy, uri]);
|
||||
|
|
18
lib/entities/unspent_transaction_output.dart
Normal file
18
lib/entities/unspent_transaction_output.dart
Normal file
|
@ -0,0 +1,18 @@
|
|||
class Unspent {
|
||||
Unspent(this.address, this.hash, this.value, this.vout, this.keyImage)
|
||||
: isSending = true,
|
||||
isFrozen = false,
|
||||
note = '';
|
||||
|
||||
final String address;
|
||||
final String hash;
|
||||
final int value;
|
||||
final int vout;
|
||||
final String? keyImage;
|
||||
|
||||
bool isSending;
|
||||
bool isFrozen;
|
||||
String note;
|
||||
|
||||
bool get isP2wpkh => address.startsWith('bc') || address.startsWith('ltc');
|
||||
}
|
|
@ -23,6 +23,14 @@ class CWEthereum extends Ethereum {
|
|||
}) =>
|
||||
EthereumRestoreWalletFromSeedCredentials(name: name, password: password, mnemonic: mnemonic);
|
||||
|
||||
@override
|
||||
WalletCredentials createEthereumRestoreWalletFromPrivateKey({
|
||||
required String name,
|
||||
required String privateKey,
|
||||
required String password,
|
||||
}) =>
|
||||
EthereumRestoreWalletFromPrivateKey(name: name, password: password, privateKey: privateKey);
|
||||
|
||||
@override
|
||||
String getAddress(WalletBase wallet) => (wallet as EthereumWallet).walletAddresses.address;
|
||||
|
||||
|
|
|
@ -68,14 +68,12 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
required CryptoCurrency to,
|
||||
required bool isFixedRateMode}) async {
|
||||
final headers = {apiHeaderKey: apiKey};
|
||||
final normalizedFrom = normalizeCryptoCurrency(from);
|
||||
final normalizedTo = normalizeCryptoCurrency(to);
|
||||
final flow = getFlow(isFixedRateMode);
|
||||
final params = <String, String>{
|
||||
'fromCurrency': normalizedFrom,
|
||||
'toCurrency': normalizedTo,
|
||||
'fromNetwork': networkFor(from),
|
||||
'toNetwork': networkFor(to),
|
||||
'fromCurrency': _normalizeCurrency(from),
|
||||
'toCurrency': _normalizeCurrency(to),
|
||||
'fromNetwork': _networkFor(from),
|
||||
'toNetwork': _networkFor(to),
|
||||
'flow': flow
|
||||
};
|
||||
final uri = Uri.https(apiAuthority, rangePath, params);
|
||||
|
@ -112,10 +110,10 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
final flow = getFlow(isFixedRateMode);
|
||||
final type = isFixedRateMode ? 'reverse' : 'direct';
|
||||
final body = <String, dynamic>{
|
||||
'fromCurrency': normalizeCryptoCurrency(_request.from),
|
||||
'toCurrency': normalizeCryptoCurrency(_request.to),
|
||||
'fromNetwork': networkFor(_request.from),
|
||||
'toNetwork': networkFor(_request.to),
|
||||
'fromCurrency': _normalizeCurrency(_request.from),
|
||||
'toCurrency': _normalizeCurrency(_request.to),
|
||||
'fromNetwork': _networkFor(_request.from),
|
||||
'toNetwork': _networkFor(_request.to),
|
||||
if (!isFixedRateMode) 'fromAmount': _request.fromAmount,
|
||||
if (isFixedRateMode) 'toAmount': _request.toAmount,
|
||||
'address': _request.address,
|
||||
|
@ -241,10 +239,10 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
final type = isReverse ? 'reverse' : 'direct';
|
||||
final flow = getFlow(isFixedRateMode);
|
||||
final params = <String, String>{
|
||||
'fromCurrency': normalizeCryptoCurrency(from),
|
||||
'toCurrency': normalizeCryptoCurrency(to),
|
||||
'fromNetwork': networkFor(from),
|
||||
'toNetwork': networkFor(to),
|
||||
'fromCurrency': _normalizeCurrency(from),
|
||||
'toCurrency': _normalizeCurrency(to),
|
||||
'fromNetwork': _networkFor(from),
|
||||
'toNetwork': _networkFor(to),
|
||||
'type': type,
|
||||
'flow': flow
|
||||
};
|
||||
|
@ -273,25 +271,34 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
|||
}
|
||||
}
|
||||
|
||||
String networkFor(CryptoCurrency currency) {
|
||||
String _networkFor(CryptoCurrency currency) {
|
||||
switch (currency) {
|
||||
case CryptoCurrency.usdt:
|
||||
return CryptoCurrency.btc.title.toLowerCase();
|
||||
return 'btc';
|
||||
default:
|
||||
return currency.tag != null ? currency.tag!.toLowerCase() : currency.title.toLowerCase();
|
||||
}
|
||||
return currency.tag != null ? _normalizeTag(currency.tag!) : currency.title.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
String normalizeCryptoCurrency(CryptoCurrency currency) {
|
||||
String _normalizeCurrency(CryptoCurrency currency) {
|
||||
switch (currency) {
|
||||
case CryptoCurrency.zec:
|
||||
return 'zec';
|
||||
case CryptoCurrency.usdcpoly:
|
||||
return 'usdcmatic';
|
||||
case CryptoCurrency.maticpoly:
|
||||
return 'maticmainnet';
|
||||
default:
|
||||
return currency.title.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
String _normalizeTag(String tag) {
|
||||
switch (tag) {
|
||||
case 'POLY':
|
||||
return 'matic';
|
||||
case 'LN':
|
||||
return 'lightning';
|
||||
case 'AVAXC':
|
||||
return 'cchain';
|
||||
default:
|
||||
return tag.toLowerCase();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,7 +28,6 @@ class SideShiftExchangeProvider extends ExchangeProvider {
|
|||
CryptoCurrency.xhv,
|
||||
CryptoCurrency.dcr,
|
||||
CryptoCurrency.kmd,
|
||||
CryptoCurrency.mkr,
|
||||
CryptoCurrency.oxt,
|
||||
CryptoCurrency.pivx,
|
||||
CryptoCurrency.rune,
|
||||
|
|
|
@ -20,7 +20,6 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
bool useTorOnly;
|
||||
|
||||
static const List<CryptoCurrency> _notSupported = [
|
||||
CryptoCurrency.scrt,
|
||||
CryptoCurrency.stx,
|
||||
CryptoCurrency.zaddr,
|
||||
];
|
||||
|
@ -60,8 +59,8 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
}) async {
|
||||
final params = <String, String>{
|
||||
'api_key': apiKey,
|
||||
'ticker_from': request.from.title.toLowerCase(),
|
||||
'ticker_to': request.to.title.toLowerCase(),
|
||||
'ticker_from': _normalizeCurrency(request.from),
|
||||
'ticker_to': _normalizeCurrency(request.to),
|
||||
'network_from': _networkFor(request.from),
|
||||
'network_to': _networkFor(request.to),
|
||||
'payment': isFixedRateMode ? 'True' : 'False',
|
||||
|
@ -137,7 +136,7 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
required bool isFixedRateMode}) async {
|
||||
final params = <String, String>{
|
||||
'api_key': apiKey,
|
||||
'ticker': from.title.toLowerCase(),
|
||||
'ticker': _normalizeCurrency(from),
|
||||
'name': from.name,
|
||||
};
|
||||
|
||||
|
@ -177,8 +176,8 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
|
||||
final params = <String, String>{
|
||||
'api_key': apiKey,
|
||||
'ticker_from': from.title.toLowerCase(),
|
||||
'ticker_to': to.title.toLowerCase(),
|
||||
'ticker_from': _normalizeCurrency(from),
|
||||
'ticker_to': _normalizeCurrency(to),
|
||||
'network_from': _networkFor(from),
|
||||
'network_to': _networkFor(to),
|
||||
if (!isFixedRateMode) 'amount_from': amount.toString(),
|
||||
|
@ -279,6 +278,15 @@ class TrocadorExchangeProvider extends ExchangeProvider {
|
|||
}
|
||||
}
|
||||
|
||||
String _normalizeCurrency(CryptoCurrency currency) {
|
||||
switch (currency) {
|
||||
case CryptoCurrency.zec:
|
||||
return 'zec';
|
||||
default:
|
||||
return currency.title.toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
String _normalizeTag(String tag) {
|
||||
switch (tag) {
|
||||
case 'ETH':
|
||||
|
|
|
@ -133,11 +133,7 @@ Future<void> initializeAppConfigs() async {
|
|||
final templates = await Hive.openBox<Template>(Template.boxName);
|
||||
final exchangeTemplates = await Hive.openBox<ExchangeTemplate>(ExchangeTemplate.boxName);
|
||||
final anonpayInvoiceInfo = await Hive.openBox<AnonpayInvoiceInfo>(AnonpayInvoiceInfo.boxName);
|
||||
Box<UnspentCoinsInfo>? unspentCoinsInfoSource;
|
||||
|
||||
if (!isMoneroOnly) {
|
||||
unspentCoinsInfoSource = await Hive.openBox<UnspentCoinsInfo>(UnspentCoinsInfo.boxName);
|
||||
}
|
||||
final unspentCoinsInfoSource = await Hive.openBox<UnspentCoinsInfo>(UnspentCoinsInfo.boxName);
|
||||
|
||||
await initialSetup(
|
||||
sharedPreferences: await SharedPreferences.getInstance(),
|
||||
|
@ -169,7 +165,7 @@ Future<void> initialSetup(
|
|||
required Box<TransactionDescription> transactionDescriptions,
|
||||
required SecureStorage secureStorage,
|
||||
required Box<AnonpayInvoiceInfo> anonpayInvoiceInfo,
|
||||
Box<UnspentCoinsInfo>? unspentCoinsInfoSource,
|
||||
required Box<UnspentCoinsInfo> unspentCoinsInfoSource,
|
||||
int initialMigrationVersion = 15}) async {
|
||||
LanguageService.loadLocaleList();
|
||||
await defaultSettingsMigration(
|
||||
|
|
|
@ -2,14 +2,14 @@ part of 'monero.dart';
|
|||
|
||||
class CWMoneroAccountList extends MoneroAccountList {
|
||||
CWMoneroAccountList(this._wallet);
|
||||
|
||||
final Object _wallet;
|
||||
|
||||
@override
|
||||
@computed
|
||||
ObservableList<Account> get accounts {
|
||||
final moneroWallet = _wallet as MoneroWallet;
|
||||
final accounts = moneroWallet.walletAddresses.accountList
|
||||
.accounts
|
||||
final accounts = moneroWallet.walletAddresses.accountList.accounts
|
||||
.map((acc) => Account(id: acc.id, label: acc.label, balance: acc.balance))
|
||||
.toList();
|
||||
return ObservableList<Account>.of(accounts);
|
||||
|
@ -43,29 +43,25 @@ class CWMoneroAccountList extends MoneroAccountList {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<void> setLabelAccount(Object wallet, {required int accountIndex, required String label}) async {
|
||||
Future<void> setLabelAccount(Object wallet,
|
||||
{required int accountIndex, required String label}) async {
|
||||
final moneroWallet = wallet as MoneroWallet;
|
||||
await moneroWallet.walletAddresses.accountList
|
||||
.setLabelAccount(
|
||||
accountIndex: accountIndex,
|
||||
label: label);
|
||||
.setLabelAccount(accountIndex: accountIndex, label: label);
|
||||
}
|
||||
}
|
||||
|
||||
class CWMoneroSubaddressList extends MoneroSubaddressList {
|
||||
CWMoneroSubaddressList(this._wallet);
|
||||
|
||||
final Object _wallet;
|
||||
|
||||
@override
|
||||
@computed
|
||||
ObservableList<Subaddress> get subaddresses {
|
||||
final moneroWallet = _wallet as MoneroWallet;
|
||||
final subAddresses = moneroWallet.walletAddresses.subaddressList
|
||||
.subaddresses
|
||||
.map((sub) => Subaddress(
|
||||
id: sub.id,
|
||||
address: sub.address,
|
||||
label: sub.label))
|
||||
final subAddresses = moneroWallet.walletAddresses.subaddressList.subaddresses
|
||||
.map((sub) => Subaddress(id: sub.id, address: sub.address, label: sub.label))
|
||||
.toList();
|
||||
return ObservableList<Subaddress>.of(subAddresses);
|
||||
}
|
||||
|
@ -85,20 +81,18 @@ class CWMoneroSubaddressList extends MoneroSubaddressList {
|
|||
@override
|
||||
List<Subaddress> getAll(Object wallet) {
|
||||
final moneroWallet = wallet as MoneroWallet;
|
||||
return moneroWallet.walletAddresses
|
||||
.subaddressList
|
||||
return moneroWallet.walletAddresses.subaddressList
|
||||
.getAll()
|
||||
.map((sub) => Subaddress(id: sub.id, label: sub.label, address: sub.address))
|
||||
.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> addSubaddress(Object wallet, {required int accountIndex, required String label}) async {
|
||||
Future<void> addSubaddress(Object wallet,
|
||||
{required int accountIndex, required String label}) async {
|
||||
final moneroWallet = wallet as MoneroWallet;
|
||||
await moneroWallet.walletAddresses.subaddressList
|
||||
.addSubaddress(
|
||||
accountIndex: accountIndex,
|
||||
label: label);
|
||||
.addSubaddress(accountIndex: accountIndex, label: label);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -106,15 +100,13 @@ class CWMoneroSubaddressList extends MoneroSubaddressList {
|
|||
{required int accountIndex, required int addressIndex, required String label}) async {
|
||||
final moneroWallet = wallet as MoneroWallet;
|
||||
await moneroWallet.walletAddresses.subaddressList
|
||||
.setLabelSubaddress(
|
||||
accountIndex: accountIndex,
|
||||
addressIndex: addressIndex,
|
||||
label: label);
|
||||
.setLabelSubaddress(accountIndex: accountIndex, addressIndex: addressIndex, label: label);
|
||||
}
|
||||
}
|
||||
|
||||
class CWMoneroWalletDetails extends MoneroWalletDetails {
|
||||
CWMoneroWalletDetails(this._wallet);
|
||||
|
||||
final Object _wallet;
|
||||
|
||||
@computed
|
||||
|
@ -171,12 +163,11 @@ class CWMonero extends Monero {
|
|||
}
|
||||
|
||||
@override
|
||||
TransactionPriority getMoneroTransactionPrioritySlow()
|
||||
=> MoneroTransactionPriority.slow;
|
||||
TransactionPriority getMoneroTransactionPrioritySlow() => MoneroTransactionPriority.slow;
|
||||
|
||||
@override
|
||||
TransactionPriority getMoneroTransactionPriorityAutomatic()
|
||||
=> MoneroTransactionPriority.automatic;
|
||||
TransactionPriority getMoneroTransactionPriorityAutomatic() =>
|
||||
MoneroTransactionPriority.automatic;
|
||||
|
||||
@override
|
||||
TransactionPriority deserializeMoneroTransactionPriority({required int raw}) {
|
||||
|
@ -217,8 +208,8 @@ class CWMonero extends Monero {
|
|||
}
|
||||
|
||||
@override
|
||||
WalletCredentials createMoneroRestoreWalletFromKeysCredentials({
|
||||
required String name,
|
||||
WalletCredentials createMoneroRestoreWalletFromKeysCredentials(
|
||||
{required String name,
|
||||
required String spendKey,
|
||||
required String viewKey,
|
||||
required String address,
|
||||
|
@ -236,27 +227,22 @@ class CWMonero extends Monero {
|
|||
}
|
||||
|
||||
@override
|
||||
WalletCredentials createMoneroRestoreWalletFromSeedCredentials({
|
||||
required String name,
|
||||
WalletCredentials createMoneroRestoreWalletFromSeedCredentials(
|
||||
{required String name,
|
||||
required String password,
|
||||
required int height,
|
||||
required String mnemonic}) {
|
||||
return MoneroRestoreWalletFromSeedCredentials(
|
||||
name: name,
|
||||
password: password,
|
||||
height: height,
|
||||
mnemonic: mnemonic);
|
||||
name: name, password: password, height: height, mnemonic: mnemonic);
|
||||
}
|
||||
|
||||
@override
|
||||
WalletCredentials createMoneroNewWalletCredentials({
|
||||
required String name,
|
||||
required String language,
|
||||
String? password,}) {
|
||||
return MoneroNewWalletCredentials(
|
||||
name: name,
|
||||
password: password,
|
||||
language: language);
|
||||
String? password,
|
||||
}) {
|
||||
return MoneroNewWalletCredentials(name: name, password: password, language: language);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -267,15 +253,16 @@ class CWMonero extends Monero {
|
|||
'privateSpendKey': keys.privateSpendKey,
|
||||
'privateViewKey': keys.privateViewKey,
|
||||
'publicSpendKey': keys.publicSpendKey,
|
||||
'publicViewKey': keys.publicViewKey};
|
||||
'publicViewKey': keys.publicViewKey
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
Object createMoneroTransactionCreationCredentials({
|
||||
required List<Output> outputs,
|
||||
required TransactionPriority priority}) {
|
||||
Object createMoneroTransactionCreationCredentials(
|
||||
{required List<Output> outputs, required TransactionPriority priority}) {
|
||||
return MoneroTransactionCreationCredentials(
|
||||
outputs: outputs.map((out) => OutputInfo(
|
||||
outputs: outputs
|
||||
.map((out) => OutputInfo(
|
||||
fiatAmount: out.fiatAmount,
|
||||
cryptoAmount: out.cryptoAmount,
|
||||
address: out.address,
|
||||
|
@ -289,12 +276,10 @@ class CWMonero extends Monero {
|
|||
}
|
||||
|
||||
@override
|
||||
Object createMoneroTransactionCreationCredentialsRaw({
|
||||
required List<OutputInfo> outputs,
|
||||
required TransactionPriority priority}) {
|
||||
Object createMoneroTransactionCreationCredentialsRaw(
|
||||
{required List<OutputInfo> outputs, required TransactionPriority priority}) {
|
||||
return MoneroTransactionCreationCredentials(
|
||||
outputs: outputs,
|
||||
priority: priority as MoneroTransactionPriority);
|
||||
outputs: outputs, priority: priority as MoneroTransactionPriority);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -322,7 +307,8 @@ class CWMonero extends Monero {
|
|||
@override
|
||||
void setCurrentAccount(Object wallet, int id, String label, String? balance) {
|
||||
final moneroWallet = wallet as MoneroWallet;
|
||||
moneroWallet.walletAddresses.account = monero_account.Account(id: id, label: label, balance: balance);
|
||||
moneroWallet.walletAddresses.account =
|
||||
monero_account.Account(id: id, label: label, balance: balance);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -337,8 +323,9 @@ class CWMonero extends Monero {
|
|||
}
|
||||
|
||||
@override
|
||||
WalletService createMoneroWalletService(Box<WalletInfo> walletInfoSource) {
|
||||
return MoneroWalletService(walletInfoSource);
|
||||
WalletService createMoneroWalletService(
|
||||
Box<WalletInfo> walletInfoSource, Box<UnspentCoinsInfo> unspentCoinSource) {
|
||||
return MoneroWalletService(walletInfoSource, unspentCoinSource);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -358,4 +345,19 @@ class CWMonero extends Monero {
|
|||
final ptx = transaction as PendingMoneroTransaction;
|
||||
return {'id': ptx.id, 'hex': ptx.hex, 'key': ptx.txKey};
|
||||
}
|
||||
|
||||
@override
|
||||
List<Unspent> getUnspents(Object wallet) {
|
||||
final moneroWallet = wallet as MoneroWallet;
|
||||
return moneroWallet.unspentCoins
|
||||
.map((MoneroUnspent moneroUnspent) => Unspent(moneroUnspent.address, moneroUnspent.hash,
|
||||
moneroUnspent.value, 0, moneroUnspent.keyImage))
|
||||
.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
void updateUnspents(Object wallet) async {
|
||||
final moneroWallet = wallet as MoneroWallet;
|
||||
await moneroWallet.updateUnspent();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,6 @@ import 'package:cake_wallet/routes.dart';
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_new_vm.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_restoration_from_seed_vm.dart';
|
||||
import 'package:cake_wallet/exchange/trade.dart';
|
||||
import 'package:cw_core/transaction_info.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
|
@ -81,7 +80,6 @@ import 'package:cake_wallet/src/screens/monero_accounts/monero_account_edit_or_c
|
|||
import 'package:cake_wallet/src/screens/contact/contact_list_page.dart';
|
||||
import 'package:cake_wallet/src/screens/contact/contact_page.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_keys/wallet_keys_page.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/restore_wallet_from_seed_details.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/exchange_page.dart';
|
||||
import 'package:cake_wallet/src/screens/rescan/rescan_page.dart';
|
||||
import 'package:cake_wallet/src/screens/faq/faq_page.dart';
|
||||
|
@ -427,16 +425,6 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
builder: (_) =>
|
||||
getIt.get<BuyWebViewPage>(param1: args));
|
||||
|
||||
case Routes.restoreWalletFromSeedDetails:
|
||||
final args = settings.arguments as List;
|
||||
final walletRestorationFromSeedVM =
|
||||
getIt.get<WalletRestorationFromSeedVM>(param1: args);
|
||||
|
||||
return CupertinoPageRoute<void>(
|
||||
fullscreenDialog: true,
|
||||
builder: (_) => RestoreWalletFromSeedDetailsPage(
|
||||
walletRestorationFromSeedVM: walletRestorationFromSeedVM));
|
||||
|
||||
case Routes.exchange:
|
||||
return CupertinoPageRoute<void>(
|
||||
fullscreenDialog: true,
|
||||
|
|
|
@ -30,7 +30,6 @@ class Routes {
|
|||
static const tradeDetails = '/trade_details';
|
||||
static const exchangeFunds = '/exchange_funds';
|
||||
static const exchangeTrade = '/exchange_trade';
|
||||
static const restoreWalletFromSeedDetails = '/restore_from_seed_details';
|
||||
static const exchange = '/exchange';
|
||||
static const settings = '/settings';
|
||||
static const desktop_settings_page = '/desktop_settings_page';
|
||||
|
|
|
@ -127,9 +127,9 @@ class BackupPage extends BasePage {
|
|||
builder: (dialogContext) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).export_backup,
|
||||
alertContent: 'Please select destination for the backup file.',
|
||||
rightButtonText: 'Save to Downloads',
|
||||
leftButtonText: 'Share',
|
||||
alertContent: S.of(context).select_destination,
|
||||
rightButtonText: S.of(context).save_to_downloads,
|
||||
leftButtonText:S.of(context).share,
|
||||
actionRightButton: () async {
|
||||
final permission = await Permission.storage.request();
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:cake_wallet/core/auth_service.dart';
|
||||
import 'package:cake_wallet/entities/contact_base.dart';
|
||||
import 'package:cake_wallet/entities/contact_record.dart';
|
||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/exchange_page_theme.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
|
@ -39,7 +40,7 @@ class ContactListPage extends BasePage {
|
|||
children: <Widget>[
|
||||
Icon(
|
||||
Icons.add,
|
||||
color: Theme.of(context).dialogTheme.backgroundColor,
|
||||
color: Theme.of(context).appBarTheme.titleTextStyle!.color,
|
||||
size: 22.0,
|
||||
),
|
||||
ButtonTheme(
|
||||
|
@ -71,7 +72,7 @@ class ContactListPage extends BasePage {
|
|||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 20.0, bottom: 20.0),
|
||||
padding: EdgeInsets.all(20.0),
|
||||
child: Observer(builder: (_) {
|
||||
final contacts = contactListViewModel.contactsToShow;
|
||||
final walletContacts = contactListViewModel.walletContactsToShow;
|
||||
|
@ -131,7 +132,6 @@ class ContactListPage extends BasePage {
|
|||
}
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
padding: const EdgeInsets.only(top: 16, bottom: 16, right: 24),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
|
@ -146,7 +146,7 @@ class ContactListPage extends BasePage {
|
|||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context).dialogTheme.backgroundColor,
|
||||
color: Theme.of(context).extension<CakeTextTheme>()!.titleColor,
|
||||
),
|
||||
),
|
||||
))
|
||||
|
|
|
@ -2,6 +2,9 @@ import 'package:auto_size_text/auto_size_text.dart';
|
|||
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class DesktopActionButton extends StatelessWidget {
|
||||
|
|
|
@ -9,6 +9,7 @@ import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/dropdown_item_
|
|||
import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_arguments.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/themes/extensions/menu_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/menu_theme.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
|
||||
import 'package:cake_wallet/anonpay/anonpay_donation_link_info.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cake_wallet/entities/receive_page_option.dart';
|
||||
|
@ -6,9 +7,12 @@ import 'package:cake_wallet/src/screens/base_page.dart';
|
|||
import 'package:cake_wallet/src/screens/dashboard/widgets/present_receive_option_picker.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/src/widgets/gradient_background.dart';
|
||||
import 'package:cake_wallet/src/widgets/gradient_background.dart';
|
||||
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||
import 'package:cake_wallet/themes/extensions/receive_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/receive_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/utils/share_util.dart';
|
||||
|
@ -182,9 +186,8 @@ class AddressPage extends BasePage {
|
|||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(25)),
|
||||
border: Border.all(
|
||||
color: Theme.of(context)
|
||||
.extension<ReceivePageTheme>()!
|
||||
.iconsBackgroundColor,
|
||||
color:
|
||||
Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor,
|
||||
width: 1),
|
||||
color: Theme.of(context)
|
||||
.extension<SyncIndicatorTheme>()!
|
||||
|
@ -201,13 +204,14 @@ class AddressPage extends BasePage {
|
|||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor),
|
||||
color: Theme.of(context)
|
||||
.extension<SyncIndicatorTheme>()!
|
||||
.textColor),
|
||||
)),
|
||||
Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 14,
|
||||
color:
|
||||
Theme.of(context).extension<DashboardPageTheme>()!.textColor,
|
||||
color: Theme.of(context).extension<SyncIndicatorTheme>()!.textColor,
|
||||
)
|
||||
],
|
||||
),
|
||||
|
|
|
@ -2,7 +2,7 @@ import 'package:cake_wallet/routes.dart';
|
|||
import 'package:cake_wallet/src/screens/exchange_trade/information_page.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/themes/extensions/sync_indicator_theme.dart';
|
||||
import 'package:cake_wallet/utils/feature_flag.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -13,6 +13,8 @@ import 'package:cake_wallet/src/widgets/introducing_card.dart';
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/dashboard_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/balance_page_theme.dart';
|
||||
|
||||
class BalancePage extends StatelessWidget {
|
||||
BalancePage({required this.dashboardViewModel, required this.settingsStore});
|
||||
|
@ -77,9 +79,7 @@ class BalancePage extends StatelessWidget {
|
|||
return IntroducingCard(
|
||||
title: S.of(context).introducing_cake_pay,
|
||||
subTitle: S.of(context).cake_pay_learn_more,
|
||||
borderColor: settingsStore.currentTheme.type == ThemeType.bright
|
||||
? Color.fromRGBO(255, 255, 255, 0.2)
|
||||
: Colors.transparent,
|
||||
borderColor: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor,
|
||||
closeCard: dashboardViewModel.balanceViewModel.disableIntroCakePayCard);
|
||||
}
|
||||
return Container();
|
||||
|
@ -139,9 +139,7 @@ class BalancePage extends StatelessWidget {
|
|||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30.0),
|
||||
border: Border.all(
|
||||
color: settingsStore.currentTheme.type == ThemeType.bright
|
||||
? Color.fromRGBO(255, 255, 255, 0.2)
|
||||
: Colors.transparent,
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.cardBorderColor,
|
||||
width: 1,
|
||||
),
|
||||
color: Theme.of(context).extension<SyncIndicatorTheme>()!.syncedBackgroundColor,
|
||||
|
@ -282,7 +280,7 @@ class BalancePage extends StatelessWidget {
|
|||
fontSize: 20,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.assetTitleColor,
|
||||
height: 1,
|
||||
),
|
||||
maxLines: 1,
|
||||
|
@ -296,7 +294,7 @@ class BalancePage extends StatelessWidget {
|
|||
fontSize: 12,
|
||||
fontFamily: 'Lato',
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Theme.of(context).extension<DashboardPageTheme>()!.textColor,
|
||||
color: Theme.of(context).extension<BalancePageTheme>()!.textColor,
|
||||
height: 1,
|
||||
),
|
||||
),
|
||||
|
|
|
@ -5,6 +5,7 @@ import 'package:cake_wallet/di.dart';
|
|||
import 'package:cake_wallet/src/screens/exchange/widgets/desktop_exchange_cards_section.dart';
|
||||
import 'package:cake_wallet/src/screens/exchange/widgets/mobile_exchange_cards_section.dart';
|
||||
import 'package:cake_wallet/src/widgets/add_template_button.dart';
|
||||
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/utils/debounce.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
|
@ -629,7 +630,7 @@ class ExchangePage extends BasePage {
|
|||
},
|
||||
imageArrow: arrowBottomPurple,
|
||||
currencyButtonColor: Colors.transparent,
|
||||
addressButtonsColor: Theme.of(context).focusColor,
|
||||
addressButtonsColor: Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor,
|
||||
borderColor: Theme.of(context).extension<ExchangePageTheme>()!.textFieldBorderTopPanelColor,
|
||||
currencyValueValidator: (value) {
|
||||
return !exchangeViewModel.isFixedRateMode
|
||||
|
@ -677,7 +678,7 @@ class ExchangePage extends BasePage {
|
|||
exchangeViewModel.changeReceiveCurrency(currency: currency),
|
||||
imageArrow: arrowBottomCakeGreen,
|
||||
currencyButtonColor: Colors.transparent,
|
||||
addressButtonsColor: Theme.of(context).focusColor,
|
||||
addressButtonsColor: Theme.of(context).extension<SendPageTheme>()!.textFieldButtonColor,
|
||||
borderColor: Theme.of(context).extension<ExchangePageTheme>()!.textFieldBorderBottomPanelColor,
|
||||
currencyValueValidator: (value) {
|
||||
return exchangeViewModel.isFixedRateMode
|
||||
|
|
|
@ -99,8 +99,7 @@ class AnonPayInvoicePage extends BasePage {
|
|||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(bottom: 24),
|
||||
content: Container(
|
||||
decoration: ResponsiveLayoutUtil.instance.isMobile
|
||||
? BoxDecoration(
|
||||
decoration: ResponsiveLayoutUtil.instance.isMobile ? BoxDecoration(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(24), bottomRight: Radius.circular(24)),
|
||||
gradient: LinearGradient(
|
||||
|
@ -111,8 +110,7 @@ class AnonPayInvoicePage extends BasePage {
|
|||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
) : null,
|
||||
child: Observer(builder: (_) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.fromLTRB(24, 120, 24, 0),
|
||||
|
|
|
@ -1,145 +0,0 @@
|
|||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/core/wallet_name_validator.dart';
|
||||
import 'package:cake_wallet/core/execution_state.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_restoration_from_seed_vm.dart';
|
||||
|
||||
class RestoreWalletFromSeedDetailsPage extends BasePage {
|
||||
RestoreWalletFromSeedDetailsPage(
|
||||
{required this.walletRestorationFromSeedVM});
|
||||
|
||||
final WalletRestorationFromSeedVM walletRestorationFromSeedVM;
|
||||
|
||||
@override
|
||||
String get title => S.current.restore_wallet_restore_description;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) => RestoreFromSeedDetailsForm(
|
||||
walletRestorationFromSeedVM: walletRestorationFromSeedVM);
|
||||
}
|
||||
|
||||
class RestoreFromSeedDetailsForm extends StatefulWidget {
|
||||
RestoreFromSeedDetailsForm({required this.walletRestorationFromSeedVM});
|
||||
|
||||
final WalletRestorationFromSeedVM walletRestorationFromSeedVM;
|
||||
|
||||
@override
|
||||
_RestoreFromSeedDetailsFormState createState() =>
|
||||
_RestoreFromSeedDetailsFormState();
|
||||
}
|
||||
|
||||
class _RestoreFromSeedDetailsFormState
|
||||
extends State<RestoreFromSeedDetailsForm> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
final _blockchainHeightKey = GlobalKey<BlockchainHeightState>();
|
||||
final _nameController = TextEditingController();
|
||||
ReactionDisposer? _stateReaction;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_stateReaction = reaction((_) => widget.walletRestorationFromSeedVM.state,
|
||||
(ExecutionState state) {
|
||||
if (state is ExecutedSuccessfullyState) {
|
||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||
}
|
||||
|
||||
if (state is FailureState) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithOneAction(
|
||||
alertTitle: S.current.restore_title_from_seed,
|
||||
alertContent: state.error,
|
||||
buttonText: S.of(context).ok,
|
||||
buttonAction: () => Navigator.of(context).pop());
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
_nameController.addListener(
|
||||
() => widget.walletRestorationFromSeedVM.name = _nameController.text);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_nameController.dispose();
|
||||
_stateReaction?.reaction.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
child: ScrollableWithBottomSection(
|
||||
contentPadding: EdgeInsets.only(bottom: 24.0),
|
||||
content: Form(
|
||||
key: _formKey,
|
||||
child: Column(children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 20.0),
|
||||
child: BaseTextFormField(
|
||||
controller: _nameController,
|
||||
hintText: S.of(context).restore_wallet_name,
|
||||
validator: WalletNameValidator(),
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
if (widget.walletRestorationFromSeedVM.hasRestorationHeight) ... [
|
||||
BlockchainHeightWidget(
|
||||
key: _blockchainHeightKey,
|
||||
onHeightChange: (height) {
|
||||
widget.walletRestorationFromSeedVM.height = height;
|
||||
print(height);
|
||||
}),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(left: 40, right: 40, top: 24),
|
||||
child: Text(
|
||||
S.of(context).restore_from_date_or_blockheight,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context).hintColor
|
||||
),
|
||||
),
|
||||
)
|
||||
]
|
||||
]),
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.only(bottom: 24),
|
||||
bottomSection: Observer(builder: (_) {
|
||||
return LoadingPrimaryButton(
|
||||
onPressed: () {
|
||||
if (_formKey.currentState != null && _formKey.currentState!.validate()) {
|
||||
widget.walletRestorationFromSeedVM.create();
|
||||
}
|
||||
},
|
||||
isLoading:
|
||||
widget.walletRestorationFromSeedVM.state is IsExecutingState,
|
||||
text: S.of(context).restore_recover,
|
||||
color: Theme.of(context).primaryColor,
|
||||
textColor: Colors.white,
|
||||
isDisabled: _nameController.text.isNotEmpty,
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,36 +1,35 @@
|
|||
import 'package:cake_wallet/src/widgets/address_text_field.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/core/wallet_name_validator.dart';
|
||||
import 'package:cake_wallet/entities/generate_name.dart';
|
||||
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
class WalletRestoreFromKeysFrom extends StatefulWidget {
|
||||
WalletRestoreFromKeysFrom({
|
||||
required this.walletRestoreViewModel,
|
||||
required this.displayPrivateKeyField,
|
||||
required this.onHeightOrDateEntered,
|
||||
required this.displayWalletPassword,
|
||||
required this.onRepeatedPasswordChange,
|
||||
this.onPasswordChange,
|
||||
Key? key,
|
||||
this.onHeightOrDateEntered,})
|
||||
: super(key: key);
|
||||
}) : super(key: key);
|
||||
|
||||
final Function(bool)? onHeightOrDateEntered;
|
||||
final Function(bool) onHeightOrDateEntered;
|
||||
final WalletRestoreViewModel walletRestoreViewModel;
|
||||
final bool displayPrivateKeyField;
|
||||
final bool displayWalletPassword;
|
||||
final void Function(String)? onPasswordChange;
|
||||
final void Function(String)? onRepeatedPasswordChange;
|
||||
|
||||
@override
|
||||
WalletRestoreFromKeysFromState createState() =>
|
||||
WalletRestoreFromKeysFromState(displayWalletPassword: displayWalletPassword);
|
||||
WalletRestoreFromKeysFromState createState() => WalletRestoreFromKeysFromState(displayWalletPassword: displayWalletPassword);
|
||||
}
|
||||
|
||||
class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
|
||||
|
@ -41,6 +40,7 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
|
|||
addressController = TextEditingController(),
|
||||
viewKeyController = TextEditingController(),
|
||||
spendKeyController = TextEditingController(),
|
||||
privateKeyController = TextEditingController(),
|
||||
nameTextEditingController = TextEditingController(),
|
||||
passwordTextEditingController = displayWalletPassword ? TextEditingController() : null,
|
||||
repeatedPasswordTextEditingController = displayWalletPassword ? TextEditingController() : null;
|
||||
|
@ -52,6 +52,7 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
|
|||
final TextEditingController viewKeyController;
|
||||
final TextEditingController spendKeyController;
|
||||
final TextEditingController nameTextEditingController;
|
||||
final TextEditingController privateKeyController;
|
||||
final TextEditingController? passwordTextEditingController;
|
||||
final TextEditingController? repeatedPasswordTextEditingController;
|
||||
void Function()? passwordListener;
|
||||
|
@ -69,6 +70,12 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
|
|||
repeatedPasswordTextEditingController?.addListener(repeatedPasswordListener!);
|
||||
}
|
||||
super.initState();
|
||||
|
||||
privateKeyController.addListener(() {
|
||||
if (privateKeyController.text.isNotEmpty) {
|
||||
widget.onHeightOrDateEntered(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
@ -78,6 +85,7 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
|
|||
addressController.dispose();
|
||||
viewKeyController.dispose();
|
||||
spendKeyController.dispose();
|
||||
privateKeyController.dispose();
|
||||
passwordTextEditingController?.dispose();
|
||||
if (passwordListener != null) {
|
||||
passwordTextEditingController?.removeListener(passwordListener!);
|
||||
|
@ -95,7 +103,8 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
|
|||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
child: Form(
|
||||
key: formKey,
|
||||
child: Column(children: <Widget>[
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Stack(
|
||||
alignment: Alignment.centerRight,
|
||||
children: [
|
||||
|
@ -110,9 +119,8 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
|
|||
|
||||
setState(() {
|
||||
nameTextEditingController.text = rName;
|
||||
nameTextEditingController.selection =
|
||||
TextSelection.fromPosition(TextPosition(
|
||||
offset: nameTextEditingController.text.length));
|
||||
nameTextEditingController.selection = TextSelection.fromPosition(
|
||||
TextPosition(offset: nameTextEditingController.text.length));
|
||||
});
|
||||
},
|
||||
icon: Container(
|
||||
|
@ -125,7 +133,8 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
|
|||
height: 34,
|
||||
child: Image.asset(
|
||||
'assets/images/refresh_icon.png',
|
||||
color: Theme.of(context).extension<SendPageTheme>()!.textFieldButtonIconColor,
|
||||
color:
|
||||
Theme.of(context).extension<SendPageTheme>()!.textFieldButtonIconColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -146,29 +155,65 @@ class WalletRestoreFromKeysFromState extends State<WalletRestoreFromKeysFrom> {
|
|||
hintText: S.of(context).repeate_wallet_password,
|
||||
obscureText: true))],
|
||||
Container(height: 20),
|
||||
_restoreFromKeysFormFields(),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _restoreFromKeysFormFields() {
|
||||
if (widget.displayPrivateKeyField) {
|
||||
return AddressTextField(
|
||||
controller: privateKeyController,
|
||||
placeholder: S.of(context).private_key,
|
||||
options: [AddressTextFieldOption.paste],
|
||||
buttonColor: Theme.of(context).hintColor,
|
||||
onPushPasteButton: (_) {
|
||||
_pasteText();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return Column(
|
||||
children: [
|
||||
BaseTextFormField(
|
||||
controller: addressController,
|
||||
keyboardType: TextInputType.multiline,
|
||||
maxLines: null,
|
||||
hintText: S.of(context).restore_address),
|
||||
hintText: S.of(context).restore_address,
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.only(top: 20.0),
|
||||
child: BaseTextFormField(
|
||||
controller: viewKeyController,
|
||||
hintText: S.of(context).restore_view_key_private,
|
||||
maxLines: null)),
|
||||
maxLines: null,
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: EdgeInsets.only(top: 20.0),
|
||||
child: BaseTextFormField(
|
||||
controller: spendKeyController,
|
||||
hintText: S.of(context).restore_spend_key_private,
|
||||
maxLines: null)),
|
||||
maxLines: null,
|
||||
),
|
||||
),
|
||||
BlockchainHeightWidget(
|
||||
key: blockchainHeightKey,
|
||||
hasDatePicker: widget.walletRestoreViewModel.type != WalletType.haven,
|
||||
onHeightChange: (_) => null,
|
||||
onHeightOrDateEntered: widget.onHeightOrDateEntered)
|
||||
]),
|
||||
));
|
||||
onHeightOrDateEntered: widget.onHeightOrDateEntered,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _pasteText() async {
|
||||
final value = await Clipboard.getData('text/plain');
|
||||
|
||||
if (value?.text?.isNotEmpty ?? false) {
|
||||
privateKeyController.text = value!.text!;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
import 'package:cake_wallet/themes/extensions/keyboard_theme.dart';
|
||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:keyboard_actions/keyboard_actions.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
@ -19,10 +16,6 @@ import 'package:cake_wallet/src/screens/restore/wallet_restore_from_keys_form.da
|
|||
import 'package:cake_wallet/src/screens/restore/wallet_restore_from_seed_form.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/core/validator.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/core/seed_validator.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_mode.dart';
|
||||
import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart';
|
||||
|
||||
|
@ -79,6 +72,7 @@ class WalletRestorePage extends BasePage {
|
|||
_pages.add(WalletRestoreFromKeysFrom(
|
||||
key: walletRestoreFromKeysFormKey,
|
||||
walletRestoreViewModel: walletRestoreViewModel,
|
||||
displayPrivateKeyField: walletRestoreViewModel.hasRestoreFromPrivateKey,
|
||||
displayWalletPassword: walletRestoreViewModel.hasWalletPassword,
|
||||
onPasswordChange: (String password) => walletRestoreViewModel.walletPassword = password,
|
||||
onRepeatedPasswordChange: (String repeatedPassword) => walletRestoreViewModel.repeatedWalletPassword = repeatedPassword,
|
||||
|
@ -201,8 +195,12 @@ class WalletRestorePage extends BasePage {
|
|||
return LoadingPrimaryButton(
|
||||
onPressed: _confirmForm,
|
||||
text: S.of(context).restore_recover,
|
||||
color: Theme.of(context).extension<WalletListTheme>()!.createNewWalletButtonBackgroundColor,
|
||||
textColor: Theme.of(context).extension<WalletListTheme>()!.restoreWalletButtonTextColor,
|
||||
color: Theme.of(context)
|
||||
.extension<WalletListTheme>()!
|
||||
.createNewWalletButtonBackgroundColor,
|
||||
textColor: Theme.of(context)
|
||||
.extension<WalletListTheme>()!
|
||||
.restoreWalletButtonTextColor,
|
||||
isLoading: walletRestoreViewModel.state is IsExecutingState,
|
||||
isDisabled: !walletRestoreViewModel.isButtonEnabled,
|
||||
);
|
||||
|
@ -253,12 +251,19 @@ class WalletRestorePage extends BasePage {
|
|||
|
||||
credentials['name'] =
|
||||
walletRestoreFromSeedFormKey.currentState!.nameTextEditingController.text;
|
||||
} else {
|
||||
if (walletRestoreViewModel.hasRestoreFromPrivateKey) {
|
||||
credentials['private_key'] =
|
||||
walletRestoreFromKeysFormKey.currentState!.privateKeyController.text;
|
||||
} else {
|
||||
credentials['address'] = walletRestoreFromKeysFormKey.currentState!.addressController.text;
|
||||
credentials['viewKey'] = walletRestoreFromKeysFormKey.currentState!.viewKeyController.text;
|
||||
credentials['spendKey'] = walletRestoreFromKeysFormKey.currentState!.spendKeyController.text;
|
||||
credentials['spendKey'] =
|
||||
walletRestoreFromKeysFormKey.currentState!.spendKeyController.text;
|
||||
credentials['height'] =
|
||||
walletRestoreFromKeysFormKey.currentState!.blockchainHeightKey.currentState!.height;
|
||||
}
|
||||
|
||||
credentials['name'] =
|
||||
walletRestoreFromKeysFormKey.currentState!.nameTextEditingController.text;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
|
||||
|
||||
|
|
|
@ -100,7 +100,7 @@ class SendPage extends BasePage {
|
|||
AppBarStyle get appBarStyle => AppBarStyle.transparent;
|
||||
|
||||
double _sendCardHeight(BuildContext context) {
|
||||
final double initialHeight = sendViewModel.isElectrumWallet ? 490 : 465;
|
||||
final double initialHeight = sendViewModel.hasCoinControl ? 490 : 465;
|
||||
|
||||
if (!ResponsiveLayoutUtil.instance.isMobile) {
|
||||
return initialHeight - 66;
|
||||
|
|
|
@ -496,7 +496,7 @@ class SendCardState extends State<SendCard> with AutomaticKeepAliveClientMixin<S
|
|||
),
|
||||
),
|
||||
),
|
||||
if (sendViewModel.isElectrumWallet)
|
||||
if (sendViewModel.hasCoinControl)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 6),
|
||||
child: GestureDetector(
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.da
|
|||
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_theme_choice.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/view_model/settings/display_settings_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
@ -69,7 +70,7 @@ class DisplaySettingsPage extends BasePage {
|
|||
return LanguageService.list[code]?.toLowerCase().contains(searchText) ?? false;
|
||||
},
|
||||
),
|
||||
if (DeviceInfo.instance.isMobile)
|
||||
if (ResponsiveLayoutUtil.instance.isMobile && DeviceInfo.instance.isMobile)
|
||||
SettingsThemeChoicesCell(_displaySettingsViewModel),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -21,7 +21,6 @@ class TransactionDetailsPage extends BasePage {
|
|||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
// FIX-ME: Added `context` it was not used here before, maby bug ?
|
||||
return SectionStandardList(
|
||||
sectionCount: 1,
|
||||
itemCounter: (int _) => transactionDetailsViewModel.items.length,
|
||||
|
|
|
@ -9,7 +9,8 @@ class TextFieldListRow extends StatelessWidget {
|
|||
required this.value,
|
||||
this.titleFontSize = 14,
|
||||
this.valueFontSize = 16,
|
||||
this.onSubmitted})
|
||||
this.onSubmitted,
|
||||
this.onTapOutside})
|
||||
: _textController = TextEditingController() {
|
||||
_textController.text = value;
|
||||
}
|
||||
|
@ -19,6 +20,7 @@ class TextFieldListRow extends StatelessWidget {
|
|||
final double titleFontSize;
|
||||
final double valueFontSize;
|
||||
final Function(String value)? onSubmitted;
|
||||
final Function(String value)? onTapOutside;
|
||||
final TextEditingController _textController;
|
||||
|
||||
@override
|
||||
|
@ -58,6 +60,7 @@ class TextFieldListRow extends StatelessWidget {
|
|||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).extension<TransactionTradeTheme>()!.detailsTitlesColor),
|
||||
border: InputBorder.none),
|
||||
onTapOutside: (_) => onTapOutside?.call(_textController.text),
|
||||
onSubmitted: (value) => onSubmitted?.call(value),
|
||||
)
|
||||
]),
|
||||
|
|
|
@ -24,7 +24,6 @@ class UnspentCoinsDetailsPage extends BasePage {
|
|||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
// FIX-ME: Added `context` it was not used here before, maby bug ?
|
||||
return SectionStandardList(
|
||||
sectionCount: 1,
|
||||
itemCounter: (int _) => unspentCoinsDetailsViewModel.items.length,
|
||||
|
@ -45,6 +44,7 @@ class UnspentCoinsDetailsPage extends BasePage {
|
|||
return TextFieldListRow(
|
||||
title: item.title,
|
||||
value: item.value,
|
||||
onTapOutside: item.onSubmitted,
|
||||
onSubmitted: item.onSubmitted,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ class UnspentCoinsListItem extends StatelessWidget {
|
|||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
AutoSizeText(
|
||||
address,
|
||||
'${address.substring(0, 5)}...${address.substring(address.length-5)}', // ToDo: Maybe use address label
|
||||
style: TextStyle(
|
||||
color: addressColor,
|
||||
fontSize: 12,
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:cake_wallet/main.dart';
|
||||
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
||||
import 'package:cake_wallet/core/auth_service.dart';
|
||||
import 'package:cake_wallet/src/screens/wallet_unlock/wallet_unlock_arguments.dart';
|
||||
import 'package:cake_wallet/themes/extensions/receive_page_theme.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:cake_wallet/core/auth_service.dart';
|
||||
import 'package:cake_wallet/themes/extensions/receive_page_theme.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
|
||||
|
|
|
@ -17,24 +17,21 @@ class SearchBarWidget extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
return TextFormField(
|
||||
controller: searchController,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).extension<PickerTheme>()!.searchTextColor),
|
||||
style: TextStyle(color: Theme.of(context).extension<PickerTheme>()!.searchTextColor),
|
||||
decoration: InputDecoration(
|
||||
hintText: hintText ?? S.of(context).search_currency,
|
||||
hintStyle: TextStyle(
|
||||
color: Theme.of(context).extension<PickerTheme>()!.searchHintColor),
|
||||
hintStyle: TextStyle(color: Theme.of(context).extension<PickerTheme>()!.searchHintColor),
|
||||
prefixIcon: Image.asset("assets/images/search_icon.png",
|
||||
color: Theme.of(context).extension<PickerTheme>()!.searchIconColor),
|
||||
filled: true,
|
||||
fillColor: Theme.of(context)
|
||||
.extension<PickerTheme>()!
|
||||
.searchBackgroundFillColor,
|
||||
fillColor: Theme.of(context).extension<PickerTheme>()!.searchBackgroundFillColor,
|
||||
alignLabelWithHint: false,
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 4, horizontal: 16),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(borderRadius),
|
||||
borderSide: const BorderSide(
|
||||
color: Colors.transparent,
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).extension<PickerTheme>()!.searchBorderColor ??
|
||||
Colors.transparent,
|
||||
)),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(borderRadius),
|
||||
|
|
|
@ -1,16 +1,9 @@
|
|||
import 'package:cake_wallet/themes/extensions/cake_text_theme.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/src/widgets/validable_annotated_editable_text.dart';
|
||||
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/core/seed_validator.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/entities/mnemonic_item.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
||||
|
||||
class SeedWidget extends StatefulWidget {
|
||||
|
|
|
@ -6,13 +6,15 @@ class PickerTheme extends ThemeExtension<PickerTheme> {
|
|||
final Color searchBackgroundFillColor;
|
||||
final Color searchTextColor;
|
||||
final Color? searchHintColor;
|
||||
final Color? searchBorderColor;
|
||||
|
||||
PickerTheme(
|
||||
{required this.dividerColor,
|
||||
this.searchIconColor,
|
||||
required this.searchBackgroundFillColor,
|
||||
required this.searchTextColor,
|
||||
this.searchHintColor});
|
||||
this.searchHintColor,
|
||||
this.searchBorderColor});
|
||||
|
||||
@override
|
||||
PickerTheme copyWith(
|
||||
|
@ -20,14 +22,15 @@ class PickerTheme extends ThemeExtension<PickerTheme> {
|
|||
Color? searchIconColor,
|
||||
Color? searchBackgroundFillColor,
|
||||
Color? searchTextColor,
|
||||
Color? searchHintColor}) =>
|
||||
Color? searchHintColor,
|
||||
Color? searchBorderColor}) =>
|
||||
PickerTheme(
|
||||
dividerColor: dividerColor ?? this.dividerColor,
|
||||
searchIconColor: searchIconColor ?? this.searchIconColor,
|
||||
searchBackgroundFillColor:
|
||||
searchBackgroundFillColor ?? this.searchBackgroundFillColor,
|
||||
searchBackgroundFillColor: searchBackgroundFillColor ?? this.searchBackgroundFillColor,
|
||||
searchTextColor: searchTextColor ?? this.searchTextColor,
|
||||
searchHintColor: searchHintColor ?? this.searchHintColor);
|
||||
searchHintColor: searchHintColor ?? this.searchHintColor,
|
||||
searchBorderColor: searchBorderColor ?? this.searchBorderColor);
|
||||
|
||||
@override
|
||||
PickerTheme lerp(ThemeExtension<PickerTheme>? other, double t) {
|
||||
|
@ -36,19 +39,14 @@ class PickerTheme extends ThemeExtension<PickerTheme> {
|
|||
}
|
||||
|
||||
return PickerTheme(
|
||||
dividerColor:
|
||||
Color.lerp(dividerColor, other.dividerColor, t) ?? dividerColor,
|
||||
searchIconColor:
|
||||
Color.lerp(searchIconColor, other.searchIconColor, t) ??
|
||||
searchIconColor,
|
||||
searchBackgroundFillColor: Color.lerp(searchBackgroundFillColor,
|
||||
other.searchBackgroundFillColor, t) ??
|
||||
dividerColor: Color.lerp(dividerColor, other.dividerColor, t) ?? dividerColor,
|
||||
searchIconColor: Color.lerp(searchIconColor, other.searchIconColor, t) ?? searchIconColor,
|
||||
searchBackgroundFillColor:
|
||||
Color.lerp(searchBackgroundFillColor, other.searchBackgroundFillColor, t) ??
|
||||
searchBackgroundFillColor,
|
||||
searchTextColor:
|
||||
Color.lerp(searchTextColor, other.searchTextColor, t) ??
|
||||
searchTextColor,
|
||||
searchHintColor:
|
||||
Color.lerp(searchHintColor, other.searchHintColor, t) ??
|
||||
searchHintColor);
|
||||
searchTextColor: Color.lerp(searchTextColor, other.searchTextColor, t) ?? searchTextColor,
|
||||
searchHintColor: Color.lerp(searchHintColor, other.searchHintColor, t) ?? searchHintColor,
|
||||
searchBorderColor:
|
||||
Color.lerp(searchBorderColor, other.searchBorderColor, t) ?? searchBorderColor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,14 +39,12 @@ class HighContrastTheme extends MoneroLightTheme {
|
|||
|
||||
@override
|
||||
CakeTextTheme get cakeTextTheme => super.cakeTextTheme.copyWith(
|
||||
buttonTextColor: Colors.white,
|
||||
buttonSecondaryTextColor: Colors.white.withOpacity(0.5));
|
||||
buttonTextColor: Colors.white, buttonSecondaryTextColor: Colors.white.withOpacity(0.5));
|
||||
|
||||
@override
|
||||
SyncIndicatorTheme get syncIndicatorStyle =>
|
||||
super.syncIndicatorStyle.copyWith(
|
||||
textColor: colorScheme.background,
|
||||
syncedBackgroundColor: containerColor);
|
||||
SyncIndicatorTheme get syncIndicatorStyle => super
|
||||
.syncIndicatorStyle
|
||||
.copyWith(textColor: colorScheme.background, syncedBackgroundColor: containerColor);
|
||||
|
||||
@override
|
||||
BalancePageTheme get balancePageTheme => super.balancePageTheme.copyWith(
|
||||
|
@ -56,32 +54,28 @@ class HighContrastTheme extends MoneroLightTheme {
|
|||
balanceAmountColor: Colors.white);
|
||||
|
||||
@override
|
||||
DashboardPageTheme get dashboardPageTheme =>
|
||||
super.dashboardPageTheme.copyWith(
|
||||
DashboardPageTheme get dashboardPageTheme => super.dashboardPageTheme.copyWith(
|
||||
textColor: Colors.black,
|
||||
cardTextColor: Colors.white,
|
||||
mainActionsIconColor: Colors.white,
|
||||
indicatorDotTheme: IndicatorDotTheme(
|
||||
indicatorColor: Colors.grey, activeIndicatorColor: Colors.black));
|
||||
indicatorDotTheme:
|
||||
IndicatorDotTheme(indicatorColor: Colors.grey, activeIndicatorColor: Colors.black));
|
||||
|
||||
@override
|
||||
ExchangePageTheme get exchangePageTheme => super
|
||||
.exchangePageTheme
|
||||
.copyWith(firstGradientTopPanelColor: containerColor);
|
||||
ExchangePageTheme get exchangePageTheme => super.exchangePageTheme.copyWith(
|
||||
firstGradientTopPanelColor: primaryColor, firstGradientBottomPanelColor: containerColor);
|
||||
|
||||
@override
|
||||
SendPageTheme get sendPageTheme => super.sendPageTheme.copyWith(
|
||||
templateTitleColor: Colors.white,
|
||||
templateBackgroundColor: Colors.black,
|
||||
firstGradientColor: containerColor);
|
||||
firstGradientColor: primaryColor);
|
||||
|
||||
@override
|
||||
AddressTheme get addressTheme =>
|
||||
super.addressTheme.copyWith(actionButtonColor: Colors.grey);
|
||||
AddressTheme get addressTheme => super.addressTheme.copyWith(actionButtonColor: Colors.grey);
|
||||
|
||||
@override
|
||||
FilterTheme get filterTheme =>
|
||||
super.filterTheme.copyWith(iconColor: Colors.white);
|
||||
FilterTheme get filterTheme => super.filterTheme.copyWith(iconColor: Colors.white);
|
||||
|
||||
@override
|
||||
CakeMenuTheme get menuTheme => super.menuTheme.copyWith(
|
||||
|
@ -91,10 +85,11 @@ class HighContrastTheme extends MoneroLightTheme {
|
|||
|
||||
@override
|
||||
PickerTheme get pickerTheme => super.pickerTheme.copyWith(
|
||||
searchIconColor: Colors.white,
|
||||
searchHintColor: Colors.white,
|
||||
searchTextColor: Colors.white,
|
||||
searchBackgroundFillColor: Colors.grey);
|
||||
searchIconColor: primaryColor,
|
||||
searchHintColor: primaryColor,
|
||||
searchTextColor: primaryColor,
|
||||
searchBackgroundFillColor: Colors.white,
|
||||
searchBorderColor: primaryColor);
|
||||
|
||||
@override
|
||||
AccountListTheme get accountListTheme => super.accountListTheme.copyWith(
|
||||
|
@ -106,13 +101,10 @@ class HighContrastTheme extends MoneroLightTheme {
|
|||
|
||||
@override
|
||||
ReceivePageTheme get receivePageTheme => super.receivePageTheme.copyWith(
|
||||
tilesTextColor: Colors.white,
|
||||
iconsBackgroundColor: Colors.grey,
|
||||
iconsColor: Colors.black);
|
||||
tilesTextColor: Colors.white, iconsBackgroundColor: Colors.grey, iconsColor: Colors.black);
|
||||
|
||||
@override
|
||||
ThemeData get themeData => super.themeData.copyWith(
|
||||
disabledColor: Colors.grey,
|
||||
dialogTheme:
|
||||
super.themeData.dialogTheme.copyWith(backgroundColor: Colors.white));
|
||||
dialogTheme: super.themeData.dialogTheme.copyWith(backgroundColor: Colors.white));
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ import 'package:cake_wallet/themes/extensions/transaction_trade_theme.dart';
|
|||
import 'package:cake_wallet/themes/extensions/wallet_list_theme.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
enum ThemeType { bright, light, dark }
|
||||
enum ThemeType { light, bright, dark }
|
||||
|
||||
abstract class ThemeBase {
|
||||
ThemeBase({required this.raw}) {
|
||||
|
|
|
@ -149,6 +149,7 @@ class ExceptionHandler {
|
|||
"CERTIFICATE_VERIFY_FAILED",
|
||||
"Handshake error in client",
|
||||
"Error while launching http",
|
||||
"OS Error: Network is unreachable",
|
||||
];
|
||||
|
||||
static Future<void> _addDeviceInfo(File file) async {
|
||||
|
|
|
@ -107,7 +107,7 @@ abstract class DashboardViewModelBase with Store {
|
|||
name = wallet.name;
|
||||
type = wallet.type;
|
||||
isOutdatedElectrumWallet =
|
||||
wallet.type == WalletType.bitcoin && wallet.seed.split(' ').length < 24;
|
||||
wallet.type == WalletType.bitcoin && wallet.seed!.split(' ').length < 24;
|
||||
isShowFirstYatIntroduction = false;
|
||||
isShowSecondYatIntroduction = false;
|
||||
isShowThirdYatIntroduction = false;
|
||||
|
@ -328,7 +328,7 @@ abstract class DashboardViewModelBase with Store {
|
|||
type = wallet.type;
|
||||
name = wallet.name;
|
||||
isOutdatedElectrumWallet =
|
||||
wallet.type == WalletType.bitcoin && wallet.seed.split(' ').length < 24;
|
||||
wallet.type == WalletType.bitcoin && wallet.seed!.split(' ').length < 24;
|
||||
updateActions();
|
||||
|
||||
if (wallet.type == WalletType.monero) {
|
||||
|
|
|
@ -66,6 +66,9 @@ abstract class WalletRestorationFromQRVMBase extends WalletCreationVM with Store
|
|||
case WalletType.litecoin:
|
||||
return bitcoin!.createBitcoinRestoreWalletFromWIFCredentials(
|
||||
name: name, password: password, wif: wif);
|
||||
case WalletType.ethereum:
|
||||
return ethereum!.createEthereumRestoreWalletFromPrivateKey(
|
||||
name: name, password: password, privateKey: restoreWallet.privateKey!);
|
||||
default:
|
||||
throw Exception('Unexpected type: ${restoreWallet.type.toString()}');
|
||||
}
|
||||
|
|
|
@ -13,7 +13,8 @@ class RestoredWallet {
|
|||
this.txAmount,
|
||||
this.txDescription,
|
||||
this.recipientName,
|
||||
this.height});
|
||||
this.height,
|
||||
this.privateKey});
|
||||
|
||||
final WalletRestoreMode restoreMode;
|
||||
final WalletType type;
|
||||
|
@ -26,6 +27,7 @@ class RestoredWallet {
|
|||
final String? txDescription;
|
||||
final String? recipientName;
|
||||
final int? height;
|
||||
final String? privateKey;
|
||||
|
||||
factory RestoredWallet.fromKey(Map<String, dynamic> json) {
|
||||
final height = json['height'] as String?;
|
||||
|
@ -36,6 +38,7 @@ class RestoredWallet {
|
|||
spendKey: json['spend_key'] as String?,
|
||||
viewKey: json['view_key'] as String?,
|
||||
height: height != null ? int.parse(height) : 0,
|
||||
privateKey: json['private_key'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,10 @@ class WalletRestoreFromQRCode {
|
|||
getSeedPhraseFromUrl(queryParameters.toString(), credentials['type'] as WalletType);
|
||||
if (seed != null) {
|
||||
credentials['seed'] = seed;
|
||||
} else {
|
||||
credentials['private_key'] = queryParameters['private_key'];
|
||||
}
|
||||
|
||||
credentials.addAll(queryParameters);
|
||||
credentials['mode'] = getWalletRestoreMode(credentials);
|
||||
|
||||
|
@ -69,6 +72,8 @@ class WalletRestoreFromQRCode {
|
|||
case 'litecoin':
|
||||
case 'litecoin-wallet':
|
||||
return WalletType.litecoin;
|
||||
case 'ethereum-wallet':
|
||||
return WalletType.ethereum;
|
||||
default:
|
||||
throw Exception('Unexpected wallet type: ${scheme.toString()}');
|
||||
}
|
||||
|
@ -101,6 +106,7 @@ class WalletRestoreFromQRCode {
|
|||
}
|
||||
case WalletType.bitcoin:
|
||||
case WalletType.litecoin:
|
||||
case WalletType.ethereum:
|
||||
RegExp regex24 = RegExp(r'\b(\S+\b\s+){23}\S+\b');
|
||||
RegExp regex18 = RegExp(r'\b(\S+\b\s+){17}\S+\b');
|
||||
RegExp regex12 = RegExp(r'\b(\S+\b\s+){11}\S+\b');
|
||||
|
@ -152,6 +158,14 @@ class WalletRestoreFromQRCode {
|
|||
: throw Exception('Unexpected restore mode: spend_key or view_key is invalid');
|
||||
}
|
||||
|
||||
if (type == WalletType.ethereum && credentials.containsKey('private_key')) {
|
||||
final privateKey = credentials['private_key'] as String;
|
||||
if (privateKey.isEmpty) {
|
||||
throw Exception('Unexpected restore mode: private_key');
|
||||
}
|
||||
return WalletRestoreMode.keys;
|
||||
}
|
||||
|
||||
throw Exception('Unexpected restore mode: restore params are invalid');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -172,6 +172,10 @@ abstract class SendViewModelBase with Store {
|
|||
.where((template) => _isEqualCurrency(template.cryptoCurrency))
|
||||
.toList();
|
||||
|
||||
@computed
|
||||
bool get hasCoinControl =>
|
||||
_wallet.type == WalletType.bitcoin || _wallet.type == WalletType.litecoin || _wallet.type == WalletType.monero;
|
||||
|
||||
@computed
|
||||
bool get isElectrumWallet =>
|
||||
_wallet.type == WalletType.bitcoin || _wallet.type == WalletType.litecoin;
|
||||
|
@ -206,12 +210,12 @@ abstract class SendViewModelBase with Store {
|
|||
|
||||
@computed
|
||||
List<ContactRecord> get contactsToShow => contactListViewModel.contacts
|
||||
.where((element) => selectedCryptoCurrency == null || element.type == selectedCryptoCurrency)
|
||||
.where((element) => element.type == selectedCryptoCurrency)
|
||||
.toList();
|
||||
|
||||
@computed
|
||||
List<WalletContact> get walletContactsToShow => contactListViewModel.walletContacts
|
||||
.where((element) => selectedCryptoCurrency == null || element.type == selectedCryptoCurrency)
|
||||
.where((element) => element.type == selectedCryptoCurrency)
|
||||
.toList();
|
||||
|
||||
@action
|
||||
|
|
|
@ -23,6 +23,7 @@ abstract class UnspentCoinsDetailsViewModelBase with Store {
|
|||
note = unspentCoinsItem.note {
|
||||
items = [
|
||||
StandartListItem(title: S.current.transaction_details_amount, value: unspentCoinsItem.amount),
|
||||
StandartListItem(title: S.current.transaction_details_transaction_id, value: unspentCoinsItem.hash),
|
||||
StandartListItem(title: S.current.widgets_address, value: unspentCoinsItem.address),
|
||||
TextFieldListItem(
|
||||
title: S.current.note_tap_to_change,
|
||||
|
@ -42,8 +43,11 @@ abstract class UnspentCoinsDetailsViewModelBase with Store {
|
|||
unspentCoinsItem.isSending = !value;
|
||||
}
|
||||
await unspentCoinsListViewModel.saveUnspentCoinInfo(unspentCoinsItem);
|
||||
}),
|
||||
BlockExplorerListItem(
|
||||
})
|
||||
];
|
||||
|
||||
if ([WalletType.bitcoin, WalletType.litecoin].contains(unspentCoinsListViewModel.wallet.type)) {
|
||||
items.add(BlockExplorerListItem(
|
||||
title: S.current.view_in_block_explorer,
|
||||
value: _explorerDescription(unspentCoinsListViewModel.wallet.type),
|
||||
onTap: () {
|
||||
|
@ -52,9 +56,9 @@ abstract class UnspentCoinsDetailsViewModelBase with Store {
|
|||
_explorerUrl(unspentCoinsListViewModel.wallet.type, unspentCoinsItem.hash));
|
||||
return launchUrl(url);
|
||||
} catch (e) {}
|
||||
|
||||
})
|
||||
];
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
String _explorerUrl(WalletType type, String txId) {
|
||||
|
|
|
@ -13,7 +13,9 @@ abstract class UnspentCoinsItemBase with Store {
|
|||
required this.note,
|
||||
required this.isSending,
|
||||
required this.amountRaw,
|
||||
required this.vout});
|
||||
required this.vout,
|
||||
required this.keyImage
|
||||
});
|
||||
|
||||
@observable
|
||||
String address;
|
||||
|
@ -38,4 +40,7 @@ abstract class UnspentCoinsItemBase with Store {
|
|||
|
||||
@observable
|
||||
int vout;
|
||||
|
||||
@observable
|
||||
String? keyImage;
|
||||
}
|
|
@ -1,10 +1,15 @@
|
|||
import 'package:cw_core/unspent_coins_info.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cake_wallet/entities/unspent_transaction_output.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cake_wallet/view_model/unspent_coins/unspent_coins_item.dart';
|
||||
import 'package:cw_bitcoin/bitcoin_wallet.dart';
|
||||
import 'package:cw_core/unspent_coins_info.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cw_monero/monero_wallet.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
part 'unspent_coins_list_view_model.g.dart';
|
||||
|
||||
|
@ -14,7 +19,7 @@ abstract class UnspentCoinsListViewModelBase with Store {
|
|||
UnspentCoinsListViewModelBase(
|
||||
{required this.wallet, required Box<UnspentCoinsInfo> unspentCoinsInfo})
|
||||
: _unspentCoinsInfo = unspentCoinsInfo {
|
||||
bitcoin!.updateUnspents(wallet);
|
||||
_updateUnspents();
|
||||
}
|
||||
|
||||
WalletBase wallet;
|
||||
|
@ -22,11 +27,10 @@ abstract class UnspentCoinsListViewModelBase with Store {
|
|||
|
||||
@computed
|
||||
ObservableList<UnspentCoinsItem> get items =>
|
||||
ObservableList.of(bitcoin!.getUnspents(wallet).map((elem) {
|
||||
final amount = bitcoin!.formatterBitcoinAmountToString(amount: elem.value) +
|
||||
' ${wallet.currency.title}';
|
||||
ObservableList.of(_getUnspents().map((elem) {
|
||||
final amount = formatAmountToString(elem.value) + ' ${wallet.currency.title}';
|
||||
|
||||
final info = getUnspentCoinInfo(elem.hash, elem.address, elem.value, elem.vout);
|
||||
final info = getUnspentCoinInfo(elem.hash, elem.address, elem.value, elem.vout, elem.keyImage);
|
||||
|
||||
return UnspentCoinsItem(
|
||||
address: elem.address,
|
||||
|
@ -36,12 +40,14 @@ abstract class UnspentCoinsListViewModelBase with Store {
|
|||
note: info?.note ?? '',
|
||||
isSending: info?.isSending ?? true,
|
||||
amountRaw: elem.value,
|
||||
vout: elem.vout);
|
||||
vout: elem.vout,
|
||||
keyImage: elem.keyImage
|
||||
);
|
||||
}));
|
||||
|
||||
Future<void> saveUnspentCoinInfo(UnspentCoinsItem item) async {
|
||||
try {
|
||||
final info = getUnspentCoinInfo(item.hash, item.address, item.amountRaw, item.vout);
|
||||
final info = getUnspentCoinInfo(item.hash, item.address, item.amountRaw, item.vout, item.keyImage);
|
||||
if (info == null) {
|
||||
final newInfo = UnspentCoinsInfo(
|
||||
walletId: wallet.id,
|
||||
|
@ -51,10 +57,12 @@ abstract class UnspentCoinsListViewModelBase with Store {
|
|||
vout: item.vout,
|
||||
isFrozen: item.isFrozen,
|
||||
isSending: item.isSending,
|
||||
noteRaw: item.note);
|
||||
noteRaw: item.note,
|
||||
keyImage: item.keyImage
|
||||
);
|
||||
|
||||
await _unspentCoinsInfo.add(newInfo);
|
||||
bitcoin!.updateUnspents(wallet);
|
||||
_updateUnspents();
|
||||
wallet.updateBalance();
|
||||
return;
|
||||
}
|
||||
|
@ -63,19 +71,45 @@ abstract class UnspentCoinsListViewModelBase with Store {
|
|||
info.note = item.note;
|
||||
|
||||
await info.save();
|
||||
bitcoin!.updateUnspents(wallet);
|
||||
_updateUnspents();
|
||||
wallet.updateBalance();
|
||||
} catch (e) {
|
||||
print(e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
UnspentCoinsInfo? getUnspentCoinInfo(String hash, String address, int value, int vout) {
|
||||
UnspentCoinsInfo? getUnspentCoinInfo(String hash, String address, int value, int vout, String? keyImage) {
|
||||
return _unspentCoinsInfo.values.firstWhereOrNull((element) =>
|
||||
element.walletId == wallet.id &&
|
||||
element.hash == hash &&
|
||||
element.address == address &&
|
||||
element.value == value &&
|
||||
element.vout == vout);
|
||||
element.vout == vout &&
|
||||
element.keyImage == keyImage
|
||||
);
|
||||
}
|
||||
|
||||
String formatAmountToString(int fullBalance) {
|
||||
if (wallet.type == WalletType.monero)
|
||||
return monero!.formatterMoneroAmountToString(amount: fullBalance);
|
||||
if ([WalletType.bitcoin, WalletType.litecoin].contains(wallet.type))
|
||||
return bitcoin!.formatterBitcoinAmountToString(amount: fullBalance);
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
void _updateUnspents() {
|
||||
if (wallet.type == WalletType.monero)
|
||||
return monero!.updateUnspents(wallet);
|
||||
if ([WalletType.bitcoin, WalletType.litecoin].contains(wallet.type))
|
||||
return bitcoin!.updateUnspents(wallet);
|
||||
}
|
||||
|
||||
List<Unspent> _getUnspents() {
|
||||
if (wallet.type == WalletType.monero)
|
||||
return monero!.getUnspents(wallet);
|
||||
if ([WalletType.bitcoin, WalletType.litecoin].contains(wallet.type))
|
||||
return bitcoin!.getUnspents(wallet);
|
||||
return List.empty();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ abstract class WalletKeysViewModelBase with Store {
|
|||
StandartListItem(title: S.current.view_key_public, value: keys['publicViewKey']!),
|
||||
if (keys['privateViewKey'] != null)
|
||||
StandartListItem(title: S.current.view_key_private, value: keys['privateViewKey']!),
|
||||
StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed),
|
||||
StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed!),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -85,15 +85,23 @@ abstract class WalletKeysViewModelBase with Store {
|
|||
StandartListItem(title: S.current.view_key_public, value: keys['publicViewKey']!),
|
||||
if (keys['privateViewKey'] != null)
|
||||
StandartListItem(title: S.current.view_key_private, value: keys['privateViewKey']!),
|
||||
StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed),
|
||||
StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed!),
|
||||
]);
|
||||
}
|
||||
|
||||
if (_appStore.wallet!.type == WalletType.bitcoin ||
|
||||
_appStore.wallet!.type == WalletType.litecoin ||
|
||||
_appStore.wallet!.type == WalletType.ethereum) {
|
||||
_appStore.wallet!.type == WalletType.litecoin) {
|
||||
items.addAll([
|
||||
StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed),
|
||||
StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed!),
|
||||
]);
|
||||
}
|
||||
|
||||
if (_appStore.wallet!.type == WalletType.ethereum) {
|
||||
items.addAll([
|
||||
if (_appStore.wallet!.privateKey != null)
|
||||
StandartListItem(title: S.current.private_key, value: _appStore.wallet!.privateKey!),
|
||||
if (_appStore.wallet!.seed != null)
|
||||
StandartListItem(title: S.current.wallet_seed, value: _appStore.wallet!.seed!),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -139,7 +147,8 @@ abstract class WalletKeysViewModelBase with Store {
|
|||
Future<Map<String, String>> get _queryParams async {
|
||||
final restoreHeightResult = await restoreHeight;
|
||||
return {
|
||||
'seed': _appStore.wallet!.seed,
|
||||
if (_appStore.wallet!.seed != null) 'seed': _appStore.wallet!.seed!,
|
||||
if (_appStore.wallet!.privateKey != null) 'private_key': _appStore.wallet!.privateKey!,
|
||||
if (restoreHeightResult != null) ...{'height': restoreHeightResult}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,77 +0,0 @@
|
|||
import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cake_wallet/core/generate_wallet_password.dart';
|
||||
import 'package:cake_wallet/core/wallet_creation_service.dart';
|
||||
import 'package:cw_core/wallet_credentials.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_creation_vm.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
|
||||
part 'wallet_restoration_from_keys_vm.g.dart';
|
||||
|
||||
class WalletRestorationFromKeysVM = WalletRestorationFromKeysVMBase
|
||||
with _$WalletRestorationFromKeysVM;
|
||||
|
||||
abstract class WalletRestorationFromKeysVMBase extends WalletCreationVM
|
||||
with Store {
|
||||
WalletRestorationFromKeysVMBase(AppStore appStore,
|
||||
WalletCreationService walletCreationService, Box<WalletInfo> walletInfoSource,
|
||||
{required WalletType type, required this.language})
|
||||
: height = 0,
|
||||
viewKey = '',
|
||||
spendKey = '',
|
||||
wif = '',
|
||||
address = '',
|
||||
super(appStore, walletInfoSource, walletCreationService, type: type, isRecovery: true);
|
||||
|
||||
@observable
|
||||
int height;
|
||||
|
||||
@observable
|
||||
String viewKey;
|
||||
|
||||
@observable
|
||||
String spendKey;
|
||||
|
||||
@observable
|
||||
String wif;
|
||||
|
||||
@observable
|
||||
String address;
|
||||
|
||||
bool get hasRestorationHeight => type == WalletType.monero;
|
||||
|
||||
final String language;
|
||||
|
||||
@override
|
||||
WalletCredentials getCredentials(dynamic options) {
|
||||
final password = generateWalletPassword();
|
||||
|
||||
switch (type) {
|
||||
case WalletType.monero:
|
||||
return monero!.createMoneroRestoreWalletFromKeysCredentials(
|
||||
name: name,
|
||||
password: password,
|
||||
language: language,
|
||||
address: address,
|
||||
viewKey: viewKey,
|
||||
spendKey: spendKey,
|
||||
height: height);
|
||||
case WalletType.bitcoin:
|
||||
return bitcoin!.createBitcoinRestoreWalletFromWIFCredentials(
|
||||
name: name, password: password, wif: wif);
|
||||
default:
|
||||
throw Exception('Unexpected type: ${type.toString()}');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<WalletBase> process(WalletCredentials credentials) async =>
|
||||
walletCreationService.restoreFromKeys(credentials);
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/monero/monero.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cake_wallet/core/generate_wallet_password.dart';
|
||||
import 'package:cake_wallet/core/wallet_creation_service.dart';
|
||||
import 'package:cw_core/wallet_credentials.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_creation_vm.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
|
||||
part 'wallet_restoration_from_seed_vm.g.dart';
|
||||
|
||||
class WalletRestorationFromSeedVM = WalletRestorationFromSeedVMBase
|
||||
with _$WalletRestorationFromSeedVM;
|
||||
|
||||
abstract class WalletRestorationFromSeedVMBase extends WalletCreationVM
|
||||
with Store {
|
||||
WalletRestorationFromSeedVMBase(AppStore appStore,
|
||||
WalletCreationService walletCreationService, Box<WalletInfo> walletInfoSource,
|
||||
{required WalletType type, required this.language, this.seed = ''})
|
||||
: height = 0,
|
||||
super(appStore, walletInfoSource, walletCreationService, type: type, isRecovery: true);
|
||||
|
||||
@observable
|
||||
String seed;
|
||||
|
||||
@observable
|
||||
int height;
|
||||
|
||||
bool get hasRestorationHeight => type == WalletType.monero;
|
||||
|
||||
final String language;
|
||||
|
||||
@override
|
||||
WalletCredentials getCredentials(dynamic options) {
|
||||
final password = generateWalletPassword();
|
||||
|
||||
switch (type) {
|
||||
case WalletType.monero:
|
||||
return monero!.createMoneroRestoreWalletFromSeedCredentials(
|
||||
name: name, height: height, mnemonic: seed, password: password);
|
||||
case WalletType.bitcoin:
|
||||
return bitcoin!.createBitcoinRestoreWalletFromSeedCredentials(
|
||||
name: name, mnemonic: seed, password: password);
|
||||
default:
|
||||
throw Exception('Unexpected type: ${type.toString()}');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<WalletBase> process(WalletCredentials credentials) async =>
|
||||
walletCreationService.restoreFromSeed(credentials);
|
||||
}
|
|
@ -1,7 +1,4 @@
|
|||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/core/mnemonic_length.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
@ -19,7 +16,6 @@ import 'package:cake_wallet/view_model/restore/restore_mode.dart';
|
|||
|
||||
part 'wallet_restore_view_model.g.dart';
|
||||
|
||||
|
||||
class WalletRestoreViewModel = WalletRestoreViewModelBase
|
||||
with _$WalletRestoreViewModel;
|
||||
|
||||
|
@ -27,11 +23,13 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
WalletRestoreViewModelBase(AppStore appStore, WalletCreationService walletCreationService,
|
||||
Box<WalletInfo> walletInfoSource,
|
||||
{required WalletType type})
|
||||
: availableModes = (type == WalletType.monero || type == WalletType.haven)
|
||||
: availableModes =
|
||||
(type == WalletType.monero || type == WalletType.haven || type == WalletType.ethereum)
|
||||
? WalletRestoreMode.values
|
||||
: [WalletRestoreMode.seed],
|
||||
hasSeedLanguageSelector = type == WalletType.monero || type == WalletType.haven,
|
||||
hasBlockchainHeightLanguageSelector = type == WalletType.monero || type == WalletType.haven,
|
||||
hasRestoreFromPrivateKey = type == WalletType.ethereum,
|
||||
isButtonEnabled = false,
|
||||
mode = WalletRestoreMode.seed,
|
||||
super(appStore, walletInfoSource, walletCreationService, type: type, isRecovery: true) {
|
||||
|
@ -47,6 +45,7 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
final List<WalletRestoreMode> availableModes;
|
||||
final bool hasSeedLanguageSelector;
|
||||
final bool hasBlockchainHeightLanguageSelector;
|
||||
final bool hasRestoreFromPrivateKey;
|
||||
|
||||
@observable
|
||||
WalletRestoreMode mode;
|
||||
|
@ -97,17 +96,17 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
}
|
||||
|
||||
if (mode == WalletRestoreMode.keys) {
|
||||
final viewKey = options['viewKey'] as String;
|
||||
final spendKey = options['spendKey'] as String;
|
||||
final address = options['address'] as String;
|
||||
final viewKey = options['viewKey'] as String?;
|
||||
final spendKey = options['spendKey'] as String?;
|
||||
final address = options['address'] as String?;
|
||||
|
||||
if (type == WalletType.monero) {
|
||||
return monero!.createMoneroRestoreWalletFromKeysCredentials(
|
||||
name: name,
|
||||
height: height,
|
||||
spendKey: spendKey,
|
||||
viewKey: viewKey,
|
||||
address: address,
|
||||
spendKey: spendKey!,
|
||||
viewKey: viewKey!,
|
||||
address: address!,
|
||||
password: password,
|
||||
language: 'English');
|
||||
}
|
||||
|
@ -116,12 +115,20 @@ abstract class WalletRestoreViewModelBase extends WalletCreationVM with Store {
|
|||
return haven!.createHavenRestoreWalletFromKeysCredentials(
|
||||
name: name,
|
||||
height: height,
|
||||
spendKey: spendKey,
|
||||
viewKey: viewKey,
|
||||
address: address,
|
||||
spendKey: spendKey!,
|
||||
viewKey: viewKey!,
|
||||
address: address!,
|
||||
password: password,
|
||||
language: 'English');
|
||||
}
|
||||
|
||||
if (type == WalletType.ethereum) {
|
||||
return ethereum!.createEthereumRestoreWalletFromPrivateKey(
|
||||
name: name,
|
||||
privateKey: options['private_key'] as String,
|
||||
password: password,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
throw Exception('Unexpected type: ${type.toString()}');
|
||||
|
|
|
@ -8,7 +8,7 @@ class WalletSeedViewModel = WalletSeedViewModelBase with _$WalletSeedViewModel;
|
|||
abstract class WalletSeedViewModelBase with Store {
|
||||
WalletSeedViewModelBase(WalletBase wallet)
|
||||
: name = wallet.name,
|
||||
seed = wallet.seed;
|
||||
seed = wallet.seed!;
|
||||
|
||||
@observable
|
||||
String name;
|
||||
|
|
|
@ -92,7 +92,10 @@ 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
|
||||
translator:
|
||||
git:
|
||||
url: https://github.com/cake-tech/google-translator.git
|
||||
version: 1.0.0
|
||||
|
||||
flutter_icons:
|
||||
image_path: "assets/images/app_logo.png"
|
||||
|
|
|
@ -686,5 +686,13 @@
|
|||
"monero_light_theme": " ضوء مونيرو",
|
||||
"etherscan_history": "Etherscan تاريخ",
|
||||
"manage_nodes": "ﺪﻘﻌﻟﺍ ﺓﺭﺍﺩﺇ",
|
||||
"template_name": "اسم القالب"
|
||||
"template_name": "اسم القالب",
|
||||
"support_title_live_chat": "الدعم المباشر",
|
||||
"support_description_live_chat": "حرة وسريعة! ممثلو الدعم المدربين متاحون للمساعدة",
|
||||
"support_title_guides": "أدلة محفظة كعكة",
|
||||
"support_description_guides": "توثيق ودعم القضايا المشتركة",
|
||||
"support_title_other_links": "روابط دعم أخرى",
|
||||
"support_description_other_links": "انضم إلى مجتمعاتنا أو تصل إلينا شركائنا من خلال أساليب أخرى",
|
||||
"select_destination": ".ﻲﻃﺎﻴﺘﺣﻻﺍ ﺦﺴﻨﻟﺍ ﻒﻠﻣ ﺔﻬﺟﻭ ﺪﻳﺪﺤﺗ ءﺎﺟﺮﻟﺍ",
|
||||
"save_to_downloads": "ﺕﻼﻳﺰﻨﺘﻟﺍ ﻲﻓ ﻆﻔﺣ"
|
||||
}
|
||||
|
|
|
@ -683,5 +683,13 @@
|
|||
"monero_light_theme": "Лека тема Monero",
|
||||
"etherscan_history": "История на Etherscan",
|
||||
"manage_nodes": "Управление на възли",
|
||||
"template_name": "Име на шаблон"
|
||||
"template_name": "Име на шаблон",
|
||||
"support_title_live_chat": "Подкрепа на живо",
|
||||
"support_description_live_chat": "Безплатно и бързо! Обучени представители на подкрепата са на разположение за подпомагане",
|
||||
"support_title_guides": "Ръководства за портфейл за торта",
|
||||
"support_description_guides": "Документация и подкрепа за общи проблеми",
|
||||
"support_title_other_links": "Други връзки за поддръжка",
|
||||
"support_description_other_links": "Присъединете се към нашите общности или се свържете с нас нашите партньори чрез други методи",
|
||||
"select_destination": "Моля, изберете дестинация за архивния файл.",
|
||||
"save_to_downloads": "Запазване в Изтегляния"
|
||||
}
|
||||
|
|
|
@ -676,5 +676,13 @@
|
|||
"monero_light_theme": "Světlé téma Monero",
|
||||
"manage_nodes": "Spravovat uzly",
|
||||
"etherscan_history": "Historie Etherscanu",
|
||||
"template_name": "Název šablony"
|
||||
"template_name": "Název šablony",
|
||||
"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",
|
||||
"select_destination": "Vyberte cíl pro záložní soubor.",
|
||||
"save_to_downloads": "Uložit do Stažených souborů"
|
||||
}
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
"please_make_selection": "Bitte treffen Sie unten eine Auswahl zum Erstellen oder Wiederherstellen Ihrer Wallet.",
|
||||
"create_new": "Neue Wallet erstellen",
|
||||
"restore_wallet": "Wallet wiederherstellen",
|
||||
"monero_com": "Monero.com by Cake Wallet",
|
||||
"monero_com_wallet_text": "Awesome wallet for Monero",
|
||||
"haven_app": "Haven by Cake Wallet",
|
||||
"haven_app_wallet_text": "Awesome wallet for Haven",
|
||||
"monero_com": "Monero.com von Cake Wallet",
|
||||
"monero_com_wallet_text": "Eine großartige Wallet für Monero",
|
||||
"haven_app": "Haven von Cake Wallet",
|
||||
"haven_app_wallet_text": "Eine großartige Wallet für Haven",
|
||||
"accounts": "Konten",
|
||||
"edit": "Bearbeiten",
|
||||
"account": "Konto",
|
||||
|
@ -152,10 +152,10 @@
|
|||
"restore_wallet_restore_description": "Beschreibung zur Wallet-Wiederherstellung",
|
||||
"restore_new_seed": "Neuer Seed",
|
||||
"restore_active_seed": "Aktiver Seed",
|
||||
"restore_bitcoin_description_from_seed": "Stellen Sie Ihre Brieftasche aus dem 24-Wort-Kombinationscode wieder her",
|
||||
"restore_bitcoin_description_from_keys": "Stellen Sie Ihre Brieftasche aus der generierten WIF-Zeichenfolge aus Ihren privaten Schlüsseln wieder her",
|
||||
"restore_bitcoin_description_from_seed": "Stellen Sie Ihre Wallet aus dem 24-Wort-Kombinationscode wieder her",
|
||||
"restore_bitcoin_description_from_keys": "Stellen Sie Ihre Wallet aus der generierten WIF-Zeichenfolge aus Ihren privaten Schlüsseln wieder her",
|
||||
"restore_bitcoin_title_from_keys": "Aus WIF wiederherstellen",
|
||||
"restore_from_date_or_blockheight": "Bitte geben Sie ein Datum ein, das einige Tage vor dem Erstellen dieser Brieftasche liegt. Oder wenn Sie die Blockhöhe kennen, geben Sie stattdessen diese ein",
|
||||
"restore_from_date_or_blockheight": "Bitte geben Sie ein Datum ein, das einige Tage vor dem Erstellen dieser Wallet liegt. Oder wenn Sie die Blockhöhe kennen, geben Sie stattdessen diese ein",
|
||||
"seed_reminder": "Bitte notieren Sie diese für den Fall, dass Sie Ihr Telefon verlieren oder es kaputtgeht",
|
||||
"seed_title": "Seed",
|
||||
"seed_share": "Seed teilen",
|
||||
|
@ -409,7 +409,7 @@
|
|||
"buy_bitcoin": "Bitcoin kaufen",
|
||||
"buy_with": "Kaufen mit",
|
||||
"moonpay_alert_text": "Der Wert des Betrags muss größer oder gleich ${minAmount} ${fiatCurrency} sein",
|
||||
"outdated_electrum_wallet_receive_warning": "Wenn diese Brieftasche einen 12-Wort-Seed hat und in Cake erstellt wurde, zahlen Sie KEINE Bitcoins in diese Brieftasche ein. Alle auf diese Wallet übertragenen BTC können verloren gehen. Erstellen Sie eine neue 24-Wort-Wallet (tippen Sie auf das Menü oben rechts, wählen Sie Wallets, wählen Sie Neue Wallet erstellen und dann Bitcoin) und verschieben Sie Ihre BTC SOFORT dorthin. Neue (24-Wort-)BTC-Wallets von Cake sind sicher",
|
||||
"outdated_electrum_wallet_receive_warning": "Wenn diese Wallet einen 12-Wort-Seed hat und in Cake erstellt wurde, zahlen Sie KEINE Bitcoins in diese Wallet ein. Alle auf diese Wallet übertragenen BTC können verloren gehen. Erstellen Sie eine neue 24-Wort-Wallet (tippen Sie auf das Menü oben rechts, wählen Sie Wallets, wählen Sie Neue Wallet erstellen und dann Bitcoin) und verschieben Sie Ihre BTC SOFORT dorthin. Neue (24-Wort-)BTC-Wallets von Cake sind sicher",
|
||||
"do_not_show_me": "Zeig mir das nicht noch einmal",
|
||||
"unspent_coins_title": "Nicht ausgegebene Münzen",
|
||||
"unspent_coins_details_title": "Details zu nicht ausgegebenen Münzen",
|
||||
|
@ -602,10 +602,10 @@
|
|||
"sweeping_wallet_alert": "Das sollte nicht lange dauern. VERLASSEN SIE DIESEN BILDSCHIRM NICHT, ANDERNFALLS KÖNNEN DIE SWEPT-GELDER VERLOREN GEHEN",
|
||||
"decimal_places_error": "Zu viele Nachkommastellen",
|
||||
"edit_node": "Knoten bearbeiten",
|
||||
"frozen_balance": "Gefrorenes Gleichgewicht",
|
||||
"frozen_balance": "Gefrorenes Guthaben",
|
||||
"invoice_details": "Rechnungs-Details",
|
||||
"donation_link_details": "Details zum Spendenlink",
|
||||
"anonpay_description": "Generieren Sie ${type}. Der Empfänger kann ${method} mit jeder unterstützten Kryptowährung verwenden, und Sie erhalten Geld in dieser Brieftasche.",
|
||||
"anonpay_description": "Generieren Sie ${type}. Der Empfänger kann ${method} mit jeder unterstützten Kryptowährung verwenden, und Sie erhalten Geld in dieser Wallet.",
|
||||
"create_invoice": "Rechnung erstellen",
|
||||
"create_donation_link": "Spendenlink erstellen",
|
||||
"optional_email_hint": "Optionale Benachrichtigungs-E-Mail für den Zahlungsempfänger",
|
||||
|
@ -621,22 +621,22 @@
|
|||
"prevent_screenshots": "Verhindern Sie Screenshots und Bildschirmaufzeichnungen",
|
||||
"profile": "Profil",
|
||||
"close": "Schließen",
|
||||
"modify_2fa": "Kuchen 2FA ändern",
|
||||
"disable_cake_2fa": "Kuchen 2FA deaktivieren",
|
||||
"question_to_disable_2fa": "Sind Sie sicher, dass Sie Cake 2FA deaktivieren möchten? Für den Zugriff auf die Brieftasche und bestimmte Funktionen wird kein 2FA-Code mehr benötigt.",
|
||||
"modify_2fa": "Cake 2FA ändern",
|
||||
"disable_cake_2fa": "Cake 2FA deaktivieren",
|
||||
"question_to_disable_2fa": "Sind Sie sicher, dass Sie Cake 2FA deaktivieren möchten? Für den Zugriff auf die Wallet und bestimmte Funktionen wird kein 2FA-Code mehr benötigt.",
|
||||
"disable": "Deaktivieren",
|
||||
"setup_2fa": "Setup-Kuchen 2FA",
|
||||
"setup_2fa": "Setup-Cake 2FA",
|
||||
"verify_with_2fa": "Verifizieren Sie mit Cake 2FA",
|
||||
"totp_code": "TOTP-Code",
|
||||
"please_fill_totp": "Bitte geben Sie den 8-stelligen Code ein, der auf Ihrem anderen Gerät vorhanden ist",
|
||||
"totp_2fa_success": "Erfolg! Cake 2FA für dieses Wallet aktiviert. Denken Sie daran, Ihren mnemonischen Seed zu speichern, falls Sie den Zugriff auf die Brieftasche verlieren.",
|
||||
"totp_2fa_success": "Erfolg! Cake 2FA für dieses Wallet aktiviert. Denken Sie daran, Ihren mnemonischen Seed zu speichern, falls Sie den Zugriff auf die Wallet verlieren.",
|
||||
"totp_verification_success": "Verifizierung erfolgreich!",
|
||||
"totp_2fa_failure": "Falscher Code. Bitte versuchen Sie es mit einem anderen Code oder generieren Sie einen neuen geheimen Schlüssel. Verwenden Sie eine kompatible 2FA-App, die 8-stellige Codes und SHA512 unterstützt.",
|
||||
"enter_totp_code": "Bitte geben Sie den TOTP-Code ein.",
|
||||
"add_secret_code": "Fügen Sie diesen Geheimcode einem anderen Gerät hinzu",
|
||||
"totp_secret_code": "TOTP-Geheimcode",
|
||||
"important_note": "Wichtiger Hinweis",
|
||||
"setup_2fa_text": "Cake 2FA ist NICHT so sicher wie eine Kühllagerung. 2FA schützt vor grundlegenden Arten von Angriffen, z. B. wenn Ihr Freund Ihren Fingerabdruck bereitstellt, während Sie schlafen.\n\n Cake 2FA schützt NICHT vor einem kompromittierten Gerät durch einen raffinierten Angreifer.\n\n Wenn Sie den Zugriff auf Ihre 2FA-Codes verlieren , VERLIEREN SIE DEN ZUGANG ZU DIESEM WALLET. Sie müssen Ihre Brieftasche aus mnemonic Seed wiederherstellen. SIE MÜSSEN DESHALB IHRE MNEMONISCHEN SEEDS SICHERN! Außerdem kann jemand mit Zugriff auf Ihre mnemonischen Seed(s) Ihr Geld stehlen und Cake 2FA umgehen.\n\n Cake-Supportmitarbeiter können Ihnen nicht helfen, wenn Sie den Zugriff auf Ihre mnemonischen Seed(s) verlieren, da Cake ein Brieftasche ohne Verwahrung.",
|
||||
"setup_2fa_text": "Cake 2FA ist NICHT so sicher wie eine Kühllagerung. 2FA schützt vor grundlegenden Arten von Angriffen, z. B. wenn Ihr Freund Ihren Fingerabdruck bereitstellt, während Sie schlafen.\n\n Cake 2FA schützt NICHT vor einem kompromittierten Gerät durch einen raffinierten Angreifer.\n\n Wenn Sie den Zugriff auf Ihre 2FA-Codes verlieren , VERLIEREN SIE DEN ZUGANG ZU DIESEM WALLET. Sie müssen Ihre Wallet aus mnemonic Seed wiederherstellen. SIE MÜSSEN DESHALB IHRE MNEMONISCHEN SEEDS SICHERN! Außerdem kann jemand mit Zugriff auf Ihre mnemonischen Seed(s) Ihr Geld stehlen und Cake 2FA umgehen.\n\n Cake-Supportmitarbeiter können Ihnen nicht helfen, wenn Sie den Zugriff auf Ihre mnemonischen Seed(s) verlieren, da Cake Wallet eine Wallet ohne treuhänderische Verwahrung ist.",
|
||||
"setup_totp_recommended": "TOTP einrichten (empfohlen)",
|
||||
"disable_buy": "Kaufaktion deaktivieren",
|
||||
"disable_sell": "Verkaufsaktion deaktivieren",
|
||||
|
@ -646,7 +646,7 @@
|
|||
"high_contrast_theme": "Kontrastreiches Thema",
|
||||
"matrix_green_dark_theme": "Matrix Green Dark Theme",
|
||||
"monero_light_theme": "Monero Light-Thema",
|
||||
"cake_2fa_preset" : "Kuchen 2FA-Voreinstellung",
|
||||
"cake_2fa_preset" : "Cake 2FA-Voreinstellung",
|
||||
"narrow": "Eng",
|
||||
"normal": "Normal",
|
||||
"aggressive": "Übereifrig",
|
||||
|
@ -684,5 +684,13 @@
|
|||
"slidable": "Verschiebbar",
|
||||
"manage_nodes": "Knoten verwalten",
|
||||
"etherscan_history": "Etherscan-Geschichte",
|
||||
"template_name": "Vorlagenname"
|
||||
"template_name": "Vorlagenname",
|
||||
"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",
|
||||
"select_destination": "Bitte wählen Sie das Ziel für die Sicherungsdatei aus.",
|
||||
"save_to_downloads": "Unter „Downloads“ speichern"
|
||||
}
|
||||
|
|
|
@ -684,5 +684,13 @@
|
|||
"slidable": "Slidable",
|
||||
"manage_nodes": "Manage nodes",
|
||||
"etherscan_history": "Etherscan history",
|
||||
"template_name": "Template Name"
|
||||
"template_name": "Template Name",
|
||||
"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",
|
||||
"select_destination": "Please select destination for the backup file.",
|
||||
"save_to_downloads": "Save to Downloads"
|
||||
}
|
||||
|
|
|
@ -684,5 +684,13 @@
|
|||
"slidable": "deslizable",
|
||||
"manage_nodes": "Administrar nodos",
|
||||
"etherscan_history": "historia de etherscan",
|
||||
"template_name": "Nombre de la plantilla"
|
||||
"template_name": "Nombre de la plantilla",
|
||||
"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",
|
||||
"select_destination": "Seleccione el destino del archivo de copia de seguridad.",
|
||||
"save_to_downloads": "Guardar en Descargas"
|
||||
}
|
||||
|
|
|
@ -684,5 +684,13 @@
|
|||
"slidable": "Glissable",
|
||||
"manage_nodes": "Gérer les nœuds",
|
||||
"etherscan_history": "Historique d'Etherscan",
|
||||
"template_name": "Nom du modèle"
|
||||
"template_name": "Nom du modèle",
|
||||
"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",
|
||||
"select_destination": "Veuillez sélectionner la destination du fichier de sauvegarde.",
|
||||
"save_to_downloads": "Enregistrer dans les téléchargements"
|
||||
}
|
||||
|
|
|
@ -662,5 +662,13 @@
|
|||
"slidable": "Mai iya zamewa",
|
||||
"etherscan_history": "Etherscan tarihin kowane zamani",
|
||||
"manage_nodes": "Sarrafa nodes",
|
||||
"template_name": "Sunan Samfura"
|
||||
"template_name": "Sunan Samfura",
|
||||
"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",
|
||||
"select_destination": "Da fatan za a zaɓi wurin da za a yi wa madadin fayil ɗin.",
|
||||
"save_to_downloads": "Ajiye zuwa Zazzagewa"
|
||||
}
|
||||
|
|
|
@ -684,5 +684,13 @@
|
|||
"slidable": "फिसलने लायक",
|
||||
"manage_nodes": "नोड्स प्रबंधित करें",
|
||||
"etherscan_history": "इथरस्कैन इतिहास",
|
||||
"template_name": "टेम्पलेट नाम"
|
||||
"template_name": "टेम्पलेट नाम",
|
||||
"support_title_live_chat": "लाइव सहायता",
|
||||
"support_description_live_chat": "मुक्त और तेजी से! प्रशिक्षित सहायता प्रतिनिधि सहायता के लिए उपलब्ध हैं",
|
||||
"support_title_guides": "केक वॉलेट गाइड",
|
||||
"support_description_guides": "सामान्य मुद्दों के लिए प्रलेखन और समर्थन",
|
||||
"support_title_other_links": "अन्य समर्थन लिंक",
|
||||
"support_description_other_links": "हमारे समुदायों में शामिल हों या अन्य तरीकों के माध्यम से हमारे साथी तक पहुंचें",
|
||||
"select_destination": "कृपया बैकअप फ़ाइल के लिए गंतव्य का चयन करें।",
|
||||
"save_to_downloads": "डाउनलोड में सहेजें"
|
||||
}
|
||||
|
|
|
@ -684,5 +684,13 @@
|
|||
"slidable": "Klizna",
|
||||
"manage_nodes": "Upravljanje čvorovima",
|
||||
"etherscan_history": "Etherscan povijest",
|
||||
"template_name": "Naziv predloška"
|
||||
"template_name": "Naziv predloška",
|
||||
"support_title_live_chat": "Podrška uživo",
|
||||
"support_description_live_chat": "Besplatno i brzo! Obučeni predstavnici podrške dostupni su za pomoć",
|
||||
"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",
|
||||
"select_destination": "Odaberite odredište za datoteku sigurnosne kopije.",
|
||||
"save_to_downloads": "Spremi u Preuzimanja"
|
||||
}
|
||||
|
|
|
@ -673,5 +673,13 @@
|
|||
"monero_light_theme": "Tema Cahaya Monero",
|
||||
"manage_nodes": "Kelola node",
|
||||
"etherscan_history": "Sejarah Etherscan",
|
||||
"template_name": "Nama Templat"
|
||||
"template_name": "Nama Templat",
|
||||
"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",
|
||||
"select_destination": "Silakan pilih tujuan untuk file cadangan.",
|
||||
"save_to_downloads": "Simpan ke Unduhan"
|
||||
}
|
||||
|
|
|
@ -684,5 +684,13 @@
|
|||
"monero_light_theme": "Tema leggero Monero",
|
||||
"manage_nodes": "Gestisci i nodi",
|
||||
"etherscan_history": "Storia Etherscan",
|
||||
"template_name": "Nome modello"
|
||||
"template_name": "Nome modello",
|
||||
"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",
|
||||
"select_destination": "Seleziona la destinazione per il file di backup.",
|
||||
"save_to_downloads": "Salva in Download"
|
||||
}
|
||||
|
|
|
@ -684,5 +684,13 @@
|
|||
"monero_light_theme": "モネロ ライト テーマ",
|
||||
"manage_nodes": "ノードの管理",
|
||||
"etherscan_history": "イーサスキャンの歴史",
|
||||
"template_name": "テンプレート名"
|
||||
"template_name": "テンプレート名",
|
||||
"support_title_live_chat": "ライブサポート",
|
||||
"support_description_live_chat": "無料で速い!訓練されたサポート担当者が支援することができます",
|
||||
"support_title_guides": "ケーキウォレットガイド",
|
||||
"support_description_guides": "一般的な問題のドキュメントとサポート",
|
||||
"support_title_other_links": "その他のサポートリンク",
|
||||
"support_description_other_links": "私たちのコミュニティに参加するか、他の方法を通して私たちのパートナーに連絡してください",
|
||||
"select_destination": "バックアップファイルの保存先を選択してください。",
|
||||
"save_to_downloads": "ダウンロードに保存"
|
||||
}
|
||||
|
|
|
@ -684,5 +684,13 @@
|
|||
"monero_light_theme": "모네로 라이트 테마",
|
||||
"manage_nodes": "노드 관리",
|
||||
"etherscan_history": "이더스캔 역사",
|
||||
"template_name": "템플릿 이름"
|
||||
"template_name": "템플릿 이름",
|
||||
"support_title_live_chat": "실시간 지원",
|
||||
"support_description_live_chat": "자유롭고 빠릅니다! 훈련 된 지원 담당자가 지원할 수 있습니다",
|
||||
"support_title_guides": "케이크 지갑 가이드",
|
||||
"support_description_guides": "일반적인 문제에 대한 문서화 및 지원",
|
||||
"support_title_other_links": "다른 지원 링크",
|
||||
"support_description_other_links": "다른 방법을 통해 커뮤니티에 가입하거나 파트너에게 연락하십시오.",
|
||||
"select_destination": "백업 파일의 대상을 선택하십시오.",
|
||||
"save_to_downloads": "다운로드에 저장"
|
||||
}
|
||||
|
|
|
@ -682,5 +682,13 @@
|
|||
"monero_light_theme": "Monero Light အပြင်အဆင်",
|
||||
"manage_nodes": "ဆုံမှတ်များကို စီမံပါ။",
|
||||
"etherscan_history": "Etherscan သမိုင်း",
|
||||
"template_name": "နမူနာပုံစံ"
|
||||
"template_name": "နမူနာပုံစံ",
|
||||
"support_title_live_chat": "တိုက်ရိုက်ပံ့ပိုးမှု",
|
||||
"support_description_live_chat": "အခမဲ့နှင့်အစာရှောင်ခြင်း! လေ့ကျင့်ထားသောထောက်ခံသူကိုယ်စားလှယ်များသည်ကူညီနိုင်သည်",
|
||||
"support_title_guides": "ကိတ်မုန့်ပိုက်ဆံအိတ်လမ်းညွှန်များ",
|
||||
"support_description_guides": "ဘုံပြ issues နာများအတွက်စာရွက်စာတမ်းများနှင့်ထောက်ခံမှု",
|
||||
"support_title_other_links": "အခြားအထောက်အပံ့လင့်များ",
|
||||
"support_description_other_links": "ကျွန်ုပ်တို့၏လူမှုအသိုင်းအဝိုင်းများသို့ 0 င်ရောက်ပါ",
|
||||
"select_destination": "အရန်ဖိုင်အတွက် ဦးတည်ရာကို ရွေးပါ။",
|
||||
"save_to_downloads": "ဒေါင်းလုဒ်များထံ သိမ်းဆည်းပါ။"
|
||||
}
|
||||
|
|
|
@ -684,5 +684,13 @@
|
|||
"monero_light_theme": "Monero Light-thema",
|
||||
"manage_nodes": "Beheer knooppunten",
|
||||
"etherscan_history": "Etherscan-geschiedenis",
|
||||
"template_name": "Sjabloonnaam"
|
||||
"template_name": "Sjabloonnaam",
|
||||
"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",
|
||||
"select_destination": "Selecteer de bestemming voor het back-upbestand.",
|
||||
"save_to_downloads": "Opslaan in downloads"
|
||||
}
|
||||
|
|
|
@ -684,5 +684,13 @@
|
|||
"monero_light_theme": "Lekki motyw Monero",
|
||||
"manage_nodes": "Zarządzaj węzłami",
|
||||
"etherscan_history": "Historia Etherscanu",
|
||||
"template_name": "Nazwa szablonu"
|
||||
"template_name": "Nazwa szablonu",
|
||||
"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",
|
||||
"select_destination": "Wybierz miejsce docelowe dla pliku kopii zapasowej.",
|
||||
"save_to_downloads": "Zapisz w Pobranych"
|
||||
}
|
||||
|
|
|
@ -683,5 +683,13 @@
|
|||
"monero_light_theme": "Monero Light Theme",
|
||||
"manage_nodes": "Gerenciar nós",
|
||||
"etherscan_history": "história Etherscan",
|
||||
"template_name": "Nome do modelo"
|
||||
"template_name": "Nome do modelo",
|
||||
"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",
|
||||
"select_destination": "Selecione o destino para o arquivo de backup.",
|
||||
"save_to_downloads": "Salvar em Downloads"
|
||||
}
|
||||
|
|
|
@ -685,5 +685,13 @@
|
|||
"monero_light_theme": "Светлая тема Monero",
|
||||
"manage_nodes": "Управление узлами",
|
||||
"etherscan_history": "История Эфириума",
|
||||
"template_name": "Имя Шаблона"
|
||||
"template_name": "Имя Шаблона",
|
||||
"support_title_live_chat": "Живая поддержка",
|
||||
"support_description_live_chat": "Бесплатно и быстро! Обученные представители поддержки доступны для оказания помощи",
|
||||
"support_title_guides": "Корт -гиды",
|
||||
"support_description_guides": "Документация и поддержка общих вопросов",
|
||||
"support_title_other_links": "Другие ссылки на поддержку",
|
||||
"support_description_other_links": "Присоединяйтесь к нашим сообществам или охватите нас наших партнеров с помощью других методов",
|
||||
"select_destination": "Пожалуйста, выберите место для файла резервной копии.",
|
||||
"save_to_downloads": "Сохранить в загрузках"
|
||||
}
|
||||
|
|
|
@ -682,5 +682,13 @@
|
|||
"monero_light_theme": "ธีมแสง Monero",
|
||||
"manage_nodes": "จัดการโหนด",
|
||||
"etherscan_history": "ประวัติอีเธอร์สแกน",
|
||||
"template_name": "ชื่อแม่แบบ"
|
||||
"template_name": "ชื่อแม่แบบ",
|
||||
"support_title_live_chat": "การสนับสนุนสด",
|
||||
"support_description_live_chat": "ฟรีและรวดเร็ว! ตัวแทนฝ่ายสนับสนุนที่ผ่านการฝึกอบรมพร้อมให้ความช่วยเหลือ",
|
||||
"support_title_guides": "คู่มือกระเป๋าเงินเค้ก",
|
||||
"support_description_guides": "เอกสารและการสนับสนุนสำหรับปัญหาทั่วไป",
|
||||
"support_title_other_links": "ลิงค์สนับสนุนอื่น ๆ",
|
||||
"support_description_other_links": "เข้าร่วมชุมชนของเราหรือเข้าถึงเราพันธมิตรของเราผ่านวิธีการอื่น ๆ",
|
||||
"select_destination": "โปรดเลือกปลายทางสำหรับไฟล์สำรอง",
|
||||
"save_to_downloads": "บันทึกลงดาวน์โหลด"
|
||||
}
|
||||
|
|
|
@ -650,7 +650,6 @@
|
|||
"require_for_adding_contacts": "Kişi eklemek için gerekli",
|
||||
"require_for_creating_new_wallets": "Yeni cüzdan oluşturmak için gerekli",
|
||||
"require_for_all_security_and_backup_settings": "Tüm güvenlik ve yedekleme ayarları için iste",
|
||||
"disable_sell": "Satış işlemini devre dışı bırak",
|
||||
"available_balance_description": "Bu, cüzdanınızda harcayabileceğiniz miktar. Bu miktar, cüzdanınızdan çekilebilecek toplam bakiyeden daha düşük olabilir, çünkü bazı fonlar henüz kullanılamaz durumda olabilir.",
|
||||
"syncing_wallet_alert_title": "Cüzdanınız senkronize ediliyor",
|
||||
"syncing_wallet_alert_content": "Bakiyeniz ve işlem listeniz, en üstte \"SENKRONİZE EDİLDİ\" yazana kadar tamamlanmamış olabilir. Daha fazla bilgi edinmek için tıklayın/dokunun.",
|
||||
|
@ -683,5 +682,13 @@
|
|||
"monero_light_theme": "Monero Hafif Tema",
|
||||
"manage_nodes": "Düğümleri yönet",
|
||||
"etherscan_history": "Etherscan geçmişi",
|
||||
"template_name": "şablon adı"
|
||||
"template_name": "şablon adı",
|
||||
"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",
|
||||
"select_destination": "Lütfen yedekleme dosyası için hedef seçin.",
|
||||
"save_to_downloads": "İndirilenlere Kaydet"
|
||||
}
|
||||
|
|
|
@ -684,5 +684,13 @@
|
|||
"monero_light_theme": "Легка тема Monero",
|
||||
"manage_nodes": "Керуйте вузлами",
|
||||
"etherscan_history": "Історія Etherscan",
|
||||
"template_name": "Назва шаблону"
|
||||
"template_name": "Назва шаблону",
|
||||
"support_title_live_chat": "Жива підтримка",
|
||||
"support_description_live_chat": "Безкоштовно і швидко! Навчені представники підтримки доступні для надання допомоги",
|
||||
"support_title_guides": "Поклики для гаманців тортів",
|
||||
"support_description_guides": "Документація та підтримка загальних питань",
|
||||
"support_title_other_links": "Інші посилання на підтримку",
|
||||
"support_description_other_links": "Приєднуйтесь до наших спільнот або досягайте нас нашими партнерами іншими методами",
|
||||
"select_destination": "Виберіть місце призначення для файлу резервної копії.",
|
||||
"save_to_downloads": "Зберегти до завантажень"
|
||||
}
|
||||
|
|
|
@ -677,5 +677,13 @@
|
|||
"monero_light_theme": "مونیرو لائٹ تھیم",
|
||||
"manage_nodes": "۔ﮟﯾﺮﮐ ﻢﻈﻧ ﺎﮐ ﺱﮈﻮﻧ",
|
||||
"etherscan_history": "ﺦﯾﺭﺎﺗ ﯽﮐ ﻦﯿﮑﺳﺍ ﺮﮭﺘﯾﺍ",
|
||||
"template_name": "ٹیمپلیٹ کا نام"
|
||||
"template_name": "ٹیمپلیٹ کا نام",
|
||||
"support_title_live_chat": "براہ راست مدد",
|
||||
"support_description_live_chat": "مفت اور تیز! تربیت یافتہ معاون نمائندے مدد کے لئے دستیاب ہیں",
|
||||
"support_title_guides": "کیک پرس گائڈز",
|
||||
"support_description_guides": "عام مسائل کے لئے دستاویزات اور مدد",
|
||||
"support_title_other_links": "دوسرے سپورٹ لنکس",
|
||||
"support_description_other_links": "ہماری برادریوں میں شامل ہوں یا دوسرے طریقوں سے ہمارے شراکت داروں تک پہنچیں",
|
||||
"select_destination": "۔ﮟﯾﺮﮐ ﺏﺎﺨﺘﻧﺍ ﺎﮐ ﻝﺰﻨﻣ ﮯﯿﻟ ﮯﮐ ﻞﺋﺎﻓ ﭖﺍ ﮏﯿﺑ ﻡﺮﮐ ﮦﺍﺮﺑ",
|
||||
"save_to_downloads": "۔ﮟﯾﺮﮐ ﻅﻮﻔﺤﻣ ﮟﯿﻣ ﺯﮈﻮﻟ ﻥﺅﺍﮈ"
|
||||
}
|
||||
|
|
|
@ -667,10 +667,18 @@
|
|||
"manage_nodes": "Ṣakoso awọn apa",
|
||||
"etherscan_history": "Etherscan itan",
|
||||
"template_name": "Orukọ Awoṣe",
|
||||
"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",
|
||||
"monero_dark_theme": "Monero Dudu Akori",
|
||||
"bitcoin_dark_theme": "Bitcoin Dark Akori",
|
||||
"bitcoin_light_theme": "Bitcoin Light Akori",
|
||||
"high_contrast_theme": "Akori Iyatọ giga",
|
||||
"matrix_green_dark_theme": "Matrix Green Dark Akori",
|
||||
"monero_light_theme": "Monero Light Akori"
|
||||
"monero_light_theme": "Monero Light Akori",
|
||||
"select_destination": "Jọwọ yan ibi ti o nlo fun faili afẹyinti.",
|
||||
"save_to_downloads": "Fipamọ si Awọn igbasilẹ"
|
||||
}
|
||||
|
|
|
@ -678,10 +678,18 @@
|
|||
"manage_nodes": "管理节点",
|
||||
"etherscan_history": "以太扫描历史",
|
||||
"template_name": "模板名称",
|
||||
"support_title_live_chat": "实时支持",
|
||||
"support_description_live_chat": "免费快速!训练有素的支持代表可以协助",
|
||||
"support_title_guides": "蛋糕钱包指南",
|
||||
"support_description_guides": "对常见问题的文档和支持",
|
||||
"support_title_other_links": "其他支持链接",
|
||||
"support_description_other_links": "加入我们的社区或通过其他方法与我们联系我们的合作伙伴",
|
||||
"monero_dark_theme": "门罗币深色主题",
|
||||
"bitcoin_dark_theme": "比特币黑暗主题",
|
||||
"bitcoin_light_theme": "比特币浅色主题",
|
||||
"high_contrast_theme": "高对比度主题",
|
||||
"matrix_green_dark_theme": "矩阵绿暗主题",
|
||||
"monero_light_theme": "门罗币浅色主题"
|
||||
"monero_light_theme": "门罗币浅色主题",
|
||||
"select_destination": "请选择备份文件的目的地。",
|
||||
"save_to_downloads": "保存到下载"
|
||||
}
|
||||
|
|
1
scripts/docker/.gitignore
vendored
Normal file
1
scripts/docker/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
output/
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue