Merge branch 'main' of https://github.com/cake-tech/cake_wallet into CW-78-Ethereum

 Conflicts:
	cw_bitcoin/lib/bitcoin_wallet_service.dart
	cw_core/lib/crypto_currency.dart
	lib/core/address_validator.dart
	lib/di.dart
This commit is contained in:
OmarHatem 2023-07-19 01:58:29 +03:00
commit cf2f1e5692
106 changed files with 1209 additions and 670 deletions

View file

@ -22,7 +22,6 @@
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize" android:windowSoftInputMode="adjustResize"
android:screenOrientation="portrait"
android:exported="true"> android:exported="true">
<meta-data <meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable" android:name="io.flutter.embedding.android.SplashScreenDrawable"

BIN
assets/images/aave_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
assets/images/arb_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

BIN
assets/images/bat_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

BIN
assets/images/cake_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 582 B

BIN
assets/images/comp_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

BIN
assets/images/cro_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
assets/images/dydx_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

BIN
assets/images/ens_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

BIN
assets/images/frax_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
assets/images/ftm_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 576 B

BIN
assets/images/grt_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

BIN
assets/images/gtc_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
assets/images/gusd_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 596 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 683 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 570 B

BIN
assets/images/ldo_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

BIN
assets/images/nexo_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
assets/images/pepe_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 538 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 773 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 557 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 680 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 518 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
assets/images/tusd_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 838 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

BIN
assets/images/wbtc_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

BIN
assets/images/weth_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6 KiB

BIN
assets/images/zrx_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

View file

@ -1,3 +1,6 @@
Enable iPad/Tablet separate layout from mobile UI Improved edit/delete for nodes and wallets
SideShift update and fixes Wallets can now be renamed
Bug Fixes Accessibility improvements
Improve Monero wallet rescan
Additional exchange assets: SHIB, AAVE, ARB, BAT, COMP, CRO, ENS, FTM, FRAX, GUSD, GTC, GRT, LDO, NEXO, CAKE, PEPE, STORJ, TUSD, WBTC, WETH, ZRX, DYDX, STETH
Cake Pay is temporarily removed, see https://cakelabs.com/news/cake-pay-mobile-to-shut-down/

View file

@ -1,4 +1,7 @@
Enable iPad/Tablet separate layout from mobile UI Improved edit/delete for nodes and wallets
SideShift update and fixes Wallets can now be renamed
Add MoonPay sell Accessibility improvements
Bug Fixes Bitcoin transaction bug fixes
Improve Monero wallet rescan
Additional exchange assets: SHIB, AAVE, ARB, BAT, COMP, CRO, ENS, FTM, FRAX, GUSD, GTC, GRT, LDO, NEXO, CAKE, PEPE, STORJ, TUSD, WBTC, WETH, ZRX, DYDX, STETH
Cake Pay is temporarily removed, see https://cakelabs.com/news/cake-pay-mobile-to-shut-down/

View file

@ -52,9 +52,32 @@ class BitcoinWalletService extends WalletService<
} }
@override @override
Future<void> remove(String wallet) async => Future<void> remove(String wallet) async {
File(await pathForWalletDir(name: wallet, type: getType())) File(await pathForWalletDir(name: wallet, type: getType()))
.delete(recursive: true); .delete(recursive: true);
final walletInfo = walletInfoSource.values.firstWhereOrNull(
(info) => info.id == WalletBase.idFor(wallet, getType()))!;
await walletInfoSource.delete(walletInfo.key);
}
@override
Future<void> rename(String currentName, String password, String newName) async {
final currentWalletInfo = walletInfoSource.values.firstWhereOrNull(
(info) => info.id == WalletBase.idFor(currentName, getType()))!;
final currentWallet = await BitcoinWalletBase.open(
password: password,
name: currentName,
walletInfo: currentWalletInfo,
unspentCoinsInfo: unspentCoinsInfoSource);
await currentWallet.renameWalletFiles(newName);
final newWalletInfo = currentWalletInfo;
newWalletInfo.id = WalletBase.idFor(newName, getType());
newWalletInfo.name = newName;
await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
}
@override @override
Future<BitcoinWallet> restoreFromKeys( Future<BitcoinWallet> restoreFromKeys(

View file

@ -66,8 +66,30 @@ class ElectrumClient {
socket!.listen((Uint8List event) { socket!.listen((Uint8List event) {
try { try {
final msg = utf8.decode(event.toList()); final msg = utf8.decode(event.toList());
final response = final messagesList = msg.split("\n");
json.decode(msg) as Map<String, dynamic>; for (var message in messagesList) {
if (message.isEmpty) {
continue;
}
_parseResponse(message);
}
} catch (e) {
print(e.toString());
}
}, onError: (Object error) {
print(error.toString());
unterminatedString = '';
_setIsConnected(false);
}, onDone: () {
unterminatedString = '';
_setIsConnected(false);
});
keepAlive();
}
void _parseResponse(String message) {
try {
final response = json.decode(message) as Map<String, dynamic>;
_handleResponse(response); _handleResponse(response);
} on FormatException catch (e) { } on FormatException catch (e) {
final msg = e.message.toLowerCase(); final msg = e.message.toLowerCase();
@ -92,8 +114,7 @@ class ElectrumClient {
return; return;
} }
final source = utf8.decode(event.toList()); unterminatedString += message;
unterminatedString += source;
if (isJSONStringCorrect(unterminatedString)) { if (isJSONStringCorrect(unterminatedString)) {
final response = final response =
@ -105,13 +126,6 @@ class ElectrumClient {
} catch (e) { } catch (e) {
print(e.toString()); print(e.toString());
} }
}, onError: (Object error) {
print(error.toString());
_setIsConnected(false);
}, onDone: () {
_setIsConnected(false);
});
keepAlive();
} }
void keepAlive() { void keepAlive() {
@ -217,7 +231,7 @@ class ElectrumClient {
Future<Map<String, dynamic>> getTransactionRaw( Future<Map<String, dynamic>> getTransactionRaw(
{required String hash}) async => {required String hash}) async =>
call(method: 'blockchain.transaction.get', params: [hash, true]) callWithTimeout(method: 'blockchain.transaction.get', params: [hash, true], timeout: 10000)
.then((dynamic result) { .then((dynamic result) {
if (result is Map<String, dynamic>) { if (result is Map<String, dynamic>) {
return result; return result;
@ -228,7 +242,7 @@ class ElectrumClient {
Future<String> getTransactionHex( Future<String> getTransactionHex(
{required String hash}) async => {required String hash}) async =>
call(method: 'blockchain.transaction.get', params: [hash, false]) callWithTimeout(method: 'blockchain.transaction.get', params: [hash, false], timeout: 10000)
.then((dynamic result) { .then((dynamic result) {
if (result is String) { if (result is String) {
return result; return result;

View file

@ -9,7 +9,7 @@ import 'package:cw_bitcoin/electrum_transaction_info.dart';
part 'electrum_transaction_history.g.dart'; part 'electrum_transaction_history.g.dart';
const _transactionsHistoryFileName = 'transactions.json'; const transactionsHistoryFileName = 'transactions.json';
class ElectrumTransactionHistory = ElectrumTransactionHistoryBase class ElectrumTransactionHistory = ElectrumTransactionHistoryBase
with _$ElectrumTransactionHistory; with _$ElectrumTransactionHistory;
@ -42,7 +42,7 @@ abstract class ElectrumTransactionHistoryBase
try { try {
final dirPath = final dirPath =
await pathForWalletDir(name: walletInfo.name, type: walletInfo.type); await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
final path = '$dirPath/$_transactionsHistoryFileName'; final path = '$dirPath/$transactionsHistoryFileName';
final data = final data =
json.encode({'height': _height, 'transactions': transactions}); json.encode({'height': _height, 'transactions': transactions});
await writeData(path: path, password: _password, data: data); await writeData(path: path, password: _password, data: data);
@ -59,7 +59,7 @@ abstract class ElectrumTransactionHistoryBase
Future<Map<String, dynamic>> _read() async { Future<Map<String, dynamic>> _read() async {
final dirPath = final dirPath =
await pathForWalletDir(name: walletInfo.name, type: walletInfo.type); await pathForWalletDir(name: walletInfo.name, type: walletInfo.type);
final path = '$dirPath/$_transactionsHistoryFileName'; final path = '$dirPath/$transactionsHistoryFileName';
final content = await read(path: path, password: _password); final content = await read(path: path, password: _password);
return json.decode(content) as Map<String, dynamic>; return json.decode(content) as Map<String, dynamic>;
} }

View file

@ -1,5 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/unspent_coins_info.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
@ -430,6 +431,28 @@ abstract class ElectrumWalletBase extends WalletBase<ElectrumBalance,
await transactionHistory.save(); await transactionHistory.save();
} }
Future<void> renameWalletFiles(String newWalletName) async {
final currentWalletPath = await pathForWallet(name: walletInfo.name, type: type);
final currentWalletFile = File(currentWalletPath);
final currentDirPath =
await pathForWalletDir(name: walletInfo.name, type: type);
final currentTransactionsFile = File('$currentDirPath/$transactionsHistoryFileName');
// Copies current wallet files into new wallet name's dir and files
if (currentWalletFile.existsSync()) {
final newWalletPath = await pathForWallet(name: newWalletName, type: type);
await currentWalletFile.copy(newWalletPath);
}
if (currentTransactionsFile.existsSync()) {
final newDirPath = await pathForWalletDir(name: newWalletName, type: type);
await currentTransactionsFile.copy('$newDirPath/$transactionsHistoryFileName');
}
// Delete old name's dir and files
await Directory(currentDirPath).delete(recursive: true);
}
@override @override
Future<void> changePassword(String password) async { Future<void> changePassword(String password) async {
_password = password; _password = password;

View file

@ -53,9 +53,32 @@ class LitecoinWalletService extends WalletService<
} }
@override @override
Future<void> remove(String wallet) async => Future<void> remove(String wallet) async {
File(await pathForWalletDir(name: wallet, type: getType())) File(await pathForWalletDir(name: wallet, type: getType()))
.delete(recursive: true); .delete(recursive: true);
final walletInfo = walletInfoSource.values.firstWhereOrNull(
(info) => info.id == WalletBase.idFor(wallet, getType()))!;
await walletInfoSource.delete(walletInfo.key);
}
@override
Future<void> rename(String currentName, String password, String newName) async {
final currentWalletInfo = walletInfoSource.values.firstWhereOrNull(
(info) => info.id == WalletBase.idFor(currentName, getType()))!;
final currentWallet = await LitecoinWalletBase.open(
password: password,
name: currentName,
walletInfo: currentWalletInfo,
unspentCoinsInfo: unspentCoinsInfoSource);
await currentWallet.renameWalletFiles(newName);
final newWalletInfo = currentWalletInfo;
newWalletInfo.id = WalletBase.idFor(newName, getType());
newWalletInfo.name = newName;
await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
}
@override @override
Future<LitecoinWallet> restoreFromKeys( Future<LitecoinWallet> restoreFromKeys(

View file

@ -68,6 +68,28 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
CryptoCurrency.stx, CryptoCurrency.stx,
CryptoCurrency.btcln, CryptoCurrency.btcln,
CryptoCurrency.shib, CryptoCurrency.shib,
CryptoCurrency.aave,
CryptoCurrency.arb,
CryptoCurrency.bat,
CryptoCurrency.comp,
CryptoCurrency.cro,
CryptoCurrency.ens,
CryptoCurrency.ftm,
CryptoCurrency.frax,
CryptoCurrency.gusd,
CryptoCurrency.gtc,
CryptoCurrency.grt,
CryptoCurrency.ldo,
CryptoCurrency.nexo,
CryptoCurrency.cake,
CryptoCurrency.pepe,
CryptoCurrency.storj,
CryptoCurrency.tusd,
CryptoCurrency.wbtc,
CryptoCurrency.weth,
CryptoCurrency.zrx,
CryptoCurrency.dydx,
CryptoCurrency.steth,
]; ];
static const havenCurrencies = [ static const havenCurrencies = [
@ -122,7 +144,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
static const ape = CryptoCurrency(title: 'APE', tag: 'ETH', fullName: 'ApeCoin', raw: 30, name: 'ape', iconPath: 'assets/images/ape_icon.png'); static const ape = CryptoCurrency(title: 'APE', tag: 'ETH', fullName: 'ApeCoin', raw: 30, name: 'ape', iconPath: 'assets/images/ape_icon.png');
static const avaxc = CryptoCurrency(title: 'AVAX', tag: 'AVAXC', raw: 31, name: 'avaxc', iconPath: 'assets/images/avaxc_icon.png'); static const avaxc = CryptoCurrency(title: 'AVAX', tag: 'AVAXC', raw: 31, name: 'avaxc', iconPath: 'assets/images/avaxc_icon.png');
static const btt = CryptoCurrency(title: 'BTT', tag: 'ETH', fullName: 'BitTorrent', raw: 32, name: 'btt', iconPath: 'assets/images/btt_icon.png'); static const btt = CryptoCurrency(title: 'BTT', tag: 'ETH', fullName: 'BitTorrent', raw: 32, name: 'btt', iconPath: 'assets/images/btt_icon.png');
static const bttc = CryptoCurrency(title: 'BTTC', tag: 'TRX', fullName: 'BitTorrent-NEW', raw: 33, name: 'bttc', iconPath: 'assets/images/bttbsc_icon.png'); static const bttc = CryptoCurrency(title: 'BTTC', tag: 'TRX', fullName: 'BitTorrent-NEW', raw: 33, name: 'bttc', iconPath: 'assets/images/btt_icon.png');
static const doge = CryptoCurrency(title: 'DOGE', fullName: 'Dogecoin', raw: 34, name: 'doge', iconPath: 'assets/images/doge_icon.png'); static const doge = CryptoCurrency(title: 'DOGE', fullName: 'Dogecoin', raw: 34, name: 'doge', iconPath: 'assets/images/doge_icon.png');
static const firo = CryptoCurrency(title: 'FIRO', raw: 35, name: 'firo', iconPath: 'assets/images/firo_icon.png'); static const firo = CryptoCurrency(title: 'FIRO', raw: 35, name: 'firo', iconPath: 'assets/images/firo_icon.png');
static const usdttrc20 = CryptoCurrency(title: 'USDT', tag: 'TRX', fullName: 'USDT Tether', raw: 36, name: 'usdttrc20', iconPath: 'assets/images/usdttrc20_icon.png'); static const usdttrc20 = CryptoCurrency(title: 'USDT', tag: 'TRX', fullName: 'USDT Tether', raw: 36, name: 'usdttrc20', iconPath: 'assets/images/usdttrc20_icon.png');
@ -130,9 +152,9 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
static const sc = CryptoCurrency(title: 'SC', fullName: 'Siacoin', raw: 38, name: 'sc', iconPath: 'assets/images/sc_icon.png'); static const sc = CryptoCurrency(title: 'SC', fullName: 'Siacoin', raw: 38, name: 'sc', iconPath: 'assets/images/sc_icon.png');
static const sol = CryptoCurrency(title: 'SOL', fullName: 'Solana', raw: 39, name: 'sol', iconPath: 'assets/images/sol_icon.png'); static const sol = CryptoCurrency(title: 'SOL', fullName: 'Solana', raw: 39, name: 'sol', iconPath: 'assets/images/sol_icon.png');
static const usdc = CryptoCurrency(title: 'USDC', tag: 'ETH', fullName: 'USD Coin', raw: 40, name: 'usdc', iconPath: 'assets/images/usdc_icon.png'); static const usdc = CryptoCurrency(title: 'USDC', tag: 'ETH', fullName: 'USD Coin', raw: 40, name: 'usdc', iconPath: 'assets/images/usdc_icon.png');
static const usdcsol = CryptoCurrency(title: 'USDC', tag: 'SOL', fullName: 'USDC Coin', raw: 41, name: 'usdcsol', iconPath: 'assets/images/usdcsol_icon.png'); static const usdcsol = CryptoCurrency(title: 'USDC', tag: 'SOL', fullName: 'USDC Coin', raw: 41, name: 'usdcsol', iconPath: 'assets/images/usdc_icon.png');
static const zaddr = CryptoCurrency(title: 'ZZEC', tag: 'ZEC', fullName: 'Shielded Zcash', iconPath: 'assets/images/zaddr_icon.png', raw: 42, name: 'zaddr'); static const zaddr = CryptoCurrency(title: 'ZZEC', tag: 'ZEC', fullName: 'Shielded Zcash', raw: 42, name: 'zaddr', iconPath: 'assets/images/zec_icon.png');
static const zec = CryptoCurrency(title: 'TZEC', tag: 'ZEC', fullName: 'Transparent Zcash', iconPath: 'assets/images/zec_icon.png', raw: 43, name: 'zec'); static const zec = CryptoCurrency(title: 'TZEC', tag: 'ZEC', fullName: 'Transparent Zcash', raw: 43, name: 'zec', iconPath: 'assets/images/zec_icon.png');
static const zen = CryptoCurrency(title: 'ZEN', fullName: 'Horizen', raw: 44, name: 'zen', iconPath: 'assets/images/zen_icon.png'); static const zen = CryptoCurrency(title: 'ZEN', fullName: 'Horizen', raw: 44, name: 'zen', iconPath: 'assets/images/zen_icon.png');
static const xvg = CryptoCurrency(title: 'XVG', fullName: 'Verge', raw: 45, name: 'xvg', iconPath: 'assets/images/xvg_icon.png'); static const xvg = CryptoCurrency(title: 'XVG', fullName: 'Verge', raw: 45, name: 'xvg', iconPath: 'assets/images/xvg_icon.png');
@ -153,7 +175,29 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
static const uni = CryptoCurrency(title: 'UNI', tag: 'ETH', fullName: 'Uniswap', raw: 60, name: 'uni', iconPath: 'assets/images/uni_icon.png'); static const uni = CryptoCurrency(title: 'UNI', tag: 'ETH', fullName: 'Uniswap', raw: 60, name: 'uni', iconPath: 'assets/images/uni_icon.png');
static const stx = CryptoCurrency(title: 'STX', fullName: 'Stacks', raw: 61, name: 'stx', iconPath: 'assets/images/stx_icon.png'); static const stx = CryptoCurrency(title: 'STX', fullName: 'Stacks', raw: 61, name: 'stx', iconPath: 'assets/images/stx_icon.png');
static const btcln = CryptoCurrency(title: 'BTC', tag: 'LN', fullName: 'Bitcoin Lightning Network', raw: 62, name: 'btcln', iconPath: 'assets/images/btc.png'); static const btcln = CryptoCurrency(title: 'BTC', tag: 'LN', fullName: 'Bitcoin Lightning Network', raw: 62, name: 'btcln', iconPath: 'assets/images/btc.png');
static const shib = CryptoCurrency(title: 'SHIB', tag: 'ETH', fullName: 'SHIBA INU', raw: 63, name: 'shib', iconPath: 'assets/images/shib_icon.png'); static const shib = CryptoCurrency(title: 'SHIB', tag: 'ETH', fullName: 'Shiba Inu', raw: 63, name: 'shib', iconPath: 'assets/images/shib_icon.png');
static const aave = CryptoCurrency(title: 'AAVE', tag: 'ETH', fullName: 'Aave', raw: 64, name: 'aave', iconPath: 'assets/images/aave_icon.png');
static const arb = CryptoCurrency(title: 'ARB', fullName: 'Arbitrum', raw: 65, name: 'arb', iconPath: 'assets/images/arb_icon.png');
static const bat = CryptoCurrency(title: 'BAT', tag: 'ETH', fullName: 'Basic Attention Token', raw: 66, name: 'bat', iconPath: 'assets/images/bat_icon.png');
static const comp = CryptoCurrency(title: 'COMP', tag: 'ETH', fullName: 'Compound', raw: 67, name: 'comp', iconPath: 'assets/images/comp_icon.png');
static const cro = CryptoCurrency(title: 'CRO', tag: 'ETH', fullName: 'Crypto.com Cronos', raw: 68, name: 'cro', iconPath: 'assets/images/cro_icon.png');
static const ens = CryptoCurrency(title: 'ENS', tag: 'ETH', fullName: 'Ethereum Name Service', raw: 69, name: 'ens', iconPath: 'assets/images/ens_icon.png');
static const ftm = CryptoCurrency(title: 'FTM', tag: 'ETH', fullName: 'Fantom', raw: 70, name: 'ftm', iconPath: 'assets/images/ftm_icon.png');
static const frax = CryptoCurrency(title: 'FRAX', tag: 'ETH', fullName: 'Frax', raw: 71, name: 'frax', iconPath: 'assets/images/frax_icon.png');
static const gusd = CryptoCurrency(title: 'GUSD', tag: 'ETH', fullName: 'Gemini USD', raw: 72, name: 'gusd', iconPath: 'assets/images/gusd_icon.png');
static const gtc = CryptoCurrency(title: 'GTC', tag: 'ETH', fullName: 'Gitcoin', raw: 73, name: 'gtc', iconPath: 'assets/images/gtc_icon.png');
static const grt = CryptoCurrency(title: 'GRT', tag: 'ETH', fullName: 'The Graph', raw: 74, name: 'grt', iconPath: 'assets/images/grt_icon.png');
static const ldo = CryptoCurrency(title: 'LDO', tag: 'ETH', fullName: 'Lido DAO', raw: 75, name: 'ldo', iconPath: 'assets/images/ldo_icon.png');
static const nexo = CryptoCurrency(title: 'NEXO', tag: 'ETH', fullName: 'Nexo', raw: 76, name: 'nexo', iconPath: 'assets/images/nexo_icon.png');
static const cake = CryptoCurrency(title: 'CAKE', tag: 'BSC', fullName: 'PancakeSwap', raw: 77, name: 'cake', iconPath: 'assets/images/cake_icon.png');
static const pepe = CryptoCurrency(title: 'PEPE', tag: 'ETH', fullName: 'Pepe', raw: 78, name: 'pepe', iconPath: 'assets/images/pepe_icon.png');
static const storj = CryptoCurrency(title: 'STORJ', tag: 'ETH', fullName: 'Storj', raw: 79, name: 'storj', iconPath: 'assets/images/storj_icon.png');
static const tusd = CryptoCurrency(title: 'TUSD', tag: 'ETH', fullName: 'TrueUSD', raw: 80, name: 'tusd', iconPath: 'assets/images/tusd_icon.png');
static const wbtc = CryptoCurrency(title: 'WBTC', tag: 'ETH', fullName: 'Wrapped Bitcoin', raw: 81, name: 'wbtc', iconPath: 'assets/images/wbtc_icon.png');
static const weth = CryptoCurrency(title: 'WETH', tag: 'ETH', fullName: 'Wrapped Ethereum', raw: 82, name: 'weth', iconPath: 'assets/images/weth_icon.png');
static const zrx = CryptoCurrency(title: 'ZRX', tag: 'ETH', fullName: '0x Protocol', raw: 83, name: 'zrx', iconPath: 'assets/images/zrx_icon.png');
static const dydx = CryptoCurrency(title: 'DYDX', tag: 'ETH', fullName: 'dYdX', raw: 84, name: 'dydx', iconPath: 'assets/images/dydx_icon.png');
static const steth = CryptoCurrency(title: 'STETH', tag: 'ETH', fullName: 'Lido Staked Ethereum', raw: 85, name: 'steth', iconPath: 'assets/images/steth_icon.png');
static final Map<int, CryptoCurrency> _rawCurrencyMap = static final Map<int, CryptoCurrency> _rawCurrencyMap =

View file

@ -17,4 +17,6 @@ abstract class WalletService<N extends WalletCredentials,
Future<bool> isWalletExit(String name); Future<bool> isWalletExit(String name);
Future<void> remove(String wallet); Future<void> remove(String wallet);
Future<void> rename(String name, String password, String newName);
} }

View file

@ -1,5 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'package:cw_core/crypto_currency.dart'; import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/transaction_priority.dart';
import 'package:cw_haven/haven_transaction_creation_credentials.dart'; import 'package:cw_haven/haven_transaction_creation_credentials.dart';
import 'package:cw_core/monero_amount_format.dart'; import 'package:cw_core/monero_amount_format.dart';
@ -251,6 +253,29 @@ abstract class HavenWalletBase extends WalletBase<MoneroBalance,
await haven_wallet.store(); await haven_wallet.store();
} }
Future<void> renameWalletFiles(String newWalletName) async {
final currentWalletPath = await pathForWallet(name: name, type: type);
final currentCacheFile = File(currentWalletPath);
final currentKeysFile = File('$currentWalletPath.keys');
final currentAddressListFile = File('$currentWalletPath.address.txt');
final newWalletPath = await pathForWallet(name: newWalletName, type: type);
// Copies current wallet files into new wallet name's dir and files
if (currentCacheFile.existsSync()) {
await currentCacheFile.copy(newWalletPath);
}
if (currentKeysFile.existsSync()) {
await currentKeysFile.copy('$newWalletPath.keys');
}
if (currentAddressListFile.existsSync()) {
await currentAddressListFile.copy('$newWalletPath.address.txt');
}
// Delete old name's dir and files
await Directory(currentWalletPath).delete(recursive: true);
}
@override @override
Future<void> changePassword(String password) async { Future<void> changePassword(String password) async {
haven_wallet.setPasswordSync(password); haven_wallet.setPasswordSync(password);

View file

@ -149,6 +149,26 @@ class HavenWalletService extends WalletService<
if (isExist) { if (isExist) {
await file.delete(recursive: true); await file.delete(recursive: true);
} }
final walletInfo = walletInfoSource.values
.firstWhere((info) => info.id == WalletBase.idFor(wallet, getType()));
await walletInfoSource.delete(walletInfo.key);
}
@override
Future<void> rename(
String currentName, String password, String newName) async {
final currentWalletInfo = walletInfoSource.values.firstWhere(
(info) => info.id == WalletBase.idFor(currentName, getType()));
final currentWallet = HavenWallet(walletInfo: currentWalletInfo);
await currentWallet.renameWalletFiles(newName);
final newWalletInfo = currentWalletInfo;
newWalletInfo.id = WalletBase.idFor(newName, getType());
newWalletInfo.name = newName;
await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
} }
@override @override

View file

@ -1,4 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:io';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/transaction_priority.dart'; import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/monero_amount_format.dart'; import 'package:cw_core/monero_amount_format.dart';
import 'package:cw_monero/monero_transaction_creation_exception.dart'; import 'package:cw_monero/monero_transaction_creation_exception.dart';
@ -6,7 +8,6 @@ import 'package:cw_monero/monero_transaction_info.dart';
import 'package:cw_monero/monero_wallet_addresses.dart'; import 'package:cw_monero/monero_wallet_addresses.dart';
import 'package:cw_core/monero_wallet_utils.dart'; import 'package:cw_core/monero_wallet_utils.dart';
import 'package:cw_monero/api/structs/pending_transaction.dart'; import 'package:cw_monero/api/structs/pending_transaction.dart';
import 'package:flutter/foundation.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cw_monero/api/transaction_history.dart' import 'package:cw_monero/api/transaction_history.dart'
as monero_transaction_history; as monero_transaction_history;
@ -267,6 +268,62 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance,
await monero_wallet.store(); await monero_wallet.store();
} }
Future<void> renameWalletFiles(String newWalletName) async {
final currentWalletDirPath = await pathForWalletDir(name: name, type: type);
try {
// -- rename the waller folder --
final currentWalletDir =
Directory(await pathForWalletDir(name: name, type: type));
final newWalletDirPath =
await pathForWalletDir(name: newWalletName, type: type);
await currentWalletDir.rename(newWalletDirPath);
// -- use new waller folder to rename files with old names still --
final renamedWalletPath = newWalletDirPath + '/$name';
final currentCacheFile = File(renamedWalletPath);
final currentKeysFile = File('$renamedWalletPath.keys');
final currentAddressListFile = File('$renamedWalletPath.address.txt');
final newWalletPath =
await pathForWallet(name: newWalletName, type: type);
if (currentCacheFile.existsSync()) {
await currentCacheFile.rename(newWalletPath);
}
if (currentKeysFile.existsSync()) {
await currentKeysFile.rename('$newWalletPath.keys');
}
if (currentAddressListFile.existsSync()) {
await currentAddressListFile.rename('$newWalletPath.address.txt');
}
} catch (e) {
final currentWalletPath = await pathForWallet(name: name, type: type);
final currentCacheFile = File(currentWalletPath);
final currentKeysFile = File('$currentWalletPath.keys');
final currentAddressListFile = File('$currentWalletPath.address.txt');
final newWalletPath =
await pathForWallet(name: newWalletName, type: type);
// Copies current wallet files into new wallet name's dir and files
if (currentCacheFile.existsSync()) {
await currentCacheFile.copy(newWalletPath);
}
if (currentKeysFile.existsSync()) {
await currentKeysFile.copy('$newWalletPath.keys');
}
if (currentAddressListFile.existsSync()) {
await currentAddressListFile.copy('$newWalletPath.address.txt');
}
// Delete old name's dir and files
await Directory(currentWalletDirPath).delete(recursive: true);
}
}
@override @override
Future<void> changePassword(String password) async { Future<void> changePassword(String password) async {
monero_wallet.setPasswordSync(password); monero_wallet.setPasswordSync(password);

View file

@ -146,6 +146,26 @@ class MoneroWalletService extends WalletService<
if (isExist) { if (isExist) {
await file.delete(recursive: true); await file.delete(recursive: true);
} }
final walletInfo = walletInfoSource.values
.firstWhere((info) => info.id == WalletBase.idFor(wallet, getType()));
await walletInfoSource.delete(walletInfo.key);
}
@override
Future<void> rename(
String currentName, String password, String newName) async {
final currentWalletInfo = walletInfoSource.values.firstWhere(
(info) => info.id == WalletBase.idFor(currentName, getType()));
final currentWallet = MoneroWallet(walletInfo: currentWalletInfo);
await currentWallet.renameWalletFiles(newName);
final newWalletInfo = currentWalletInfo;
newWalletInfo.id = WalletBase.idFor(newName, getType());
newWalletInfo.name = newName;
await walletInfoSource.put(currentWalletInfo.key, newWalletInfo);
} }
@override @override

View file

@ -286,4 +286,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 09df1114e7c360f55770d35a79356bf5446e0100 PODFILE CHECKSUM: 09df1114e7c360f55770d35a79356bf5446e0100
COCOAPODS: 1.11.3 COCOAPODS: 1.12.1

View file

@ -36,6 +36,26 @@ class AddressValidator extends TextValidator {
case CryptoCurrency.oxt: case CryptoCurrency.oxt:
case CryptoCurrency.paxg: case CryptoCurrency.paxg:
case CryptoCurrency.uni: case CryptoCurrency.uni:
case CryptoCurrency.aave:
case CryptoCurrency.bat:
case CryptoCurrency.comp:
case CryptoCurrency.cro:
case CryptoCurrency.ens:
case CryptoCurrency.ftm:
case CryptoCurrency.frax:
case CryptoCurrency.gusd:
case CryptoCurrency.gtc:
case CryptoCurrency.grt:
case CryptoCurrency.ldo:
case CryptoCurrency.nexo:
case CryptoCurrency.pepe:
case CryptoCurrency.storj:
case CryptoCurrency.tusd:
case CryptoCurrency.wbtc:
case CryptoCurrency.weth:
case CryptoCurrency.zrx:
case CryptoCurrency.dydx:
case CryptoCurrency.steth:
case CryptoCurrency.shib: case CryptoCurrency.shib:
return '0x[0-9a-zA-Z]'; return '0x[0-9a-zA-Z]';
case CryptoCurrency.xrp: case CryptoCurrency.xrp:
@ -102,8 +122,6 @@ class AddressValidator extends TextValidator {
return null; return null;
case CryptoCurrency.ada: case CryptoCurrency.ada:
return null; return null;
case CryptoCurrency.ape:
return [42];
case CryptoCurrency.avaxc: case CryptoCurrency.avaxc:
return [42]; return [42];
case CryptoCurrency.bch: case CryptoCurrency.bch:
@ -112,13 +130,43 @@ class AddressValidator extends TextValidator {
return [42]; return [42];
case CryptoCurrency.btc: case CryptoCurrency.btc:
return null; return null;
case CryptoCurrency.dai:
return [42];
case CryptoCurrency.dash: case CryptoCurrency.dash:
return [34]; return [34];
case CryptoCurrency.eos: case CryptoCurrency.eos:
return [42]; return [42];
case CryptoCurrency.eth: case CryptoCurrency.eth:
case CryptoCurrency.usdcpoly:
case CryptoCurrency.mana:
case CryptoCurrency.matic:
case CryptoCurrency.maticpoly:
case CryptoCurrency.mkr:
case CryptoCurrency.oxt:
case CryptoCurrency.paxg:
case CryptoCurrency.uni:
case CryptoCurrency.dai:
case CryptoCurrency.ape:
case CryptoCurrency.usdc:
case CryptoCurrency.usdterc20:
case CryptoCurrency.aave:
case CryptoCurrency.bat:
case CryptoCurrency.comp:
case CryptoCurrency.cro:
case CryptoCurrency.ens:
case CryptoCurrency.ftm:
case CryptoCurrency.frax:
case CryptoCurrency.gusd:
case CryptoCurrency.gtc:
case CryptoCurrency.grt:
case CryptoCurrency.ldo:
case CryptoCurrency.nexo:
case CryptoCurrency.pepe:
case CryptoCurrency.storj:
case CryptoCurrency.tusd:
case CryptoCurrency.wbtc:
case CryptoCurrency.weth:
case CryptoCurrency.zrx:
case CryptoCurrency.dydx:
case CryptoCurrency.steth:
case CryptoCurrency.shib: case CryptoCurrency.shib:
return [42]; return [42];
case CryptoCurrency.ltc: case CryptoCurrency.ltc:
@ -131,14 +179,10 @@ class AddressValidator extends TextValidator {
return [32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44]; return [32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44];
case CryptoCurrency.trx: case CryptoCurrency.trx:
return [34]; return [34];
case CryptoCurrency.usdc:
return [42];
case CryptoCurrency.usdcsol: case CryptoCurrency.usdcsol:
return [32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44]; return [32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44];
case CryptoCurrency.usdt: case CryptoCurrency.usdt:
return [34]; return [34];
case CryptoCurrency.usdterc20:
return [42];
case CryptoCurrency.usdttrc20: case CryptoCurrency.usdttrc20:
return [34]; return [34];
case CryptoCurrency.xlm: case CryptoCurrency.xlm:
@ -186,15 +230,6 @@ class AddressValidator extends TextValidator {
return [35]; return [35];
case CryptoCurrency.stx: case CryptoCurrency.stx:
return [40, 41, 42]; return [40, 41, 42];
case CryptoCurrency.usdcpoly:
case CryptoCurrency.mana:
case CryptoCurrency.matic:
case CryptoCurrency.maticpoly:
case CryptoCurrency.mkr:
case CryptoCurrency.oxt:
case CryptoCurrency.paxg:
case CryptoCurrency.uni:
return [42];
case CryptoCurrency.rune: case CryptoCurrency.rune:
return [43]; return [43];
case CryptoCurrency.scrt: case CryptoCurrency.scrt:

View file

@ -21,4 +21,11 @@ class KeyService {
await _secureStorage.write(key: key, value: encodedPassword); await _secureStorage.write(key: key, value: encodedPassword);
} }
Future<void> deleteWalletPassword({required String walletName}) async {
final key = generateStoreKeyFor(
key: SecretStoreKey.moneroWalletPassword, walletName: walletName);
await _secureStorage.delete(key: key);
}
} }

View file

@ -8,14 +8,35 @@ import 'package:shared_preferences/shared_preferences.dart';
class WalletLoadingService { class WalletLoadingService {
WalletLoadingService( WalletLoadingService(
this.sharedPreferences, this.sharedPreferences, this.keyService, this.walletServiceFactory);
this.keyService,
this.walletServiceFactory);
final SharedPreferences sharedPreferences; final SharedPreferences sharedPreferences;
final KeyService keyService; final KeyService keyService;
final WalletService Function(WalletType type) walletServiceFactory; final WalletService Function(WalletType type) walletServiceFactory;
Future<void> renameWallet(
WalletType type, String name, String newName) async {
final walletService = walletServiceFactory.call(type);
final password = await keyService.getWalletPassword(walletName: name);
// Save the current wallet's password to the new wallet name's key
await keyService.saveWalletPassword(
walletName: newName, password: password);
// Delete previous wallet name from keyService to keep only new wallet's name
// otherwise keeps duplicate (old and new names)
await keyService.deleteWalletPassword(walletName: name);
await walletService.rename(name, password, newName);
// set shared preferences flag based on previous wallet name
if (type == WalletType.monero) {
final oldNameKey = PreferencesKey.moneroWalletUpdateV1Key(name);
final isPasswordUpdated = sharedPreferences.getBool(oldNameKey) ?? false;
final newNameKey = PreferencesKey.moneroWalletUpdateV1Key(newName);
await sharedPreferences.setBool(newNameKey, isPasswordUpdated);
}
}
Future<WalletBase> load(WalletType type, String name) async { Future<WalletBase> load(WalletType type, String name) async {
final walletService = walletServiceFactory.call(type); final walletService = walletServiceFactory.call(type);
final password = await keyService.getWalletPassword(walletName: name); final password = await keyService.getWalletPassword(walletName: name);
@ -40,9 +61,11 @@ class WalletLoadingService {
// Save new generated password with backup key for case where // Save new generated password with backup key for case where
// wallet will change password, but it will fail to update in secure storage // wallet will change password, but it will fail to update in secure storage
final bakWalletName = '#__${wallet.name}_bak__#'; final bakWalletName = '#__${wallet.name}_bak__#';
await keyService.saveWalletPassword(walletName: bakWalletName, password: password); await keyService.saveWalletPassword(
walletName: bakWalletName, password: password);
await wallet.changePassword(password); await wallet.changePassword(password);
await keyService.saveWalletPassword(walletName: wallet.name, password: password); await keyService.saveWalletPassword(
walletName: wallet.name, password: password);
isPasswordUpdated = true; isPasswordUpdated = true;
await sharedPreferences.setBool(key, isPasswordUpdated); await sharedPreferences.setBool(key, isPasswordUpdated);
} }

View file

@ -34,6 +34,7 @@ import 'package:cake_wallet/src/screens/setup_2fa/modify_2fa_page.dart';
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_qr_page.dart'; import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_qr_page.dart';
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa.dart'; import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa.dart';
import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_enter_code_page.dart'; import 'package:cake_wallet/src/screens/setup_2fa/setup_2fa_enter_code_page.dart';
import 'package:cake_wallet/src/screens/wallet/wallet_edit_page.dart';
import 'package:cake_wallet/themes/theme_list.dart'; import 'package:cake_wallet/themes/theme_list.dart';
import 'package:cake_wallet/utils/device_info.dart'; import 'package:cake_wallet/utils/device_info.dart';
import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart'; import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
@ -71,6 +72,8 @@ import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart
import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart'; import 'package:cake_wallet/view_model/settings/security_settings_view_model.dart';
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart'; import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.dart'; import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_edit_view_model.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
import 'package:cw_core/erc20_token.dart'; import 'package:cw_core/erc20_token.dart';
import 'package:cw_core/unspent_coins_info.dart'; import 'package:cw_core/unspent_coins_info.dart';
import 'package:cake_wallet/core/backup_service.dart'; import 'package:cake_wallet/core/backup_service.dart';
@ -573,6 +576,21 @@ Future setup({
authService: getIt.get<AuthService>(), authService: getIt.get<AuthService>(),
)); ));
getIt.registerFactoryParam<WalletEditViewModel, WalletListViewModel, void>(
(WalletListViewModel walletListViewModel, _) => WalletEditViewModel(
walletListViewModel, getIt.get<WalletLoadingService>()));
getIt.registerFactoryParam<WalletEditPage, List<dynamic>, void>((args, _) {
final walletListViewModel = args.first as WalletListViewModel;
final editingWallet = args.last as WalletListItem;
return WalletEditPage(
walletEditViewModel: getIt.get<WalletEditViewModel>(param1: walletListViewModel),
authService: getIt.get<AuthService>(),
walletNewVM: getIt.get<WalletNewVM>(param1: editingWallet.type),
editingWallet: editingWallet);
});
getIt.registerFactory(() { getIt.registerFactory(() {
final wallet = getIt.get<AppStore>().wallet!; final wallet = getIt.get<AppStore>().wallet!;

View file

@ -193,12 +193,7 @@ class App extends StatefulWidget {
} }
class AppState extends State<App> with SingleTickerProviderStateMixin { class AppState extends State<App> with SingleTickerProviderStateMixin {
AppState() : yatStore = getIt.get<YatStore>() { AppState() : yatStore = getIt.get<YatStore>();
SystemChrome.setPreferredOrientations(
ResponsiveLayoutUtil.instance.isIpad ?
[DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight] :
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
}
YatStore yatStore; YatStore yatStore;
StreamSubscription? stream; StreamSubscription? stream;
@ -290,7 +285,43 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
locale: Locale(settingsStore.languageCode), locale: Locale(settingsStore.languageCode),
onGenerateRoute: (settings) => Router.createRoute(settings), onGenerateRoute: (settings) => Router.createRoute(settings),
initialRoute: initialRoute, initialRoute: initialRoute,
home: _Home(),
)); ));
}); });
} }
} }
class _Home extends StatefulWidget {
const _Home();
@override
State<_Home> createState() => _HomeState();
}
class _HomeState extends State<_Home> {
@override
void didChangeDependencies() {
if(!ResponsiveLayoutUtil.instance.isMobile){
_setOrientation(context);
}
super.didChangeDependencies();
}
void _setOrientation(BuildContext context){
final orientation = MediaQuery.of(context).orientation;
final width = MediaQuery.of(context).size.width;
final height = MediaQuery.of(context).size.height;
if (orientation == Orientation.portrait && width < height) {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
} else if (orientation == Orientation.landscape && width > height) {
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight]);
}
}
@override
Widget build(BuildContext context) {
return const SizedBox.shrink();
}
}

View file

@ -47,6 +47,7 @@ import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart'; import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart'; import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart'; import 'package:cake_wallet/view_model/advanced_privacy_settings_view_model.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
import 'package:cake_wallet/wallet_type_utils.dart'; import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -65,6 +66,7 @@ import 'package:cake_wallet/src/screens/nodes/node_create_or_edit_page.dart';
import 'package:cake_wallet/src/screens/receive/receive_page.dart'; import 'package:cake_wallet/src/screens/receive/receive_page.dart';
import 'package:cake_wallet/src/screens/subaddress/address_edit_or_create_page.dart'; import 'package:cake_wallet/src/screens/subaddress/address_edit_or_create_page.dart';
import 'package:cake_wallet/src/screens/wallet_list/wallet_list_page.dart'; import 'package:cake_wallet/src/screens/wallet_list/wallet_list_page.dart';
import 'package:cake_wallet/src/screens/wallet/wallet_edit_page.dart';
import 'package:cake_wallet/src/screens/new_wallet/new_wallet_page.dart'; import 'package:cake_wallet/src/screens/new_wallet/new_wallet_page.dart';
import 'package:cake_wallet/src/screens/setup_pin_code/setup_pin_code.dart'; import 'package:cake_wallet/src/screens/setup_pin_code/setup_pin_code.dart';
import 'package:cake_wallet/src/screens/restore/restore_options_page.dart'; import 'package:cake_wallet/src/screens/restore/restore_options_page.dart';
@ -262,6 +264,12 @@ Route<dynamic> createRoute(RouteSettings settings) {
return MaterialPageRoute<void>( return MaterialPageRoute<void>(
fullscreenDialog: true, builder: (_) => getIt.get<WalletListPage>()); fullscreenDialog: true, builder: (_) => getIt.get<WalletListPage>());
case Routes.walletEdit:
return MaterialPageRoute<void>(
fullscreenDialog: true,
builder: (_) => getIt.get<WalletEditPage>(
param1: settings.arguments as List<dynamic>));
case Routes.auth: case Routes.auth:
return MaterialPageRoute<void>( return MaterialPageRoute<void>(
fullscreenDialog: true, fullscreenDialog: true,

View file

@ -11,6 +11,7 @@ class Routes {
static const transactionDetails = '/transaction_info'; static const transactionDetails = '/transaction_info';
static const receive = '/receive'; static const receive = '/receive';
static const newSubaddress = '/new_subaddress'; static const newSubaddress = '/new_subaddress';
static const walletEdit = '/walletEdit';
static const disclaimer = '/disclaimer'; static const disclaimer = '/disclaimer';
static const readDisclaimer = '/read_disclaimer'; static const readDisclaimer = '/read_disclaimer';
static const seedLanguage = '/seed_language'; static const seedLanguage = '/seed_language';

View file

@ -4,6 +4,7 @@ import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/entities/main_actions.dart'; import 'package:cake_wallet/entities/main_actions.dart';
import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar_wrapper.dart'; import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_sidebar_wrapper.dart';
import 'package:cake_wallet/src/screens/dashboard/widgets/market_place_page.dart'; import 'package:cake_wallet/src/screens/dashboard/widgets/market_place_page.dart';
import 'package:cake_wallet/utils/device_info.dart';
import 'package:cake_wallet/utils/version_comparator.dart'; import 'package:cake_wallet/utils/version_comparator.dart';
import 'package:cake_wallet/view_model/dashboard/market_place_view_model.dart'; import 'package:cake_wallet/view_model/dashboard/market_place_view_model.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
@ -42,16 +43,31 @@ class DashboardPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(body: LayoutBuilder(
body: ResponsiveLayoutUtil.instance.isMobile builder: (context, constraints) {
? _DashboardPageView( if (DeviceInfo.instance.isDesktop) {
if (constraints.maxWidth > ResponsiveLayoutUtil.kDesktopMaxDashBoardWidthConstraint) {
return getIt.get<DesktopSidebarWrapper>();
} else {
return _DashboardPageView(
balancePage: balancePage, balancePage: balancePage,
dashboardViewModel: dashboardViewModel, dashboardViewModel: dashboardViewModel,
addressListViewModel: addressListViewModel, addressListViewModel: addressListViewModel,
)
: getIt.get<DesktopSidebarWrapper>(),
); );
} }
} else if (ResponsiveLayoutUtil.instance.shouldRenderMobileUI()) {
return _DashboardPageView(
balancePage: balancePage,
dashboardViewModel: dashboardViewModel,
addressListViewModel: addressListViewModel,
);
} else {
return getIt.get<DesktopSidebarWrapper>();
}
},
));
}
} }
class _DashboardPageView extends BasePage { class _DashboardPageView extends BasePage {

View file

@ -138,7 +138,7 @@ class PresentReceiveOptionPicker extends StatelessWidget {
Container( Container(
margin: EdgeInsets.only(bottom: 40), margin: EdgeInsets.only(bottom: 40),
child: InkWell( child: InkWell(
onTap: () => Navigator.pop(context), onTap: () => Navigator.pop(popUpContext),
child: CircleAvatar( child: CircleAvatar(
child: Icon( child: Icon(
Icons.close, Icons.close,

View file

@ -1,6 +1,8 @@
import 'package:cake_wallet/core/execution_state.dart'; import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart'; import 'package:cake_wallet/src/screens/nodes/widgets/node_form.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/utils/show_pop_up.dart'; import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cw_core/node.dart'; import 'package:cw_core/node.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -122,17 +124,35 @@ class NodeCreateOrEditPage extends BasePage {
padding: EdgeInsets.only(right: 8.0), padding: EdgeInsets.only(right: 8.0),
child: LoadingPrimaryButton( child: LoadingPrimaryButton(
onPressed: () async { onPressed: () async {
if (_formKey.currentState != null && !_formKey.currentState!.validate()) { final confirmed = await showPopUp<bool>(
return; context: context,
} builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle:
S.of(context).remove_node,
alertContent: S
.of(context)
.remove_node_message,
rightButtonText:
S.of(context).remove,
leftButtonText:
S.of(context).cancel,
actionRightButton: () =>
Navigator.pop(context, true),
actionLeftButton: () =>
Navigator.pop(context, false));
}) ??
false;
await nodeCreateOrEditViewModel.connect(); if (confirmed) {
await editingNode!.delete();
Navigator.of(context).pop();
}
}, },
isLoading: nodeCreateOrEditViewModel text: S.of(context).delete,
.connectionState is IsExecutingState, isDisabled: !nodeCreateOrEditViewModel.isReady ||
text: S.of(context).node_test, (isSelected ?? false),
isDisabled: !nodeCreateOrEditViewModel.isReady, color: Palette.red,
color: Colors.orange,
textColor: Colors.white), textColor: Colors.white),
)), )),
Flexible( Flexible(

View file

@ -9,8 +9,8 @@ class NodeIndicator extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
width: 8.0, width: 12.0,
height: 8.0, height: 12.0,
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, color: isLive ? Palette.green : Palette.red), shape: BoxShape.circle, color: isLive ? Palette.green : Palette.red),
); );

View file

@ -1,21 +1,23 @@
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/nodes/widgets/node_indicator.dart'; import 'package:cake_wallet/src/screens/nodes/widgets/node_indicator.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart'; import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:cw_core/node.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class NodeListRow extends StandardListRow { class NodeListRow extends StandardListRow {
NodeListRow( NodeListRow(
{required String title, {required String title,
required this.node,
required void Function(BuildContext context) onTap, required void Function(BuildContext context) onTap,
required bool isSelected, required bool isSelected})
required this.isAlive})
: super(title: title, onTap: onTap, isSelected: isSelected); : super(title: title, onTap: onTap, isSelected: isSelected);
final Future<bool> isAlive; final Node node;
@override @override
Widget buildTrailing(BuildContext context) { Widget buildLeading(BuildContext context) {
return FutureBuilder( return FutureBuilder(
future: isAlive, future: node.requestNode(),
builder: (context, snapshot) { builder: (context, snapshot) {
switch (snapshot.connectionState) { switch (snapshot.connectionState) {
case ConnectionState.done: case ConnectionState.done:
@ -25,6 +27,24 @@ class NodeListRow extends StandardListRow {
} }
}); });
} }
@override
Widget buildTrailing(BuildContext context) {
return GestureDetector(
onTap: () => Navigator.of(context).pushNamed(Routes.newNode,
arguments: {'editingNode': node, 'isSelected': isSelected}),
child: Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Theme.of(context)
.textTheme
.headlineMedium!
.decorationColor!),
child: Icon(Icons.edit,
size: 14,
color: Theme.of(context).textTheme.headlineMedium!.color!)));
}
} }
class NodeHeaderListRow extends StandardListRow { class NodeHeaderListRow extends StandardListRow {

View file

@ -8,7 +8,6 @@ import 'package:cake_wallet/src/screens/dashboard/widgets/present_receive_option
import 'package:cake_wallet/src/screens/receive/widgets/anonpay_input_form.dart'; import 'package:cake_wallet/src/screens/receive/widgets/anonpay_input_form.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart'; import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart'; import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
import 'package:cake_wallet/utils/device_info.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart'; import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:cake_wallet/view_model/anon_invoice_page_view_model.dart'; import 'package:cake_wallet/view_model/anon_invoice_page_view_model.dart';
import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart'; import 'package:cake_wallet/view_model/dashboard/receive_option_view_model.dart';
@ -54,9 +53,7 @@ class AnonPayInvoicePage extends BasePage {
AppBarStyle get appBarStyle => AppBarStyle.transparent; AppBarStyle get appBarStyle => AppBarStyle.transparent;
@override @override
void onClose(BuildContext context) { void onClose(BuildContext context) => Navigator.popUntil(context, (route) => route.isFirst);
Navigator.popUntil(context, ModalRoute.withName(Routes.dashboard));
}
@override @override
Widget middle(BuildContext context) => Widget middle(BuildContext context) =>

View file

@ -32,28 +32,7 @@ class AnonPayReceivePage extends BasePage {
bool get resizeToAvoidBottomInset => false; bool get resizeToAvoidBottomInset => false;
@override @override
Widget leading(BuildContext context) { void onClose(BuildContext context) => Navigator.popUntil(context, (route) => route.isFirst);
final _backButton = Icon(
Icons.arrow_back_ios,
color: Theme.of(context)
.accentTextTheme!
.displayMedium!
.backgroundColor!,
size: 16,
);
return SizedBox(
height: 37,
width: 37,
child: ButtonTheme(
minWidth: double.minPositive,
child: TextButton(
onPressed: () =>
Navigator.pushNamedAndRemoveUntil(context, Routes.dashboard, (route) => false),
child: _backButton),
),
);
}
@override @override
Widget middle(BuildContext context) { Widget middle(BuildContext context) {

View file

@ -2,7 +2,6 @@ import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/themes/theme_base.dart'; import 'package:cake_wallet/themes/theme_base.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart';
@ -38,46 +37,33 @@ class PreSeedPage extends BasePage {
padding: EdgeInsets.all(24), padding: EdgeInsets.all(24),
child: ConstrainedBox( child: ConstrainedBox(
constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint), constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
child: Column(
children: [
Flexible(
flex: 2,
child: AspectRatio(
aspectRatio: 1,
child: FittedBox(child: image, fit: BoxFit.contain))),
Flexible(
flex: 3,
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: <Widget>[
ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height * 0.3
),
child: AspectRatio(aspectRatio: 1, child: image),
),
Padding( Padding(
padding: EdgeInsets.only(top: 70, left: 16, right: 16), padding: EdgeInsets.all(10),
child: Text( child: Text(
S S.of(context).pre_seed_description(wordsCount.toString()),
.of(context)
.pre_seed_description(wordsCount.toString()),
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.normal, fontWeight: FontWeight.normal,
color: Theme.of(context) color: Theme.of(context).primaryTextTheme.bodySmall!.color!),
.primaryTextTheme!
.bodySmall!
.color!),
), ),
), ),
PrimaryButton( PrimaryButton(
onPressed: () => Navigator.of(context) onPressed: () =>
.popAndPushNamed(Routes.seed, arguments: true), Navigator.of(context).popAndPushNamed(Routes.seed, arguments: true),
text: S.of(context).pre_seed_button_text, text: S.of(context).pre_seed_button_text,
color: Theme.of(context) color: Theme.of(context).accentTextTheme!.bodyLarge!.color!,
.accentTextTheme!
.bodyLarge!
.color!,
textColor: Colors.white) textColor: Colors.white)
], ],
))
],
), ),
), ),
)); ));

View file

@ -52,8 +52,7 @@ class WalletSeedPage extends BasePage {
} }
@override @override
Widget? leading(BuildContext context) => Widget? leading(BuildContext context) => isNewWalletCreated ? null : super.leading(context);
isNewWalletCreated ? null: super.leading(context);
@override @override
Widget trailing(BuildContext context) { Widget trailing(BuildContext context) {
@ -67,16 +66,11 @@ class WalletSeedPage extends BasePage {
margin: EdgeInsets.only(left: 10), margin: EdgeInsets.only(left: 10),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(16)), borderRadius: BorderRadius.all(Radius.circular(16)),
color: Theme.of(context) color: Theme.of(context).accentTextTheme.bodySmall!.color!),
.accentTextTheme!
.bodySmall!
.color!),
child: Text( child: Text(
S.of(context).seed_language_next, S.of(context).seed_language_next,
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14, fontWeight: FontWeight.w600, color: Palette.blueCraiola),
fontWeight: FontWeight.w600,
color: Palette.blueCraiola),
), ),
), ),
) )
@ -87,27 +81,22 @@ class WalletSeedPage extends BasePage {
Widget body(BuildContext context) { Widget body(BuildContext context) {
final image = currentTheme.type == ThemeType.dark ? imageDark : imageLight; final image = currentTheme.type == ThemeType.dark ? imageDark : imageLight;
return WillPopScope(onWillPop: () async => false, child: Container( return WillPopScope(
onWillPop: () async => false,
child: Container(
padding: EdgeInsets.all(24), padding: EdgeInsets.all(24),
alignment: Alignment.center, alignment: Alignment.center,
child: ConstrainedBox( child: ConstrainedBox(
constraints: constraints: BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
child: Column(
children: <Widget>[
Flexible(
flex: 2,
child: AspectRatio(
aspectRatio: 1,
child: FittedBox(child: image, fit: BoxFit.fill))),
Flexible(
flex: 3,
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[ children: <Widget>[
Padding( ConstrainedBox(
padding: EdgeInsets.only(top: 33), constraints:
child: Observer(builder: (_) { BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.3),
child: AspectRatio(aspectRatio: 1, child: image),
),
Observer(builder: (_) {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[ children: <Widget>[
@ -116,46 +105,34 @@ class WalletSeedPage extends BasePage {
style: TextStyle( style: TextStyle(
fontSize: 20, fontSize: 20,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Theme.of(context) color: Theme.of(context).primaryTextTheme.titleLarge!.color!),
.primaryTextTheme!
.titleLarge!
.color!),
), ),
Padding( Padding(
padding: padding: EdgeInsets.only(top: 20, left: 16, right: 16),
EdgeInsets.only(top: 20, left: 16, right: 16),
child: Text( child: Text(
walletSeedViewModel.seed, walletSeedViewModel.seed,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.normal, fontWeight: FontWeight.normal,
color: Theme.of(context) color: Theme.of(context).primaryTextTheme.bodySmall!.color!),
.primaryTextTheme!
.bodySmall!
.color!),
), ),
) )
], ],
); );
}), }),
),
Column( Column(
children: <Widget>[ children: <Widget>[
isNewWalletCreated isNewWalletCreated
? Padding( ? Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(bottom: 43, left: 43, right: 43),
bottom: 52, left: 43, right: 43),
child: Text( child: Text(
S.of(context).seed_reminder, S.of(context).seed_reminder,
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.normal, fontWeight: FontWeight.normal,
color: Theme.of(context) color: Theme.of(context).primaryTextTheme.labelSmall!.color!),
.primaryTextTheme!
.labelSmall!
.color!),
), ),
) )
: Offstage(), : Offstage(),
@ -182,16 +159,12 @@ class WalletSeedPage extends BasePage {
child: Builder( child: Builder(
builder: (context) => PrimaryButton( builder: (context) => PrimaryButton(
onPressed: () { onPressed: () {
Clipboard.setData(ClipboardData( Clipboard.setData(
text: walletSeedViewModel.seed)); ClipboardData(text: walletSeedViewModel.seed));
showBar<void>(context, showBar<void>(context, S.of(context).copied_to_clipboard);
S.of(context).copied_to_clipboard);
}, },
text: S.of(context).copy, text: S.of(context).copy,
color: Theme.of(context) color: Theme.of(context).accentTextTheme.bodyMedium!.color!,
.accentTextTheme!
.bodyMedium!
.color!,
textColor: Colors.white)), textColor: Colors.white)),
)) ))
], ],
@ -199,9 +172,8 @@ class WalletSeedPage extends BasePage {
], ],
) )
], ],
))
],
), ),
))); ),
));
} }
} }

View file

@ -4,16 +4,16 @@ import 'package:flutter/cupertino.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
List<Image> flagImages = [ List<Image> flagImages = [
Image.asset('assets/images/usa.png'), Image.asset('assets/images/flags/usa.png'),
Image.asset('assets/images/china.png'), Image.asset('assets/images/flags/chn.png'),
Image.asset('assets/images/holland.png'), Image.asset('assets/images/flags/nld.png'),
Image.asset('assets/images/germany.png'), Image.asset('assets/images/flags/deu.png'),
Image.asset('assets/images/japan.png'), Image.asset('assets/images/flags/jpn.png'),
Image.asset('assets/images/portugal.png'), Image.asset('assets/images/flags/prt.png'),
Image.asset('assets/images/russia.png'), Image.asset('assets/images/flags/rus.png'),
Image.asset('assets/images/spain.png'), Image.asset('assets/images/flags/esp.png'),
Image.asset('assets/images/france.png'), Image.asset('assets/images/flags/fra.png'),
Image.asset('assets/images/italy.png'), Image.asset('assets/images/flags/ita.png'),
]; ];
const List<String> languageCodes = [ const List<String> languageCodes = [

View file

@ -12,7 +12,6 @@ import 'package:cake_wallet/src/screens/nodes/widgets/node_list_row.dart';
import 'package:cake_wallet/src/widgets/standard_list.dart'; import 'package:cake_wallet/src/widgets/standard_list.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart'; import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/view_model/node_list/node_list_view_model.dart'; import 'package:cake_wallet/view_model/node_list/node_list_view_model.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
class ConnectionSyncPage extends BasePage { class ConnectionSyncPage extends BasePage {
ConnectionSyncPage(this.nodeListViewModel, this.dashboardViewModel); ConnectionSyncPage(this.nodeListViewModel, this.dashboardViewModel);
@ -64,14 +63,10 @@ class ConnectionSyncPage extends BasePage {
itemBuilder: (_, sectionIndex, index) { itemBuilder: (_, sectionIndex, index) {
final node = nodeListViewModel.nodes[index]; final node = nodeListViewModel.nodes[index];
final isSelected = node.keyIndex == nodeListViewModel.currentNode.keyIndex; final isSelected = node.keyIndex == nodeListViewModel.currentNode.keyIndex;
final nodeListRow = Semantics( final nodeListRow = NodeListRow(
label: 'Slidable',
selected: isSelected,
enabled: !isSelected,
child: NodeListRow(
title: node.uriRaw, title: node.uriRaw,
node: node,
isSelected: isSelected, isSelected: isSelected,
isAlive: node.requestNode(),
onTap: (_) async { onTap: (_) async {
if (isSelected) { if (isSelected) {
return; return;
@ -96,17 +91,9 @@ class ConnectionSyncPage extends BasePage {
); );
}); });
}, },
),
); );
final dismissibleRow = Slidable( return nodeListRow;
key: Key('${node.keyIndex}'),
startActionPane: _actionPane(context, node, isSelected),
endActionPane: _actionPane(context, node, isSelected),
child: nodeListRow,
);
return dismissibleRow;
}, },
), ),
); );
@ -134,44 +121,4 @@ class ConnectionSyncPage extends BasePage {
}, },
); );
} }
ActionPane _actionPane(BuildContext context, Node node, bool isSelected) => ActionPane(
motion: const ScrollMotion(),
extentRatio: isSelected ? 0.3 : 0.6,
children: [
if (!isSelected)
SlidableAction(
onPressed: (context) async {
final confirmed = await showPopUp<bool>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: S.of(context).remove_node,
alertContent: S.of(context).remove_node_message,
rightButtonText: S.of(context).remove,
leftButtonText: S.of(context).cancel,
actionRightButton: () => Navigator.pop(context, true),
actionLeftButton: () => Navigator.pop(context, false));
}) ??
false;
if (confirmed) {
await nodeListViewModel.delete(node);
}
},
backgroundColor: Colors.red,
foregroundColor: Colors.white,
icon: CupertinoIcons.delete,
label: S.of(context).delete,
),
SlidableAction(
onPressed: (_) => Navigator.of(context).pushNamed(Routes.newNode,
arguments: {'editingNode': node, 'isSelected': isSelected}),
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
icon: Icons.edit,
label: S.of(context).edit,
),
],
);
} }

View file

@ -0,0 +1,175 @@
import 'package:another_flushbar/flushbar.dart';
import 'package:cake_wallet/core/auth_service.dart';
import 'package:cake_wallet/core/wallet_name_validator.dart';
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_edit_view_model.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
import 'package:cake_wallet/view_model/wallet_new_vm.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
class WalletEditPage extends BasePage {
WalletEditPage(
{required this.walletEditViewModel,
required this.editingWallet,
required this.walletNewVM,
required this.authService})
: _formKey = GlobalKey<FormState>(),
_labelController = TextEditingController(),
super() {
_labelController.text = editingWallet.name;
_labelController.addListener(() => walletEditViewModel.newName = _labelController.text);
}
final GlobalKey<FormState> _formKey;
final TextEditingController _labelController;
final WalletEditViewModel walletEditViewModel;
final WalletNewVM walletNewVM;
final WalletListItem editingWallet;
final AuthService authService;
@override
String get title => S.current.wallet_list_edit_wallet;
Flushbar<void>? _progressBar;
@override
Widget body(BuildContext context) {
return Form(
key: _formKey,
child: Container(
padding: EdgeInsets.all(24.0),
child: Column(
children: <Widget>[
Expanded(
child: Center(
child: BaseTextFormField(
controller: _labelController,
hintText: S.of(context).wallet_list_wallet_name,
validator: WalletNameValidator()))),
Observer(
builder: (_) {
final isLoading = walletEditViewModel.state is WalletEditRenamePending ||
walletEditViewModel.state is WalletEditDeletePending;
return Row(
children: <Widget>[
Flexible(
child: Container(
padding: EdgeInsets.only(right: 8.0),
child: LoadingPrimaryButton(
isDisabled: isLoading,
onPressed: () => _removeWallet(context),
text: S.of(context).delete,
color: Palette.red,
textColor: Colors.white),
),
),
Flexible(
child: Container(
padding: EdgeInsets.only(left: 8.0),
child: LoadingPrimaryButton(
onPressed: () async {
if (_formKey.currentState?.validate() ?? false) {
if (walletNewVM.nameExists(walletEditViewModel.newName)) {
showPopUp<void>(
context: context,
builder: (_) {
return AlertWithOneAction(
alertTitle: '',
alertContent: S.of(context).wallet_name_exists,
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop(),
);
},
);
} else {
try {
await walletEditViewModel.changeName(editingWallet);
Navigator.of(context).pop();
walletEditViewModel.resetState();
} catch (e) {}
}
}
},
text: S.of(context).save,
color: Theme.of(context).accentTextTheme.bodyLarge!.color!,
textColor: Colors.white,
isDisabled: walletEditViewModel.newName.isEmpty || isLoading,
),
),
)
],
);
},
)
],
),
),
);
}
Future<void> _removeWallet(BuildContext context) async {
authService.authenticateAction(context, onAuthSuccess: (isAuthenticatedSuccessfully) async {
if (!isAuthenticatedSuccessfully) {
return;
}
_onSuccessfulAuth(context);
});
}
void _onSuccessfulAuth(BuildContext context) async {
bool confirmed = false;
await showPopUp<void>(
context: context,
builder: (BuildContext dialogContext) {
return AlertWithTwoActions(
alertTitle: S.of(context).delete_wallet,
alertContent: S.of(context).delete_wallet_confirm_message(editingWallet.name),
leftButtonText: S.of(context).cancel,
rightButtonText: S.of(context).delete,
actionLeftButton: () => Navigator.of(dialogContext).pop(),
actionRightButton: () {
confirmed = true;
Navigator.of(dialogContext).pop();
});
});
if (confirmed) {
Navigator.of(context).pop();
try {
changeProcessText(context, S.of(context).wallet_list_removing_wallet(editingWallet.name));
await walletEditViewModel.remove(editingWallet);
hideProgressText();
} catch (e) {
changeProcessText(
context,
S.of(context).wallet_list_failed_to_remove(editingWallet.name, e.toString()),
);
}
}
}
void changeProcessText(BuildContext context, String text) {
_progressBar = createBar<void>(text, duration: null)..show(context);
}
Future<void> hideProgressText() async {
await Future.delayed(Duration(milliseconds: 50), () {
_progressBar?.dismiss();
_progressBar = null;
});
}
}

View file

@ -6,7 +6,6 @@ import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart'; import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
import 'package:another_flushbar/flushbar.dart'; import 'package:another_flushbar/flushbar.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_mobx/flutter_mobx.dart'; import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:cake_wallet/routes.dart'; import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/generated/i18n.dart'; import 'package:cake_wallet/generated/i18n.dart';
@ -15,7 +14,6 @@ import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart'; import 'package:cake_wallet/src/widgets/primary_button.dart';
import 'package:cake_wallet/src/screens/base_page.dart'; import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart'; import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:cake_wallet/wallet_type_utils.dart'; import 'package:cake_wallet/wallet_type_utils.dart';
class WalletListPage extends BasePage { class WalletListPage extends BasePage {
@ -78,31 +76,7 @@ class WalletListBodyState extends State<WalletListBody> {
? Theme.of(context).accentTextTheme!.titleSmall!.decorationColor! ? Theme.of(context).accentTextTheme!.titleSmall!.decorationColor!
: Theme.of(context).colorScheme.background; : Theme.of(context).colorScheme.background;
final row = GestureDetector( final row = GestureDetector(
onTap: () async { onTap: () => wallet.isCurrent ? null : _loadWallet(wallet),
if (wallet.isCurrent || !wallet.isEnabled) {
return;
}
final confirmed = await showPopUp<bool>(
context: context,
builder: (dialogContext) {
return AlertWithTwoActions(
alertTitle: S.of(context).change_wallet_alert_title,
alertContent:
S.of(context).change_wallet_alert_content(wallet.name),
leftButtonText: S.of(context).cancel,
rightButtonText: S.of(context).change,
actionLeftButton: () =>
Navigator.of(dialogContext).pop(false),
actionRightButton: () =>
Navigator.of(dialogContext).pop(true));
}) ??
false;
if (confirmed) {
await _loadWallet(wallet);
}
},
child: Container( child: Container(
height: tileHeight, height: tileHeight,
width: double.infinity, width: double.infinity,
@ -130,16 +104,21 @@ class WalletListBodyState extends State<WalletListBody> {
? _imageFor(type: wallet.type) ? _imageFor(type: wallet.type)
: nonWalletTypeIcon, : nonWalletTypeIcon,
SizedBox(width: 10), SizedBox(width: 10),
Text( Flexible(
child: Text(
wallet.name, wallet.name,
maxLines: null,
softWrap: true,
style: TextStyle( style: TextStyle(
fontSize: 22, fontSize: 22,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Theme.of(context) color: Theme.of(context)
.primaryTextTheme .primaryTextTheme
.titleLarge! .titleLarge!
.color!), .color!,
) ),
),
),
], ],
), ),
), ),
@ -150,12 +129,38 @@ class WalletListBodyState extends State<WalletListBody> {
return wallet.isCurrent return wallet.isCurrent
? row ? row
: Slidable( : Row(children: [
key: Key('${wallet.key}'), Expanded(child: row),
startActionPane: _actionPane(wallet), GestureDetector(
endActionPane: _actionPane(wallet), onTap: () => Navigator.of(context).pushNamed(
child: row, Routes.walletEdit,
); arguments: [widget.walletListViewModel, wallet]),
child: Container(
padding: EdgeInsets.only(right: 20),
child: Center(
child: Container(
height: 40,
width: 44,
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Theme.of(context)
.textTheme
.headlineMedium!
.decorationColor!),
child: Icon(
Icons.edit,
size: 14,
color: Theme.of(context)
.textTheme
.headlineMedium!
.color!,
),
),
),
),
)
]);
}), }),
), ),
), ),
@ -218,7 +223,7 @@ class WalletListBodyState extends State<WalletListBody> {
await hideProgressText(); await hideProgressText();
// only pop the wallets route in mobile as it will go back to dashboard page // only pop the wallets route in mobile as it will go back to dashboard page
// in desktop platforms the navigation tree is different // in desktop platforms the navigation tree is different
if (ResponsiveLayoutUtil.instance.isMobile) { if (ResponsiveLayoutUtil.instance.shouldRenderMobileUI()) {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
Navigator.of(context).pop(); Navigator.of(context).pop();
}); });
@ -229,47 +234,6 @@ class WalletListBodyState extends State<WalletListBody> {
}); });
} }
Future<void> _removeWallet(WalletListItem wallet) async {
widget.authService.authenticateAction(context,
onAuthSuccess: (isAuthenticatedSuccessfully) async {
if (!isAuthenticatedSuccessfully) {
return;
}
_onSuccessfulAuth(wallet);
});
}
void _onSuccessfulAuth(WalletListItem wallet) async {
bool confirmed = false;
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle: S.of(context).delete_wallet,
alertContent: S.of(context).delete_wallet_confirm_message(wallet.name),
leftButtonText: S.of(context).cancel,
rightButtonText: S.of(context).delete,
actionLeftButton: () => Navigator.of(context).pop(),
actionRightButton: () {
confirmed = true;
Navigator.of(context).pop();
},
);
});
if (confirmed) {
try {
changeProcessText(S.of(context).wallet_list_removing_wallet(wallet.name));
await widget.walletListViewModel.remove(wallet);
hideProgressText();
} catch (e) {
changeProcessText(
S.of(context).wallet_list_failed_to_remove(wallet.name, e.toString()),
);
}
}
}
void changeProcessText(String text) { void changeProcessText(String text) {
_progressBar = createBar<void>(text, duration: null)..show(context); _progressBar = createBar<void>(text, duration: null)..show(context);
} }
@ -280,18 +244,4 @@ class WalletListBodyState extends State<WalletListBody> {
_progressBar = null; _progressBar = null;
}); });
} }
ActionPane _actionPane(WalletListItem wallet) => ActionPane(
motion: const ScrollMotion(),
extentRatio: 0.3,
children: [
SlidableAction(
onPressed: (_) => _removeWallet(wallet),
backgroundColor: Colors.red,
foregroundColor: Colors.white,
icon: CupertinoIcons.delete,
label: S.of(context).delete,
),
],
);
} }

View file

@ -46,43 +46,41 @@ class WelcomePage extends BasePage {
@override @override
Widget body(BuildContext context) { Widget body(BuildContext context) {
final welcomeImage = currentTheme.type == ThemeType.dark ? welcomeImageDark : welcomeImageLight; final welcomeImage = currentTheme.type == ThemeType.dark
? welcomeImageDark
: welcomeImageLight;
final newWalletImage = Image.asset('assets/images/new_wallet.png', final newWalletImage = Image.asset('assets/images/new_wallet.png',
height: 12, height: 12,
width: 12, width: 12,
color: Theme.of(context) color: Theme.of(context)
.accentTextTheme! .accentTextTheme.headlineSmall!
.headlineSmall!
.decorationColor!); .decorationColor!);
final restoreWalletImage = Image.asset('assets/images/restore_wallet.png', final restoreWalletImage = Image.asset('assets/images/restore_wallet.png',
height: 12, height: 12,
width: 12, width: 12,
color: Theme.of(context).primaryTextTheme!.titleLarge!.color!);
color: Theme.of(context).primaryTextTheme.titleLarge!.color!);
return WillPopScope( return WillPopScope(
onWillPop: () async => false, onWillPop: () async => false,
child: Container( child: Container(
alignment: Alignment.center,
padding: EdgeInsets.only(top: 64, bottom: 24, left: 24, right: 24), padding: EdgeInsets.only(top: 64, bottom: 24, left: 24, right: 24),
child: Center(
child: ConstrainedBox( child: ConstrainedBox(
constraints: constraints: BoxConstraints(
BoxConstraints(maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint), maxWidth: ResponsiveLayoutUtil.kDesktopMaxWidthConstraint),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Flexible(
flex: 2,
child: AspectRatio(
aspectRatio: aspectRatioImage,
child: FittedBox(child: welcomeImage, fit: BoxFit.fill))),
Flexible(
flex: 3,
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[ children: <Widget>[
Column( Column(
children: <Widget>[ children: <Widget>[
AspectRatio(
aspectRatio: aspectRatioImage,
child: FittedBox(
child: welcomeImage, fit: BoxFit.contain),
),
Padding( Padding(
padding: EdgeInsets.only(top: 24), padding: EdgeInsets.only(top: 24),
child: Text( child: Text(
@ -91,9 +89,8 @@ class WelcomePage extends BasePage {
fontSize: 18, fontSize: 18,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Theme.of(context) color: Theme.of(context)
.accentTextTheme! .accentTextTheme.displayMedium!
.displayMedium! .color!,
.color,
), ),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
@ -106,8 +103,7 @@ class WelcomePage extends BasePage {
fontSize: 36, fontSize: 36,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: Theme.of(context) color: Theme.of(context)
.primaryTextTheme! .primaryTextTheme.titleLarge!
.titleLarge!
.color!, .color!,
), ),
textAlign: TextAlign.center, textAlign: TextAlign.center,
@ -121,9 +117,8 @@ class WelcomePage extends BasePage {
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Theme.of(context) color: Theme.of(context)
.accentTextTheme! .accentTextTheme.displayMedium!
.displayMedium! .color!,
.color,
), ),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
@ -138,26 +133,23 @@ class WelcomePage extends BasePage {
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.normal, fontWeight: FontWeight.normal,
color: Theme.of(context) color: Theme.of(context)
.accentTextTheme! .accentTextTheme.displayMedium!
.displayMedium! .color!,
.color,
), ),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
Padding( Padding(
padding: EdgeInsets.only(top: 24), padding: EdgeInsets.only(top: 24),
child: PrimaryImageButton( child: PrimaryImageButton(
onPressed: () => onPressed: () => Navigator.pushNamed(
Navigator.pushNamed(context, Routes.newWalletFromWelcome), context, Routes.newWalletFromWelcome),
image: newWalletImage, image: newWalletImage,
text: S.of(context).create_new, text: S.of(context).create_new,
color: Theme.of(context) color: Theme.of(context)
.accentTextTheme! .accentTextTheme.titleSmall!
.titleSmall!
.decorationColor!, .decorationColor!,
textColor: Theme.of(context) textColor: Theme.of(context)
.accentTextTheme! .accentTextTheme.headlineSmall!
.headlineSmall!
.decorationColor!, .decorationColor!,
), ),
), ),
@ -165,26 +157,22 @@ class WelcomePage extends BasePage {
padding: EdgeInsets.only(top: 10), padding: EdgeInsets.only(top: 10),
child: PrimaryImageButton( child: PrimaryImageButton(
onPressed: () { onPressed: () {
Navigator.pushNamed(context, Routes.restoreOptions, Navigator.pushNamed(
context, Routes.restoreOptions,
arguments: true); arguments: true);
}, },
image: restoreWalletImage, image: restoreWalletImage,
text: S.of(context).restore_wallet, text: S.of(context).restore_wallet,
color: Theme.of(context) color: Theme.of(context)
.accentTextTheme! .accentTextTheme.bodySmall!
.bodySmall!
.color!, .color!,
textColor: Theme.of(context) textColor: Theme.of(context)
.primaryTextTheme! .primaryTextTheme.titleLarge!
.titleLarge!
.color!), .color!),
) )
], ],
) )
], ],
))
],
),
), ),
))); )));
} }

View file

@ -234,7 +234,7 @@ class SectionStandardList extends StatelessWidget {
return Container(); return Container();
} }
return StandardListSeparator(padding: EdgeInsets.only(left: 24)); return StandardListSeparator(padding: dividerPadding);
}, },
itemCount: totalRows.length, itemCount: totalRows.length,
itemBuilder: (_, index) => totalRows[index]); itemBuilder: (_, index) => totalRows[index]);

View file

@ -1,22 +1,32 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class ResponsiveLayoutUtil { class ResponsiveLayoutUtil {
static const double _kMobileThreshold = 768; static const double _kMobileThreshold = 550;
static const double kDesktopMaxWidthConstraint = 400; static const double kDesktopMaxWidthConstraint = 400;
static const double kDesktopMaxDashBoardWidthConstraint = 900;
static const double kPopupWidth = 400; static const double kPopupWidth = 400;
static const double kPopupSpaceHeight = 100; static const double kPopupSpaceHeight = 100;
static const _kIpadMaxWidth = 2560.0;
const ResponsiveLayoutUtil._(); const ResponsiveLayoutUtil._();
static final instance = ResponsiveLayoutUtil._(); static final instance = ResponsiveLayoutUtil._();
bool get isMobile => bool get isMobile =>
MediaQueryData.fromWindow(WidgetsBinding.instance.window).size.width < _kMobileThreshold; MediaQueryData.fromWindow(WidgetsBinding.instance.window).size.shortestSide <=
_kMobileThreshold;
bool get isIpad { bool shouldRenderMobileUI() {
final width = MediaQueryData.fromWindow(WidgetsBinding.instance.window).size.width; final mediaQuery = MediaQueryData.fromWindow(WidgetsBinding.instance.window);
return width >= _kMobileThreshold && !(width > _kIpadMaxWidth); final orientation = mediaQuery.orientation;
final width = mediaQuery.size.width;
final height = mediaQuery.size.height;
if (isMobile ||
(orientation == Orientation.portrait && width < height) ||
(orientation == Orientation.landscape && width < height)) {
return true;
} else {
return false;
}
} }
/// Returns dynamic size. /// Returns dynamic size.

View file

@ -0,0 +1,55 @@
import 'package:cake_wallet/core/wallet_loading_service.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/di.dart';
import 'package:cw_core/wallet_service.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
part 'wallet_edit_view_model.g.dart';
class WalletEditViewModel = WalletEditViewModelBase with _$WalletEditViewModel;
abstract class WalletEditViewModelState {}
class WalletEditViewModelInitialState extends WalletEditViewModelState {}
class WalletEditRenamePending extends WalletEditViewModelState {}
class WalletEditDeletePending extends WalletEditViewModelState {}
abstract class WalletEditViewModelBase with Store {
WalletEditViewModelBase(this._walletListViewModel, this._walletLoadingService)
: state = WalletEditViewModelInitialState(),
newName = '';
@observable
WalletEditViewModelState state;
@observable
String newName;
final WalletListViewModel _walletListViewModel;
final WalletLoadingService _walletLoadingService;
@action
Future<void> changeName(WalletListItem walletItem) async {
state = WalletEditRenamePending();
await _walletLoadingService.renameWallet(
walletItem.type, walletItem.name, newName);
_walletListViewModel.updateList();
}
@action
Future<void> remove(WalletListItem wallet) async {
state = WalletEditDeletePending();
final walletService = getIt.get<WalletService>(param1: wallet.type);
await walletService.remove(wallet.name);
resetState();
_walletListViewModel.updateList();
}
@action
void resetState() {
state = WalletEditViewModelInitialState();
}
}

View file

@ -1,10 +1,9 @@
import 'package:cake_wallet/core/auth_service.dart'; import 'package:cake_wallet/core/auth_service.dart';
import 'package:cake_wallet/core/wallet_loading_service.dart'; import 'package:cake_wallet/core/wallet_loading_service.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart'; import 'package:mobx/mobx.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/store/app_store.dart'; import 'package:cake_wallet/store/app_store.dart';
import 'package:cw_core/wallet_service.dart';
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart'; import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
import 'package:cw_core/wallet_info.dart'; import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart'; import 'package:cw_core/wallet_type.dart';
@ -21,8 +20,8 @@ abstract class WalletListViewModelBase with Store {
this._walletLoadingService, this._walletLoadingService,
this._authService, this._authService,
) : wallets = ObservableList<WalletListItem>() { ) : wallets = ObservableList<WalletListItem>() {
_updateList(); updateList();
reaction((_) => _appStore.wallet, (_) => _updateList()); reaction((_) => _appStore.wallet, (_) => updateList());
} }
@observable @observable
@ -37,20 +36,14 @@ abstract class WalletListViewModelBase with Store {
@action @action
Future<void> loadWallet(WalletListItem walletItem) async { Future<void> loadWallet(WalletListItem walletItem) async {
final wallet = await _walletLoadingService.load(walletItem.type, walletItem.name); final wallet =
await _walletLoadingService.load(walletItem.type, walletItem.name);
_appStore.changeCurrentWallet(wallet); _appStore.changeCurrentWallet(wallet);
_updateList();
} }
@action @action
Future<void> remove(WalletListItem wallet) async { void updateList() {
final walletService = getIt.get<WalletService>(param1: wallet.type);
await walletService.remove(wallet.name);
await _walletInfoSource.delete(wallet.key);
_updateList();
}
void _updateList() {
wallets.clear(); wallets.clear();
wallets.addAll( wallets.addAll(
_walletInfoSource.values.map( _walletInfoSource.values.map(
@ -58,7 +51,8 @@ abstract class WalletListViewModelBase with Store {
name: info.name, name: info.name,
type: info.type, type: info.type,
key: info.key, key: info.key,
isCurrent: info.name == _appStore.wallet!.name && info.type == _appStore.wallet!.type, isCurrent: info.name == _appStore.wallet!.name &&
info.type == _appStore.wallet!.type,
isEnabled: availableWalletTypes.contains(info.type), isEnabled: availableWalletTypes.contains(info.type),
), ),
), ),

View file

@ -250,6 +250,8 @@
"transaction_details_recipient_address": "عناوين المستلم", "transaction_details_recipient_address": "عناوين المستلم",
"wallet_list_title": "محفظة Monero", "wallet_list_title": "محفظة Monero",
"wallet_list_create_new_wallet": "إنشاء محفظة جديدة", "wallet_list_create_new_wallet": "إنشاء محفظة جديدة",
"wallet_list_edit_wallet" : "تحرير المحفظة",
"wallet_list_wallet_name" : "اسم المحفظة",
"wallet_list_restore_wallet": "استعادة المحفظة", "wallet_list_restore_wallet": "استعادة المحفظة",
"wallet_list_load_wallet": "تحميل المحفظة", "wallet_list_load_wallet": "تحميل المحفظة",
"wallet_list_loading_wallet": "جار تحميل محفظة ${wallet_name}", "wallet_list_loading_wallet": "جار تحميل محفظة ${wallet_name}",

View file

@ -250,6 +250,8 @@
"transaction_details_recipient_address": "Адрес на получател", "transaction_details_recipient_address": "Адрес на получател",
"wallet_list_title": "Monero портфейл", "wallet_list_title": "Monero портфейл",
"wallet_list_create_new_wallet": "Създаване на нов портфейл", "wallet_list_create_new_wallet": "Създаване на нов портфейл",
"wallet_list_edit_wallet" : "Редактиране на портфейла",
"wallet_list_wallet_name" : "Име на портфейла",
"wallet_list_restore_wallet": "Възстановяване на портфейл", "wallet_list_restore_wallet": "Възстановяване на портфейл",
"wallet_list_load_wallet": "Зареждане на портфейл", "wallet_list_load_wallet": "Зареждане на портфейл",
"wallet_list_loading_wallet": "Зареждане на портфейл ${wallet_name}", "wallet_list_loading_wallet": "Зареждане на портфейл ${wallet_name}",

View file

@ -250,6 +250,8 @@
"transaction_details_recipient_address": "Adresa příjemce", "transaction_details_recipient_address": "Adresa příjemce",
"wallet_list_title": "Monero Wallet", "wallet_list_title": "Monero Wallet",
"wallet_list_create_new_wallet": "Vytvořit novou peněženku", "wallet_list_create_new_wallet": "Vytvořit novou peněženku",
"wallet_list_edit_wallet" : "Upravit peněženku",
"wallet_list_wallet_name" : "Název peněženky",
"wallet_list_restore_wallet": "Obnovit peněženku", "wallet_list_restore_wallet": "Obnovit peněženku",
"wallet_list_load_wallet": "Načíst peněženku", "wallet_list_load_wallet": "Načíst peněženku",
"wallet_list_loading_wallet": "Načítám ${wallet_name} peněženku", "wallet_list_loading_wallet": "Načítám ${wallet_name} peněženku",

View file

@ -250,6 +250,8 @@
"transaction_details_recipient_address": "Empfängeradressen", "transaction_details_recipient_address": "Empfängeradressen",
"wallet_list_title": "Monero-Wallet", "wallet_list_title": "Monero-Wallet",
"wallet_list_create_new_wallet": "Neue Wallet erstellen", "wallet_list_create_new_wallet": "Neue Wallet erstellen",
"wallet_list_edit_wallet" : "Wallet bearbeiten",
"wallet_list_wallet_name" : "Wallet namen",
"wallet_list_restore_wallet": "Wallet wiederherstellen", "wallet_list_restore_wallet": "Wallet wiederherstellen",
"wallet_list_load_wallet": "Wallet laden", "wallet_list_load_wallet": "Wallet laden",
"wallet_list_loading_wallet": "Wallet ${wallet_name} wird geladen", "wallet_list_loading_wallet": "Wallet ${wallet_name} wird geladen",

View file

@ -250,6 +250,8 @@
"transaction_details_recipient_address": "Recipient addresses", "transaction_details_recipient_address": "Recipient addresses",
"wallet_list_title": "Monero Wallet", "wallet_list_title": "Monero Wallet",
"wallet_list_create_new_wallet": "Create New Wallet", "wallet_list_create_new_wallet": "Create New Wallet",
"wallet_list_edit_wallet" : "Edit wallet",
"wallet_list_wallet_name" : "Wallet name",
"wallet_list_restore_wallet": "Restore Wallet", "wallet_list_restore_wallet": "Restore Wallet",
"wallet_list_load_wallet": "Load wallet", "wallet_list_load_wallet": "Load wallet",
"wallet_list_loading_wallet": "Loading ${wallet_name} wallet", "wallet_list_loading_wallet": "Loading ${wallet_name} wallet",

View file

@ -250,6 +250,8 @@
"transaction_details_recipient_address": "Direcciones de destinatarios", "transaction_details_recipient_address": "Direcciones de destinatarios",
"wallet_list_title": "Monedero Monero", "wallet_list_title": "Monedero Monero",
"wallet_list_create_new_wallet": "Crear nueva billetera", "wallet_list_create_new_wallet": "Crear nueva billetera",
"wallet_list_edit_wallet" : "Editar billetera",
"wallet_list_wallet_name" : "Nombre de la billetera",
"wallet_list_restore_wallet": "Restaurar billetera", "wallet_list_restore_wallet": "Restaurar billetera",
"wallet_list_load_wallet": "Billetera de carga", "wallet_list_load_wallet": "Billetera de carga",
"wallet_list_loading_wallet": "Billetera ${wallet_name} de carga", "wallet_list_loading_wallet": "Billetera ${wallet_name} de carga",

View file

@ -250,6 +250,8 @@
"transaction_details_recipient_address": "Adresse du bénéficiaire", "transaction_details_recipient_address": "Adresse du bénéficiaire",
"wallet_list_title": "Portefeuille (Wallet) Monero", "wallet_list_title": "Portefeuille (Wallet) Monero",
"wallet_list_create_new_wallet": "Créer un Nouveau Portefeuille (Wallet)", "wallet_list_create_new_wallet": "Créer un Nouveau Portefeuille (Wallet)",
"wallet_list_edit_wallet" : "Modifier le portefeuille",
"wallet_list_wallet_name" : "Nom du portefeuille",
"wallet_list_restore_wallet": "Restaurer un Portefeuille (Wallet)", "wallet_list_restore_wallet": "Restaurer un Portefeuille (Wallet)",
"wallet_list_load_wallet": "Charger un Portefeuille (Wallet)", "wallet_list_load_wallet": "Charger un Portefeuille (Wallet)",
"wallet_list_loading_wallet": "Chargement du portefeuille (wallet) ${wallet_name}", "wallet_list_loading_wallet": "Chargement du portefeuille (wallet) ${wallet_name}",

View file

@ -250,6 +250,8 @@
"transaction_details_recipient_address": "Adireshin masu amfani", "transaction_details_recipient_address": "Adireshin masu amfani",
"wallet_list_title": "Monero walat", "wallet_list_title": "Monero walat",
"wallet_list_create_new_wallet": "Ƙirƙiri Sabon Wallet", "wallet_list_create_new_wallet": "Ƙirƙiri Sabon Wallet",
"wallet_list_edit_wallet" : "Gyara walat",
"wallet_list_wallet_name" : "Sunan walat",
"wallet_list_restore_wallet": "Maida Wallet", "wallet_list_restore_wallet": "Maida Wallet",
"wallet_list_load_wallet": "Ana loda wallet na Monero", "wallet_list_load_wallet": "Ana loda wallet na Monero",
"wallet_list_loading_wallet": "Ana loda ${wallet_name} walat", "wallet_list_loading_wallet": "Ana loda ${wallet_name} walat",
@ -634,3 +636,4 @@
"share": "Raba", "share": "Raba",
"slidable": "Mai iya zamewa" "slidable": "Mai iya zamewa"
} }

View file

@ -250,6 +250,8 @@
"transaction_details_recipient_address": "प्राप्तकर्ता के पते", "transaction_details_recipient_address": "प्राप्तकर्ता के पते",
"wallet_list_title": "Monero बटुआ", "wallet_list_title": "Monero बटुआ",
"wallet_list_create_new_wallet": "नया बटुआ बनाएँ", "wallet_list_create_new_wallet": "नया बटुआ बनाएँ",
"wallet_list_edit_wallet" : "बटुआ संपादित करें",
"wallet_list_wallet_name" : "बटुआ नाम",
"wallet_list_restore_wallet": "वॉलेट को पुनर्स्थापित करें", "wallet_list_restore_wallet": "वॉलेट को पुनर्स्थापित करें",
"wallet_list_load_wallet": "वॉलेट लोड करें", "wallet_list_load_wallet": "वॉलेट लोड करें",
"wallet_list_loading_wallet": "लोड हो रहा है ${wallet_name} बटुआ", "wallet_list_loading_wallet": "लोड हो रहा है ${wallet_name} बटुआ",

View file

@ -250,6 +250,8 @@
"transaction_details_recipient_address": "Adrese primatelja", "transaction_details_recipient_address": "Adrese primatelja",
"wallet_list_title": "Monero novčanik", "wallet_list_title": "Monero novčanik",
"wallet_list_create_new_wallet": "Izradi novi novčanik", "wallet_list_create_new_wallet": "Izradi novi novčanik",
"wallet_list_edit_wallet" : "Uredi novčanik",
"wallet_list_wallet_name" : "Naziv novčanika",
"wallet_list_restore_wallet": "Oporavi novčanik", "wallet_list_restore_wallet": "Oporavi novčanik",
"wallet_list_load_wallet": "Učitaj novčanik", "wallet_list_load_wallet": "Učitaj novčanik",
"wallet_list_loading_wallet": "Učitavanje novčanika ${wallet_name}", "wallet_list_loading_wallet": "Učitavanje novčanika ${wallet_name}",

View file

@ -250,6 +250,8 @@
"transaction_details_recipient_address": "Alamat Penerima", "transaction_details_recipient_address": "Alamat Penerima",
"wallet_list_title": "Dompet Monero", "wallet_list_title": "Dompet Monero",
"wallet_list_create_new_wallet": "Buat Dompet Baru", "wallet_list_create_new_wallet": "Buat Dompet Baru",
"wallet_list_edit_wallet" : "Edit dompet",
"wallet_list_wallet_name" : "Nama dompet",
"wallet_list_restore_wallet": "Pulihkan Dompet", "wallet_list_restore_wallet": "Pulihkan Dompet",
"wallet_list_load_wallet": "Muat dompet", "wallet_list_load_wallet": "Muat dompet",
"wallet_list_loading_wallet": "Memuat ${wallet_name} dompet", "wallet_list_loading_wallet": "Memuat ${wallet_name} dompet",

View file

@ -250,6 +250,8 @@
"transaction_details_recipient_address": "Indirizzi dei destinatari", "transaction_details_recipient_address": "Indirizzi dei destinatari",
"wallet_list_title": "Portafoglio Monero", "wallet_list_title": "Portafoglio Monero",
"wallet_list_create_new_wallet": "Crea Nuovo Portafoglio", "wallet_list_create_new_wallet": "Crea Nuovo Portafoglio",
"wallet_list_edit_wallet" : "Modifica portafoglio",
"wallet_list_wallet_name" : "Nome del portafoglio",
"wallet_list_restore_wallet": "Recupera Portafoglio", "wallet_list_restore_wallet": "Recupera Portafoglio",
"wallet_list_load_wallet": "Caricamento Portafoglio", "wallet_list_load_wallet": "Caricamento Portafoglio",
"wallet_list_loading_wallet": "Caricamento portafoglio ${wallet_name}", "wallet_list_loading_wallet": "Caricamento portafoglio ${wallet_name}",

View file

@ -250,6 +250,8 @@
"transaction_details_recipient_address": "受信者のアドレス", "transaction_details_recipient_address": "受信者のアドレス",
"wallet_list_title": "Monero 財布", "wallet_list_title": "Monero 財布",
"wallet_list_create_new_wallet": "新しいウォレットを作成", "wallet_list_create_new_wallet": "新しいウォレットを作成",
"wallet_list_edit_wallet" : "ウォレットを編集する",
"wallet_list_wallet_name" : "ウォレット名",
"wallet_list_restore_wallet": "ウォレットを復元", "wallet_list_restore_wallet": "ウォレットを復元",
"wallet_list_load_wallet": "ウォレットをロード", "wallet_list_load_wallet": "ウォレットをロード",
"wallet_list_loading_wallet": "読み込み中 ${wallet_name} 財布", "wallet_list_loading_wallet": "読み込み中 ${wallet_name} 財布",

View file

@ -250,6 +250,8 @@
"transaction_details_recipient_address": "받는 사람 주소", "transaction_details_recipient_address": "받는 사람 주소",
"wallet_list_title": "모네로 월렛", "wallet_list_title": "모네로 월렛",
"wallet_list_create_new_wallet": "새 월렛 만들기", "wallet_list_create_new_wallet": "새 월렛 만들기",
"wallet_list_edit_wallet" : "지갑 수정",
"wallet_list_wallet_name" : "지갑 이름",
"wallet_list_restore_wallet": "월렛 복원", "wallet_list_restore_wallet": "월렛 복원",
"wallet_list_load_wallet": "지갑로드", "wallet_list_load_wallet": "지갑로드",
"wallet_list_loading_wallet": "로딩 ${wallet_name} 지갑", "wallet_list_loading_wallet": "로딩 ${wallet_name} 지갑",

View file

@ -250,6 +250,8 @@
"transaction_details_recipient_address": "လက်ခံသူလိပ်စာများ", "transaction_details_recipient_address": "လက်ခံသူလိပ်စာများ",
"wallet_list_title": "Monero ပိုက်ဆံအိတ်", "wallet_list_title": "Monero ပိုက်ဆံအိတ်",
"wallet_list_create_new_wallet": "Wallet အသစ်ဖန်တီးပါ။", "wallet_list_create_new_wallet": "Wallet အသစ်ဖန်တီးပါ။",
"wallet_list_edit_wallet" : "ပိုက်ဆံအိတ်ကို တည်းဖြတ်ပါ။",
"wallet_list_wallet_name" : "ပိုက်ဆံအိတ်နာမည်",
"wallet_list_restore_wallet": "ပိုက်ဆံအိတ်ကို ပြန်ယူပါ။", "wallet_list_restore_wallet": "ပိုက်ဆံအိတ်ကို ပြန်ယူပါ။",
"wallet_list_load_wallet": "ပိုက်ဆံအိတ်ကို တင်ပါ။", "wallet_list_load_wallet": "ပိုက်ဆံအိတ်ကို တင်ပါ။",
"wallet_list_loading_wallet": "${wallet_name} ပိုက်ဆံအိတ်ကို ဖွင့်နေသည်။", "wallet_list_loading_wallet": "${wallet_name} ပိုက်ဆံအိတ်ကို ဖွင့်နေသည်။",

View file

@ -250,6 +250,8 @@
"transaction_details_recipient_address": "Adressen van ontvangers", "transaction_details_recipient_address": "Adressen van ontvangers",
"wallet_list_title": "Monero portemonnee", "wallet_list_title": "Monero portemonnee",
"wallet_list_create_new_wallet": "Maak een nieuwe portemonnee", "wallet_list_create_new_wallet": "Maak een nieuwe portemonnee",
"wallet_list_edit_wallet" : "Portemonnee bewerken",
"wallet_list_wallet_name" : "Portemonnee naam",
"wallet_list_restore_wallet": "Portemonnee herstellen", "wallet_list_restore_wallet": "Portemonnee herstellen",
"wallet_list_load_wallet": "Portemonnee laden", "wallet_list_load_wallet": "Portemonnee laden",
"wallet_list_loading_wallet": "Bezig met laden ${wallet_name} portemonnee", "wallet_list_loading_wallet": "Bezig met laden ${wallet_name} portemonnee",

View file

@ -250,6 +250,8 @@
"transaction_details_recipient_address": "Adres odbiorcy", "transaction_details_recipient_address": "Adres odbiorcy",
"wallet_list_title": "Portfel Monero", "wallet_list_title": "Portfel Monero",
"wallet_list_create_new_wallet": "Utwórz nowy portfel", "wallet_list_create_new_wallet": "Utwórz nowy portfel",
"wallet_list_edit_wallet" : "Edytuj portfel",
"wallet_list_wallet_name" : "Nazwa portfela",
"wallet_list_restore_wallet": "Przywróć portfel", "wallet_list_restore_wallet": "Przywróć portfel",
"wallet_list_load_wallet": "Załaduj portfel", "wallet_list_load_wallet": "Załaduj portfel",
"wallet_list_loading_wallet": "Ładuję ${wallet_name} portfel", "wallet_list_loading_wallet": "Ładuję ${wallet_name} portfel",

View file

@ -250,6 +250,8 @@
"transaction_details_recipient_address": "Endereços de destinatários", "transaction_details_recipient_address": "Endereços de destinatários",
"wallet_list_title": "Carteira Monero", "wallet_list_title": "Carteira Monero",
"wallet_list_create_new_wallet": "Criar nova carteira", "wallet_list_create_new_wallet": "Criar nova carteira",
"wallet_list_edit_wallet" : "Editar carteira",
"wallet_list_wallet_name" : "Nome da carteira",
"wallet_list_restore_wallet": "Restaurar carteira", "wallet_list_restore_wallet": "Restaurar carteira",
"wallet_list_load_wallet": "Abrir carteira", "wallet_list_load_wallet": "Abrir carteira",
"wallet_list_loading_wallet": "Abrindo a carteira ${wallet_name}", "wallet_list_loading_wallet": "Abrindo a carteira ${wallet_name}",

View file

@ -250,6 +250,8 @@
"transaction_details_recipient_address": "Адреса получателей", "transaction_details_recipient_address": "Адреса получателей",
"wallet_list_title": "Monero Кошелёк", "wallet_list_title": "Monero Кошелёк",
"wallet_list_create_new_wallet": "Создать новый кошелёк", "wallet_list_create_new_wallet": "Создать новый кошелёк",
"wallet_list_edit_wallet" : "Изменить кошелек",
"wallet_list_wallet_name" : "Имя кошелька",
"wallet_list_restore_wallet": "Восстановить кошелёк", "wallet_list_restore_wallet": "Восстановить кошелёк",
"wallet_list_load_wallet": "Загрузка кошелька", "wallet_list_load_wallet": "Загрузка кошелька",
"wallet_list_loading_wallet": "Загрузка ${wallet_name} кошелька", "wallet_list_loading_wallet": "Загрузка ${wallet_name} кошелька",

View file

@ -250,6 +250,8 @@
"transaction_details_recipient_address": "ที่อยู่ผู้รับ", "transaction_details_recipient_address": "ที่อยู่ผู้รับ",
"wallet_list_title": "กระเป๋า Monero", "wallet_list_title": "กระเป๋า Monero",
"wallet_list_create_new_wallet": "สร้างกระเป๋าใหม่", "wallet_list_create_new_wallet": "สร้างกระเป๋าใหม่",
"wallet_list_edit_wallet" : "แก้ไขกระเป๋าสตางค์",
"wallet_list_wallet_name" : "ชื่อกระเป๋าสตางค์",
"wallet_list_restore_wallet": "กู้กระเป๋า", "wallet_list_restore_wallet": "กู้กระเป๋า",
"wallet_list_load_wallet": "โหลดกระเป๋า", "wallet_list_load_wallet": "โหลดกระเป๋า",
"wallet_list_loading_wallet": "กำลังโหลดกระเป๋า ${wallet_name}", "wallet_list_loading_wallet": "กำลังโหลดกระเป๋า ${wallet_name}",

View file

@ -250,6 +250,8 @@
"transaction_details_recipient_address": "Alıcı adres", "transaction_details_recipient_address": "Alıcı adres",
"wallet_list_title": "Monero Cüzdanı", "wallet_list_title": "Monero Cüzdanı",
"wallet_list_create_new_wallet": "Yeni Cüzdan Oluştur", "wallet_list_create_new_wallet": "Yeni Cüzdan Oluştur",
"wallet_list_edit_wallet" : "Cüzdanı düzenle",
"wallet_list_wallet_name" : "Cüzdan adı",
"wallet_list_restore_wallet": "Cüzdanı Geri Yükle", "wallet_list_restore_wallet": "Cüzdanı Geri Yükle",
"wallet_list_load_wallet": "Cüzdanı yükle", "wallet_list_load_wallet": "Cüzdanı yükle",
"wallet_list_loading_wallet": "${wallet_name} cüzdanı yükleniyor", "wallet_list_loading_wallet": "${wallet_name} cüzdanı yükleniyor",

View file

@ -250,6 +250,8 @@
"transaction_details_recipient_address": "Адреси одержувачів", "transaction_details_recipient_address": "Адреси одержувачів",
"wallet_list_title": "Monero Гаманець", "wallet_list_title": "Monero Гаманець",
"wallet_list_create_new_wallet": "Створити новий гаманець", "wallet_list_create_new_wallet": "Створити новий гаманець",
"wallet_list_edit_wallet" : "Редагувати гаманець",
"wallet_list_wallet_name" : "Назва гаманця",
"wallet_list_restore_wallet": "Відновити гаманець", "wallet_list_restore_wallet": "Відновити гаманець",
"wallet_list_load_wallet": "Завантаження гаманця", "wallet_list_load_wallet": "Завантаження гаманця",
"wallet_list_loading_wallet": "Завантаження ${wallet_name} гаманця", "wallet_list_loading_wallet": "Завантаження ${wallet_name} гаманця",

Some files were not shown because too many files have changed in this diff Show more