Merged with 4.1.0

This commit is contained in:
Tanner Silva
2020-12-24 18:15:03 -06:00
132 changed files with 5479 additions and 1402 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 760 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 408 B

After

Width:  |  Height:  |  Size: 629 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 341 B

After

Width:  |  Height:  |  Size: 440 B

+6 -6
View File
@@ -354,7 +354,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 3;
CURRENT_PROJECT_VERSION = 7;
DEVELOPMENT_TEAM = 32J6BB6VUS;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
@@ -371,7 +371,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
MARKETING_VERSION = 4.0.8;
MARKETING_VERSION = 4.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.fotolockr.cakewallet;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -494,7 +494,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 3;
CURRENT_PROJECT_VERSION = 7;
DEVELOPMENT_TEAM = 32J6BB6VUS;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
@@ -511,7 +511,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
MARKETING_VERSION = 4.0.8;
MARKETING_VERSION = 4.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.fotolockr.cakewallet;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
@@ -528,7 +528,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 3;
CURRENT_PROJECT_VERSION = 7;
DEVELOPMENT_TEAM = 32J6BB6VUS;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
@@ -545,7 +545,7 @@
"$(inherited)",
"$(PROJECT_DIR)/Flutter",
);
MARKETING_VERSION = 4.0.8;
MARKETING_VERSION = 4.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.fotolockr.cakewallet;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
+25
View File
@@ -0,0 +1,25 @@
import 'dart:typed_data';
import 'package:bs58check/bs58check.dart' as bs58check;
import 'package:bitcoin_flutter/src/utils/constants/op.dart';
import 'package:bitcoin_flutter/src/utils/script.dart' as bscript;
import 'package:bitcoin_flutter/src/address.dart';
Uint8List p2shAddressToOutputScript(String address) {
final decodeBase58 = bs58check.decode(address);
final hash = decodeBase58.sublist(1);
return bscript.compile(<dynamic>[OPS['OP_HASH160'], hash, OPS['OP_EQUAL']]);
}
Uint8List addressToOutputScript(String address) {
try {
// FIXME: improve validation for p2sh addresses
if (address.startsWith('3')) {
return p2shAddressToOutputScript(address);
}
return Address.addressToOutputScript(address);
} catch (_) {
return Uint8List(0);
}
}
+25 -2
View File
@@ -1,11 +1,16 @@
import 'dart:convert';
import 'package:cake_wallet/entities/balance_display_mode.dart';
import 'package:flutter/foundation.dart';
import 'package:cake_wallet/bitcoin/bitcoin_amount_format.dart';
import 'package:cake_wallet/entities/balance.dart';
class BitcoinBalance extends Balance {
const BitcoinBalance({@required this.confirmed, @required this.unconfirmed}) : super();
const BitcoinBalance({@required this.confirmed, @required this.unconfirmed})
: super(const [
BalanceDisplayMode.availableBalance,
BalanceDisplayMode.fullBalance
]);
factory BitcoinBalance.fromJSON(String jsonSource) {
if (jsonSource == null) {
@@ -22,7 +27,10 @@ class BitcoinBalance extends Balance {
final int confirmed;
final int unconfirmed;
int get total => confirmed + unconfirmed;
int get total =>
confirmed + (unconfirmed < 0 ? unconfirmed * -1 : unconfirmed);
int get availableBalance => confirmed + (unconfirmed < 0 ? unconfirmed : 0);
String get confirmedFormatted => bitcoinAmountToString(amount: confirmed);
@@ -30,6 +38,21 @@ class BitcoinBalance extends Balance {
String get totalFormatted => bitcoinAmountToString(amount: total);
String get availableBalanceFormatted =>
bitcoinAmountToString(amount: availableBalance);
@override
String formattedBalance(BalanceDisplayMode mode) {
switch (mode) {
case BalanceDisplayMode.fullBalance:
return totalFormatted;
case BalanceDisplayMode.availableBalance:
return availableBalanceFormatted;
default:
return null;
}
}
String toJSON() =>
json.encode({'confirmed': confirmed, 'unconfirmed': unconfirmed});
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,5 @@
class BitcoinMnemonicIsIncorrectException implements Exception {
@override
String toString() =>
'Bitcoin mnemonic has incorrect format. Mnemonic should contain 12 words separated by space.';
}
+4 -6
View File
@@ -65,7 +65,7 @@ abstract class BitcoinTransactionHistoryBase
return historiesWithDetails.fold<Map<String, BitcoinTransactionInfo>>(
<String, BitcoinTransactionInfo>{}, (acc, tx) {
acc[tx.id] = tx;
acc[tx.id] = acc[tx.id]?.updated(tx) ?? tx;
return acc;
});
}
@@ -103,10 +103,6 @@ abstract class BitcoinTransactionHistoryBase
Future<void> save() async {
final data = json.encode({'height': _height, 'transactions': transactions});
print('data');
print(data);
await writeData(path: path, password: _password, data: data);
}
@@ -168,7 +164,9 @@ abstract class BitcoinTransactionHistoryBase
});
_height = content['height'] as int;
} catch (_) {}
} catch (e) {
print(e);
}
}
void _updateOrInsert(BitcoinTransactionInfo transaction) {
+33 -6
View File
@@ -12,6 +12,7 @@ class BitcoinTransactionInfo extends TransactionInfo {
{@required String id,
@required int height,
@required int amount,
@required int fee,
@required TransactionDirection direction,
@required bool isPending,
@required DateTime date,
@@ -19,6 +20,7 @@ class BitcoinTransactionInfo extends TransactionInfo {
this.id = id;
this.height = height;
this.amount = amount;
this.fee = fee;
this.direction = direction;
this.date = date;
this.isPending = isPending;
@@ -36,37 +38,42 @@ class BitcoinTransactionInfo extends TransactionInfo {
: DateTime.now();
final confirmations = obj['confirmations'] as int ?? 0;
var direction = TransactionDirection.incoming;
var inputsAmount = 0;
var amount = 0;
var totalOutAmount = 0;
for (dynamic vin in vins) {
final vout = vin['vout'] as int;
final out = vin['tx']['vout'][vout] as Map;
final outAddresses =
(out['scriptPubKey']['addresses'] as List<Object>)?.toSet();
inputsAmount += doubleToBitcoinAmount(out['value'] as double ?? 0);
if (outAddresses?.intersection(addressesSet)?.isNotEmpty ?? false) {
direction = TransactionDirection.outgoing;
break;
}
}
final amount = vout.fold(0, (int acc, dynamic out) {
for (dynamic out in vout) {
final outAddresses =
out['scriptPubKey']['addresses'] as List<Object> ?? [];
final ntrs = outAddresses.toSet().intersection(addressesSet);
var amount = acc;
final value = doubleToBitcoinAmount(out['value'] as double ?? 0.0);
totalOutAmount += value;
if ((direction == TransactionDirection.incoming && ntrs.isNotEmpty) ||
(direction == TransactionDirection.outgoing && ntrs.isEmpty)) {
amount += doubleToBitcoinAmount(out['value'] as double ?? 0.0);
amount += value;
}
}
return amount;
});
final fee = inputsAmount - totalOutAmount;
return BitcoinTransactionInfo(
id: id,
height: height,
isPending: false,
fee: fee,
direction: direction,
amount: amount,
date: date,
@@ -101,6 +108,7 @@ class BitcoinTransactionInfo extends TransactionInfo {
id: tx.getId(),
height: height,
isPending: false,
fee: null,
direction: TransactionDirection.incoming,
amount: amount,
date: date,
@@ -112,6 +120,7 @@ class BitcoinTransactionInfo extends TransactionInfo {
id: data['id'] as String,
height: data['height'] as int,
amount: data['amount'] as int,
fee: data['fee'] as int,
direction: parseTransactionDirectionFromInt(data['direction'] as int),
date: DateTime.fromMillisecondsSinceEpoch(data['date'] as int),
isPending: data['isPending'] as bool,
@@ -124,12 +133,29 @@ class BitcoinTransactionInfo extends TransactionInfo {
String amountFormatted() =>
'${formatAmount(bitcoinAmountToString(amount: amount))} BTC';
@override
String feeFormatted() => fee != null
? '${formatAmount(bitcoinAmountToString(amount: fee))} BTC'
: '';
@override
String fiatAmount() => _fiatAmount ?? '';
@override
void changeFiatAmount(String amount) => _fiatAmount = formatAmount(amount);
BitcoinTransactionInfo updated(BitcoinTransactionInfo info) {
return BitcoinTransactionInfo(
id: id,
height: info.height,
amount: info.amount,
fee: info.fee,
direction: direction ?? info.direction,
date: date ?? info.date,
isPending: isPending ?? info.isPending,
confirmations: info.confirmations);
}
Map<String, dynamic> toJson() {
final m = <String, dynamic>{};
m['id'] = id;
@@ -139,6 +165,7 @@ class BitcoinTransactionInfo extends TransactionInfo {
m['date'] = date.millisecondsSinceEpoch;
m['isPending'] = isPending;
m['confirmations'] = confirmations;
m['fee'] = fee;
return m;
}
}
+51 -17
View File
@@ -1,7 +1,8 @@
import 'dart:async';
import 'dart:convert';
import 'package:cake_wallet/bitcoin/address_to_output_script.dart';
import 'package:cake_wallet/bitcoin/bitcoin_mnemonic.dart';
import 'package:mobx/mobx.dart';
import 'package:bip39/bip39.dart' as bip39;
import 'package:flutter/foundation.dart';
import 'package:rxdart/rxdart.dart';
import 'package:bitcoin_flutter/bitcoin_flutter.dart' as bitcoin;
@@ -42,8 +43,9 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
BitcoinBalance initialBalance})
: balance =
initialBalance ?? BitcoinBalance(confirmed: 0, unconfirmed: 0),
hd = bitcoin.HDWallet.fromSeed(bip39.mnemonicToSeed(mnemonic),
network: bitcoin.bitcoin),
hd = bitcoin.HDWallet.fromSeed(mnemonicToSeedBytes(mnemonic),
network: bitcoin.bitcoin)
.derivePath("m/0'/0"),
addresses = initialAddresses != null
? ObservableList<BitcoinAddressRecord>.of(initialAddresses)
: ObservableList<BitcoinAddressRecord>(),
@@ -58,6 +60,7 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
{@required String password,
@required String name,
@required String dirPath,
@required WalletInfo walletInfo,
String jsonSource}) {
final data = json.decode(jsonSource) as Map;
final mnemonic = data['mnemonic'] as String;
@@ -83,7 +86,8 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
name: name,
accountIndex: accountIndex,
initialAddresses: addresses,
initialBalance: balance);
initialBalance: balance,
walletInfo: walletInfo);
}
static BitcoinWallet build(
@@ -91,6 +95,7 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
@required String password,
@required String name,
@required String dirPath,
@required WalletInfo walletInfo,
List<BitcoinAddressRecord> initialAddresses,
BitcoinBalance initialBalance,
int accountIndex = 0}) {
@@ -107,7 +112,8 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
accountIndex: accountIndex,
initialAddresses: initialAddresses,
initialBalance: initialBalance,
transactionHistory: history);
transactionHistory: history,
walletInfo: walletInfo);
}
@override
@@ -170,6 +176,22 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
return address;
}
Future<List<BitcoinAddressRecord>> generateNewAddresses(int count) async {
final list = <BitcoinAddressRecord>[];
for (var i = 0; i < count; i++) {
_accountIndex += 1;
final address = BitcoinAddressRecord(_getAddress(index: _accountIndex),
index: _accountIndex, label: null);
list.add(address);
}
addresses.addAll(list);
await save();
return list;
}
Future<void> updateAddress(String address, {String label}) async {
for (final addr in addresses) {
if (addr.address == address) {
@@ -185,8 +207,10 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
Future<void> startSync() async {
try {
syncStatus = StartingSyncStatus();
transactionHistory.updateAsync(
onFinished: () => print('transactionHistory update finished!'));
transactionHistory.updateAsync(onFinished: () {
print('transactionHistory update finished!');
transactionHistory.save();
});
_subscribeForUpdates();
await _updateBalance();
syncStatus = SyncedSyncStatus();
@@ -238,9 +262,8 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
final utxs = await unptsFutures;
for (final utx in utxs) {
final inAmount = utx.value > totalAmount ? totalAmount : utx.value;
leftAmount = leftAmount - inAmount;
totalInputAmount += inAmount;
leftAmount = leftAmount - utx.value;
totalInputAmount += utx.value;
inputs.add(utx);
if (leftAmount <= 0) {
@@ -279,7 +302,8 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
}
});
txb.addOutput(transactionCredentials.address, amount);
txb.addOutput(
addressToOutputScript(transactionCredentials.address), amount);
if (changeValue > 0) {
txb.addOutput(changeAddress, changeValue);
@@ -295,7 +319,10 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
return PendingBitcoinTransaction(txb.build(),
eclient: eclient, amount: amount, fee: fee)
..addListener((transaction) => transactionHistory.addOne(transaction));
..addListener((transaction) async {
transactionHistory.addOne(transaction);
await _updateBalance();
});
}
String toJSON() => json.encode({
@@ -310,8 +337,10 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
bitcoinAmountToDouble(amount: _feeMultiplier(priority));
@override
Future<void> save() async =>
await write(path: path, password: _password, data: toJSON());
Future<void> save() async {
await write(path: path, password: _password, data: toJSON());
await transactionHistory.save();
}
bitcoin.ECPair keyPairFor({@required int index}) =>
generateKeyPair(hd: hd, index: index);
@@ -321,13 +350,18 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
// FIXME: Unimplemented
}
@override
void close() async{
await eclient.close();
}
void _subscribeForUpdates() {
scriptHashes.forEach((sh) async {
await _scripthashesUpdateSubject[sh]?.close();
_scripthashesUpdateSubject[sh] = eclient.scripthashUpdate(sh);
_scripthashesUpdateSubject[sh].listen((event) async {
transactionHistory.updateAsync();
await _updateBalance();
transactionHistory.updateAsync();
});
});
}
@@ -358,9 +392,9 @@ abstract class BitcoinWalletBase extends WalletBase<BitcoinBalance> with Store {
case TransactionPriority.slow:
return 6000;
case TransactionPriority.regular:
return 9000;
return 22080;
case TransactionPriority.fast:
return 15000;
return 24000;
default:
return 0;
}
@@ -1,21 +1,23 @@
import 'package:cake_wallet/core/wallet_credentials.dart';
import 'package:cake_wallet/entities/wallet_info.dart';
class BitcoinNewWalletCredentials extends WalletCredentials {
BitcoinNewWalletCredentials({String name}) : super(name: name);
BitcoinNewWalletCredentials({String name, WalletInfo walletInfo})
: super(name: name, walletInfo: walletInfo);
}
class BitcoinRestoreWalletFromSeedCredentials extends WalletCredentials {
BitcoinRestoreWalletFromSeedCredentials(
{String name, String password, this.mnemonic})
: super(name: name, password: password);
{String name, String password, this.mnemonic, WalletInfo walletInfo})
: super(name: name, password: password, walletInfo: walletInfo);
final String mnemonic;
}
class BitcoinRestoreWalletFromWIFCredentials extends WalletCredentials {
BitcoinRestoreWalletFromWIFCredentials(
{String name, String password, this.wif})
: super(name: name, password: password);
{String name, String password, this.wif, WalletInfo walletInfo})
: super(name: name, password: password, walletInfo: walletInfo);
final String wif;
}
+24 -5
View File
@@ -1,25 +1,34 @@
import 'dart:io';
import 'package:bip39/bip39.dart' as bip39;
import 'package:cake_wallet/bitcoin/bitcoin_mnemonic.dart';
import 'package:cake_wallet/bitcoin/bitcoin_mnemonic_is_incorrect_exception.dart';
import 'package:cake_wallet/bitcoin/file.dart';
import 'package:cake_wallet/bitcoin/bitcoin_wallet_creation_credentials.dart';
import 'package:cake_wallet/core/wallet_base.dart';
import 'package:cake_wallet/core/wallet_service.dart';
import 'package:cake_wallet/bitcoin/bitcoin_wallet.dart';
import 'package:cake_wallet/entities/pathForWallet.dart';
import 'package:cake_wallet/entities/wallet_info.dart';
import 'package:cake_wallet/entities/wallet_type.dart';
import 'package:hive/hive.dart';
class BitcoinWalletService extends WalletService<
BitcoinNewWalletCredentials,
BitcoinRestoreWalletFromSeedCredentials,
BitcoinRestoreWalletFromWIFCredentials> {
BitcoinWalletService(this.walletInfoSource);
final Box<WalletInfo> walletInfoSource;
@override
Future<BitcoinWallet> create(BitcoinNewWalletCredentials credentials) async {
final dirPath = await pathForWalletDir(
type: WalletType.bitcoin, name: credentials.name);
final wallet = BitcoinWalletBase.build(
dirPath: dirPath,
mnemonic: bip39.generateMnemonic(),
mnemonic: generateMnemonic(),
password: credentials.password,
name: credentials.name);
name: credentials.name,
walletInfo: credentials.walletInfo);
await wallet.save();
await wallet.init();
@@ -37,11 +46,15 @@ class BitcoinWalletService extends WalletService<
await pathForWalletDir(name: name, type: WalletType.bitcoin);
final walletPath = '$walletDirPath/$name';
final walletJSONRaw = await read(path: walletPath, password: password);
final walletInfo = walletInfoSource.values.firstWhere(
(info) => info.id == WalletBase.idFor(name, WalletType.bitcoin),
orElse: () => null);
final wallet = BitcoinWalletBase.fromJSON(
password: password,
name: name,
dirPath: walletDirPath,
jsonSource: walletJSONRaw);
jsonSource: walletJSONRaw,
walletInfo: walletInfo);
await wallet.init();
return wallet;
@@ -62,15 +75,21 @@ class BitcoinWalletService extends WalletService<
@override
Future<BitcoinWallet> restoreFromSeed(
BitcoinRestoreWalletFromSeedCredentials credentials) async {
if (!validateMnemonic(credentials.mnemonic)) {
throw BitcoinMnemonicIsIncorrectException();
}
final dirPath = await pathForWalletDir(
type: WalletType.bitcoin, name: credentials.name);
final wallet = BitcoinWalletBase.build(
dirPath: dirPath,
name: credentials.name,
password: credentials.password,
mnemonic: credentials.mnemonic);
mnemonic: credentials.mnemonic,
walletInfo: credentials.walletInfo);
await wallet.save();
await wallet.init();
await wallet.generateNewAddresses(32);
return wallet;
}
+86 -42
View File
@@ -22,8 +22,9 @@ String jsonrpcparams(List<Object> params) {
}
String jsonrpc(
{String method, List<Object> params, int id, double version = 2.0}) =>
'{"jsonrpc": "$version", "method": "$method", "id": "$id", "params": ${json.encode(params)}}\n';
{String method, List<Object> params, int id, double version = 2.0}) =>
'{"jsonrpc": "$version", "method": "$method", "id": "$id", "params": ${json
.encode(params)}}\n';
class SocketTask {
SocketTask({this.completer, this.isSubscription, this.subject});
@@ -49,6 +50,7 @@ class ElectrumClient {
final Map<String, SocketTask> _tasks;
bool _isConnected;
Timer _aliveTimer;
String unterminatedString;
Future<void> connectToUri(String uri) async {
final splittedUri = uri.split(':');
@@ -73,26 +75,31 @@ class ElectrumClient {
socket.listen((Uint8List event) {
try {
final jsoned =
json.decode(utf8.decode(event.toList())) as Map<String, Object>;
print(jsoned);
final method = jsoned['method'];
final id = jsoned['id'] as String;
final params = jsoned['result'];
_handleResponse(utf8.decode(event.toList()));
} on FormatException catch (e) {
final msg = e.message.toLowerCase();
if (method is String) {
_methodHandler(method: method, request: jsoned);
return;
if (msg == 'Unterminated string'.toLowerCase()) {
unterminatedString = e.source as String;
}
_finish(id, params);
if (msg == 'Unexpected character'.toLowerCase()) {
unterminatedString += e.source as String;
}
if (isJSONStringCorrect(unterminatedString)) {
_handleResponse(unterminatedString);
unterminatedString = null;
}
} catch (e) {
print(e);
}
}, onError: (Object error) {
print(error.toString());
_setIsConnected(false);
}, onDone: () => _setIsConnected(false));
}, onDone: () {
_setIsConnected(false);
});
keepAlive();
}
@@ -103,7 +110,7 @@ class ElectrumClient {
Future<void> ping() async {
try {
// await callWithTimeout(method: 'server.ping');
await callWithTimeout(method: 'server.ping');
_setIsConnected(true);
} on RequestFailedTimeoutException catch (_) {
_setIsConnected(false);
@@ -146,7 +153,7 @@ class ElectrumClient {
});
Future<List<Map<String, dynamic>>> getListUnspentWithAddress(
String address) =>
String address) =>
call(
method: 'blockchain.scripthash.listunspent',
params: [scriptHash(address)]).then((dynamic result) {
@@ -197,7 +204,7 @@ class ElectrumClient {
});
Future<Map<String, Object>> getTransactionRaw(
{@required String hash}) async =>
{@required String hash}) async =>
call(method: 'blockchain.transaction.get', params: [hash, true])
.then((dynamic result) {
if (result is Map<String, Object>) {
@@ -209,20 +216,24 @@ class ElectrumClient {
Future<Map<String, Object>> getTransactionExpanded(
{@required String hash}) async {
final originalTx = await getTransactionRaw(hash: hash);
final vins = originalTx['vin'] as List<Object>;
try {
final originalTx = await getTransactionRaw(hash: hash);
final vins = originalTx['vin'] as List<Object>;
for (dynamic vin in vins) {
if (vin is Map<String, Object>) {
vin['tx'] = await getTransactionRaw(hash: vin['txid'] as String);
for (dynamic vin in vins) {
if (vin is Map<String, Object>) {
vin['tx'] = await getTransactionRaw(hash: vin['txid'] as String);
}
}
}
return originalTx;
return originalTx;
} catch (_) {
return {};
}
}
Future<String> broadcastTransaction(
{@required String transactionRaw}) async =>
{@required String transactionRaw}) async =>
call(method: 'blockchain.transaction.broadcast', params: [transactionRaw])
.then((dynamic result) {
if (result is String) {
@@ -233,14 +244,14 @@ class ElectrumClient {
});
Future<Map<String, dynamic>> getMerkle(
{@required String hash, @required int height}) async =>
{@required String hash, @required int height}) async =>
await call(
method: 'blockchain.transaction.get_merkle',
params: [hash, height]) as Map<String, dynamic>;
Future<Map<String, dynamic>> getHeader({@required int height}) async =>
await call(method: 'blockchain.block.get_header', params: [height])
as Map<String, dynamic>;
as Map<String, dynamic>;
Future<double> estimatefee({@required int p}) =>
call(method: 'blockchain.estimatefee', params: [p])
@@ -256,16 +267,17 @@ class ElectrumClient {
return 0;
});
BehaviorSubject<Object> scripthashUpdate(String scripthash) =>
subscribe<Object>(
id: 'blockchain.scripthash.subscribe:$scripthash',
method: 'blockchain.scripthash.subscribe',
params: [scripthash]);
BehaviorSubject<Object> scripthashUpdate(String scripthash) {
_id += 1;
return subscribe<Object>(
id: 'blockchain.scripthash.subscribe:$scripthash',
method: 'blockchain.scripthash.subscribe',
params: [scripthash]);
}
BehaviorSubject<T> subscribe<T>(
{@required String id,
@required String method,
List<Object> params = const []}) {
BehaviorSubject<T> subscribe<T>({@required String id,
@required String method,
List<Object> params = const []}) {
final subscription = BehaviorSubject<T>();
_regisrySubscription(id, subscription);
socket.write(jsonrpc(method: method, id: _id, params: params));
@@ -273,7 +285,8 @@ class ElectrumClient {
return subscription;
}
Future<dynamic> call({String method, List<Object> params = const []}) {
Future<dynamic> call({String method, List<Object> params = const []}) async {
await Future<void>.delayed(Duration(milliseconds: 100));
final completer = Completer<dynamic>();
_id += 1;
final id = _id;
@@ -283,10 +296,9 @@ class ElectrumClient {
return completer.future;
}
Future<dynamic> callWithTimeout(
{String method,
List<Object> params = const [],
int timeout = 2000}) async {
Future<dynamic> callWithTimeout({String method,
List<Object> params = const [],
int timeout = 2000}) async {
final completer = Completer<dynamic>();
_id += 1;
final id = _id;
@@ -307,8 +319,15 @@ class ElectrumClient {
socket.write(jsonrpc(method: method, id: _id, params: params));
}
void _regisryTask(int id, Completer completer) => _tasks[id.toString()] =
SocketTask(completer: completer, isSubscription: false);
Future<void> close() async {
_aliveTimer.cancel();
await socket.close();
onConnectionStatusChange = null;
}
void _regisryTask(int id, Completer completer) =>
_tasks[id.toString()] =
SocketTask(completer: completer, isSubscription: false);
void _regisrySubscription(String id, BehaviorSubject subject) =>
_tasks[id] = SocketTask(subject: subject, isSubscription: true);
@@ -351,6 +370,31 @@ class ElectrumClient {
_isConnected = isConnected;
}
void _handleResponse(String response) {
print('Response: $response');
final jsoned = json.decode(response) as Map<String, Object>;
// print(jsoned);
final method = jsoned['method'];
final id = jsoned['id'] as String;
final result = jsoned['result'];
if (method is String) {
_methodHandler(method: method, request: jsoned);
return;
}
_finish(id, result);
}
}
// FIXME: move me
bool isJSONStringCorrect(String source) {
try {
json.decode(source);
return true;
} catch (_) {
return false;
}
}
class RequestFailedTimeoutException implements Exception {
@@ -16,6 +16,7 @@ class PendingBitcoinTransaction with PendingTransaction {
final int amount;
final int fee;
@override
String get id => _tx.getId();
@override
+1 -1
View File
@@ -60,7 +60,7 @@ class AddressValidator extends TextValidator {
case CryptoCurrency.bnb:
return [42];
case CryptoCurrency.btc:
return [33, 34, 42];
return [33, 34, 42, 62];
case CryptoCurrency.dai:
return [42];
case CryptoCurrency.dash:
+5 -1
View File
@@ -4,7 +4,11 @@ class InitialExecutionState extends ExecutionState {}
class IsExecutingState extends ExecutionState {}
class ExecutedSuccessfullyState extends ExecutionState {}
class ExecutedSuccessfullyState extends ExecutionState {
ExecutedSuccessfullyState({this.payload});
final dynamic payload;
}
class FailureState extends ExecutionState {
FailureState(this.error);
+1 -1
View File
@@ -7,7 +7,7 @@ class MoneroLabelValidator extends TextValidator {
MoneroLabelValidator({@required CryptoCurrency type})
: super(
errorMessage: S.current.error_text_account_name,
pattern: '^[a-zA-Z0-9_]{1,15}\$',
pattern: '^[a-zA-Z0-9_ ]{1,15}\$',
minLength: 1,
maxLength: 15);
}
+2 -2
View File
@@ -1,4 +1,4 @@
import 'package:bip39/src/wordlists/english.dart' as bitcoin_english;
import 'package:cake_wallet/bitcoin/bitcoin_mnemonic.dart' as bitcoin_electrum;
import 'package:cake_wallet/core/validator.dart';
import 'package:cake_wallet/entities/mnemonic_item.dart';
import 'package:cake_wallet/entities/wallet_type.dart';
@@ -64,7 +64,7 @@ class SeedValidator extends Validator<MnemonicItem> {
static List<String> getBitcoinWordList(String language) {
assert(language.toLowerCase() == LanguageList.english.toLowerCase());
return bitcoin_english.WORDLIST;
return bitcoin_electrum.englishWordlist;
}
@override
+2
View File
@@ -52,4 +52,6 @@ abstract class WalletBase<BalaceType> {
Future<void> save();
Future<void> rescan({int height});
void close();
}
+1 -1
View File
@@ -1,7 +1,7 @@
import 'package:cake_wallet/entities/wallet_info.dart';
abstract class WalletCredentials {
WalletCredentials({this.name, this.password, this.height});
WalletCredentials({this.name, this.password, this.height, this.walletInfo});
final String name;
final int height;
+26 -3
View File
@@ -16,11 +16,13 @@ import 'package:cake_wallet/src/screens/contact/contact_page.dart';
import 'package:cake_wallet/src/screens/exchange_trade/exchange_confirm_page.dart';
import 'package:cake_wallet/src/screens/exchange_trade/exchange_trade_page.dart';
import 'package:cake_wallet/src/screens/faq/faq_page.dart';
import 'package:cake_wallet/src/screens/new_wallet/new_wallet_type_page.dart';
import 'package:cake_wallet/src/screens/nodes/node_create_or_edit_page.dart';
import 'package:cake_wallet/src/screens/nodes/nodes_list_page.dart';
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
import 'package:cake_wallet/src/screens/rescan/rescan_page.dart';
import 'package:cake_wallet/src/screens/restore/wallet_restore_page.dart';
import 'package:cake_wallet/src/screens/seed/pre_seed_page.dart';
import 'package:cake_wallet/src/screens/seed/wallet_seed_page.dart';
import 'package:cake_wallet/src/screens/send/send_template_page.dart';
import 'package:cake_wallet/src/screens/settings/change_language.dart';
@@ -48,6 +50,7 @@ import 'package:cake_wallet/store/wallet_list_store.dart';
import 'package:cake_wallet/view_model/contact_list/contact_list_view_model.dart';
import 'package:cake_wallet/view_model/contact_list/contact_view_model.dart';
import 'package:cake_wallet/view_model/exchange/exchange_trade_view_model.dart';
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
import 'package:cake_wallet/view_model/node_list/node_list_view_model.dart';
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
import 'package:cake_wallet/view_model/rescan_view_model.dart';
@@ -273,7 +276,7 @@ Future setup(
getIt.registerFactory(() => MoneroAccountListPage(
accountListViewModel: getIt.get<MoneroAccountListViewModel>()));
getIt.registerFactory(() {
/*getIt.registerFactory(() {
final wallet = getIt.get<AppStore>().wallet;
if (wallet is MoneroWallet) {
@@ -286,7 +289,19 @@ Future setup(
getIt.registerFactory(() => MoneroAccountEditOrCreatePage(
moneroAccountCreationViewModel:
getIt.get<MoneroAccountEditOrCreateViewModel>()));
getIt.get<MoneroAccountEditOrCreateViewModel>()));*/
getIt.registerFactoryParam<MoneroAccountEditOrCreateViewModel,
AccountListItem, void>(
(AccountListItem account, _) => MoneroAccountEditOrCreateViewModel(
(getIt.get<AppStore>().wallet as MoneroWallet).accountList,
accountListItem: account));
getIt.registerFactoryParam<MoneroAccountEditOrCreatePage, AccountListItem,
void>(
(AccountListItem account, _) => MoneroAccountEditOrCreatePage(
moneroAccountCreationViewModel:
getIt.get<MoneroAccountEditOrCreateViewModel>(param1: account)));
getIt.registerFactory(() {
final appStore = getIt.get<AppStore>();
@@ -361,7 +376,7 @@ Future setup(
getIt.registerFactory(() => MoneroWalletService(walletInfoSource));
getIt.registerFactory(() => BitcoinWalletService());
getIt.registerFactory(() => BitcoinWalletService(walletInfoSource));
getIt.registerFactoryParam<WalletService, WalletType, void>(
(WalletType param1, __) {
@@ -405,4 +420,12 @@ Future setup(
transactionInfo,
getIt.get<SettingsStore>().shouldSaveRecipientAddress,
transactionDescriptionBox));
getIt.registerFactoryParam<NewWalletTypePage,
void Function(BuildContext, WalletType), bool>(
(para1, param2) => NewWalletTypePage(getIt.get<WalletNewVM>(),
onTypeSelected: para1, isNewWallet: param2));
getIt.registerFactoryParam<PreSeedPage, WalletType, void>(
(WalletType type, _) => PreSeedPage(type));
}
+7 -1
View File
@@ -1,3 +1,9 @@
import 'package:cake_wallet/entities/balance_display_mode.dart';
abstract class Balance {
const Balance();
const Balance(this.availableModes);
final List<BalanceDisplayMode> availableModes;
String formattedBalance(BalanceDisplayMode mode);
}
+1 -1
View File
@@ -45,7 +45,7 @@ Future defaultSettingsMigration(
FiatCurrency.usd.toString());
await sharedPreferences.setInt(
PreferencesKey.currentTransactionPriorityKey,
TransactionPriority.standart.raw);
TransactionPriority.standard.raw);
await sharedPreferences.setInt(
PreferencesKey.currentBalanceDisplayModeKey,
BalanceDisplayMode.availableBalance.raw);
+1 -1
View File
@@ -19,5 +19,5 @@ Future<void> loadCurrentWallet() async {
await getIt.get<KeyService>().getWalletPassword(walletName: name);
final _service = getIt.get<WalletService>(param1: type);
final wallet = await _service.openWallet(name, password);
appStore.wallet = wallet;
appStore.changeCurrentWallet(wallet);
}
+9 -2
View File
@@ -14,7 +14,8 @@ class Node extends HiveObject with Keyable {
{@required this.uri,
@required WalletType type,
this.login,
this.password}) {
this.password,
this.useSSL}) {
this.type = type;
}
@@ -22,7 +23,8 @@ class Node extends HiveObject with Keyable {
: uri = map['uri'] as String ?? '',
login = map['login'] as String,
password = map['password'] as String,
typeRaw = map['typeRaw'] as int;
typeRaw = map['typeRaw'] as int,
useSSL = map['useSSL'] as bool;
static const boxName = 'Nodes';
@@ -38,6 +40,11 @@ class Node extends HiveObject with Keyable {
@HiveField(3)
int typeRaw;
@HiveField(4)
bool useSSL;
bool get isSSL => useSSL ?? false;
@override
dynamic get keyIndex {
_keyIndex ??= key;
+3 -3
View File
@@ -39,9 +39,9 @@ Future<List<Node>> loadElectrumServerList() async {
Future resetToDefault(Box<Node> nodeSource) async {
final moneroNodes = await loadDefaultNodes();
// final bitcoinElectrumServerList = await loadElectrumServerList();
// final nodes = moneroNodes + bitcoinElectrumServerList;
final bitcoinElectrumServerList = await loadElectrumServerList();
final nodes = moneroNodes + bitcoinElectrumServerList;
await nodeSource.clear();
await nodeSource.addAll(moneroNodes);
await nodeSource.addAll(nodes);
}
+2 -1
View File
@@ -9,7 +9,8 @@ class PreferencesKey {
static const shouldSaveRecipientAddressKey = 'save_recipient_address';
static const allowBiometricalAuthenticationKey =
'allow_biometrical_authentication';
static const currentDarkTheme = 'dark_theme';
static const currentTheme = 'current_theme';
static const isDarkThemeLegacy = 'dark_theme';
static const displayActionListModeKey = 'display_list_mode';
static const currentPinLength = 'current_pin_length';
static const currentLanguageCode = 'language_code';
+2
View File
@@ -4,6 +4,7 @@ import 'package:cake_wallet/utils/mobx.dart';
abstract class TransactionInfo extends Object with Keyable {
String id;
int amount;
int fee;
TransactionDirection direction;
bool isPending;
DateTime date;
@@ -11,6 +12,7 @@ abstract class TransactionInfo extends Object with Keyable {
int confirmations;
String amountFormatted();
String fiatAmount();
String feeFormatted();
void changeFiatAmount(String amount);
@override
+18 -1
View File
@@ -1,3 +1,4 @@
import 'package:cake_wallet/entities/wallet_type.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/entities/enumerable_item.dart';
@@ -17,7 +18,23 @@ class TransactionPriority extends EnumerableItem<int> with Serializable<int> {
static const medium = TransactionPriority(title: 'Medium', raw: 2);
static const fast = TransactionPriority(title: 'Fast', raw: 3);
static const fastest = TransactionPriority(title: 'Fastest', raw: 4);
static const standart = slow;
static const standard = slow;
static List<TransactionPriority> forWalletType(WalletType type) {
switch (type) {
case WalletType.monero:
return TransactionPriority.all;
case WalletType.bitcoin:
return [
TransactionPriority.slow,
TransactionPriority.regular,
TransactionPriority.fast
];
default:
return [];
}
}
static TransactionPriority deserialize({int raw}) {
switch (raw) {
+11
View File
@@ -48,3 +48,14 @@ String walletTypeToString(WalletType type) {
return '';
}
}
String walletTypeToDisplayName(WalletType type) {
switch (type) {
case WalletType.monero:
return 'Monero';
case WalletType.bitcoin:
return 'Bitcoin (Electrum)';
default:
return '';
}
}
+2 -1
View File
@@ -14,7 +14,8 @@ class TradeIsCreatedSuccessfully extends ExchangeTradeState {
}
class TradeIsCreatedFailure extends ExchangeTradeState {
TradeIsCreatedFailure({@required this.error});
TradeIsCreatedFailure({@required this.title, @required this.error});
final String title;
final String error;
}
+28 -16
View File
@@ -12,6 +12,7 @@ import 'package:cake_wallet/exchange/xmrto/xmrto_trade_request.dart';
import 'package:cake_wallet/exchange/trade_not_created_exeption.dart';
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/exchange/trade_not_found_exeption.dart';
import 'package:cake_wallet/generated/i18n.dart';
class XMRTOExchangeProvider extends ExchangeProvider {
XMRTOExchangeProvider()
@@ -26,11 +27,14 @@ class XMRTOExchangeProvider extends ExchangeProvider {
static const _orderParameterUriSuffix = '/order_parameter_query';
static const _orderStatusUriSuffix = '/order_status_query/';
static const _orderCreateUriSuffix = '/order_create/';
static const _headers = {
'Content-Type': 'application/json',
'User-Agent': userAgent
};
static Future<bool> _checkIsAvailable() async {
const url = originalApiUri + _orderParameterUriSuffix;
final response =
await get(url, headers: {'Content-Type': 'application/json'});
final response = await get(url, headers: _headers);
return !(response.statusCode == 403);
}
@@ -90,16 +94,28 @@ class XMRTOExchangeProvider extends ExchangeProvider {
Future<Trade> createTrade({TradeRequest request}) async {
final _request = request as XMRTOTradeRequest;
final url = originalApiUri + _orderCreateUriSuffix;
final _amount =
_request.isBTCRequest ? _request.receiveAmount : _request.amount;
final _amountCurrency = _request.isBTCRequest
? _request.to.toString()
: _request.from.toString();
final pattern = '^([0-9]+([.\,][0-9]{0,8})?|[.\,][0-9]{1,8})\$';
final isValid = RegExp(pattern).hasMatch(_amount);
if (!isValid) {
throw TradeNotCreatedException(description,
description: S.current.xmr_to_error_description);
}
final body = {
'amount':
_request.isBTCRequest ? _request.receiveAmount : _request.amount,
'amount_currency': _request.isBTCRequest
? _request.to.toString()
: _request.from.toString(),
'amount': _amount,
'amount_currency': _amountCurrency,
'btc_dest_address': _request.address
};
final response = await post(url,
headers: {'Content-Type': 'application/json'}, body: json.encode(body));
final response =
await post(url, headers: _headers, body: json.encode(body));
if (response.statusCode != 201) {
if (response.statusCode == 400) {
@@ -127,13 +143,10 @@ class XMRTOExchangeProvider extends ExchangeProvider {
@override
Future<Trade> findTradeById({@required String id}) async {
const headers = {
'Content-Type': 'application/json',
'User-Agent': userAgent
};
final url = originalApiUri + _orderStatusUriSuffix;
final body = {'uuid': id};
final response = await post(url, headers: headers, body: json.encode(body));
final response =
await post(url, headers: _headers, body: json.encode(body));
if (response.statusCode != 200) {
if (response.statusCode == 400) {
@@ -196,8 +209,7 @@ class XMRTOExchangeProvider extends ExchangeProvider {
Future<double> _fetchRates() async {
try {
final url = originalApiUri + _orderParameterUriSuffix;
final response =
await get(url, headers: {'Content-Type': 'application/json'});
final response = await get(url, headers: _headers);
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
final price = double.parse(responseJSON['price'] as String);
+403 -35
View File
File diff suppressed because it is too large Load Diff
+13 -15
View File
@@ -1,3 +1,4 @@
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:hive/hive.dart';
@@ -83,7 +84,6 @@ void main() async {
)))));
}
}
Future<void> initialSetup(
{@required SharedPreferences sharedPreferences,
@required Box<Node> nodes,
@@ -123,27 +123,25 @@ class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
final settingsStore = getIt.get<AppStore>().settingsStore;
if (settingsStore.theme == null) {
settingsStore.isDarkTheme = false;
}
final statusBarColor = Colors.transparent;
final statusBarBrightness =
settingsStore.isDarkTheme ? Brightness.light : Brightness.dark;
final statusBarIconBrightness =
settingsStore.isDarkTheme ? Brightness.light : Brightness.dark;
final authenticationStore = getIt.get<AuthenticationStore>();
final initialRoute = authenticationStore.state == AuthenticationState.denied
? Routes.disclaimer
: Routes.login;
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor: statusBarColor,
statusBarBrightness: statusBarBrightness,
statusBarIconBrightness: statusBarIconBrightness));
return Observer(builder: (BuildContext context) {
final currentTheme = settingsStore.currentTheme;
final statusBarBrightness = currentTheme.type == ThemeType.dark
? Brightness.light
: Brightness.dark;
final statusBarIconBrightness = currentTheme.type == ThemeType.dark
? Brightness.light
: Brightness.dark;
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor: statusBarColor,
statusBarBrightness: statusBarBrightness,
statusBarIconBrightness: statusBarIconBrightness));
return Root(
authenticationStore: authenticationStore,
navigatorKey: navigatorKey,
+27 -5
View File
@@ -1,20 +1,42 @@
import 'package:cake_wallet/entities/balance.dart';
import 'package:cake_wallet/entities/balance_display_mode.dart';
import 'package:flutter/foundation.dart';
import 'package:cake_wallet/monero/monero_amount_format.dart';
class MoneroBalance {
class MoneroBalance extends Balance {
MoneroBalance({@required this.fullBalance, @required this.unlockedBalance})
: formattedFullBalance = moneroAmountToString(amount: fullBalance),
formattedUnlockedBalance =
moneroAmountToString(amount: unlockedBalance);
moneroAmountToString(amount: unlockedBalance),
super(const [
BalanceDisplayMode.availableBalance,
BalanceDisplayMode.fullBalance
]);
MoneroBalance.fromString(
{@required this.formattedFullBalance,
@required this.formattedUnlockedBalance})
@required this.formattedUnlockedBalance})
: fullBalance = moneroParseAmount(amount: formattedFullBalance),
unlockedBalance = moneroParseAmount(amount: formattedUnlockedBalance);
unlockedBalance = moneroParseAmount(amount: formattedUnlockedBalance),
super(const [
BalanceDisplayMode.availableBalance,
BalanceDisplayMode.fullBalance
]);
final int fullBalance;
final int unlockedBalance;
final String formattedFullBalance;
final String formattedUnlockedBalance;
}
@override
String formattedBalance(BalanceDisplayMode mode) {
switch (mode) {
case BalanceDisplayMode.fullBalance:
return formattedFullBalance;
case BalanceDisplayMode.availableBalance:
return formattedUnlockedBalance;
default:
return null;
}
}
}
+49 -34
View File
@@ -40,6 +40,10 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance> with Store {
fullBalance: monero_wallet.getFullBalance(accountIndex: 0),
unlockedBalance: monero_wallet.getFullBalance(accountIndex: 0));
_onAccountChangeReaction = reaction((_) => account, (Account account) {
balance = MoneroBalance(
fullBalance: monero_wallet.getFullBalance(accountIndex: account.id),
unlockedBalance:
monero_wallet.getUnlockedBalance(accountIndex: account.id));
subaddressList.update(accountIndex: account.id);
subaddress = subaddressList.subaddresses.first;
address = subaddress.address;
@@ -94,7 +98,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance> with Store {
bool _isSavingAfterNewTransaction;
Future<void> init() async {
await accountList.update();
accountList.update();
account = accountList.accounts.first;
subaddressList.update(accountIndex: account.id ?? 0);
subaddress = subaddressList.getAll().first;
@@ -116,6 +120,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance> with Store {
}
}
@override
void close() {
_listener?.stop();
_onAccountChangeReaction?.reaction?.dispose();
@@ -147,8 +152,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance> with Store {
address: node.uri,
login: node.login,
password: node.password,
useSSL: false,
// FIXME: hardcoded value
useSSL: node.isSSL,
isLightWallet: false); // FIXME: hardcoded value
syncStatus = ConnectedSyncStatus();
} catch (e) {
@@ -256,6 +260,7 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance> with Store {
monero_wallet.rescanBlockchainAsync();
await startSync();
_askForUpdateBalance();
accountList.update();
await _askForUpdateTransactionHistory();
await save();
await walletInfo.save();
@@ -311,9 +316,8 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance> with Store {
}
}
Future<void> _askForUpdateTransactionHistory() async {
await transactionHistory.update();
}
Future<void> _askForUpdateTransactionHistory() async =>
await transactionHistory.update();
int _getFullBalance() =>
monero_wallet.getFullBalance(accountIndex: account.id);
@@ -322,13 +326,13 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance> with Store {
monero_wallet.getUnlockedBalance(accountIndex: account.id);
Future<void> _afterSyncSave() async {
if (_isSavingAfterSync) {
return;
}
_isSavingAfterSync = true;
try {
if (_isSavingAfterSync) {
return;
}
_isSavingAfterSync = true;
final nowTimestamp = DateTime.now().millisecondsSinceEpoch;
final sum = _lastAutosaveTimestamp + _autoAfterSyncSaveInterval;
@@ -346,13 +350,13 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance> with Store {
}
Future<void> _afterNewTransactionSave() async {
if (_isSavingAfterNewTransaction) {
return;
}
_isSavingAfterNewTransaction = true;
try {
if (_isSavingAfterNewTransaction) {
return;
}
_isSavingAfterNewTransaction = true;
await save();
} catch (e) {
print(e.toString());
@@ -362,27 +366,38 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance> with Store {
}
void _onNewBlock(int height, int blocksLeft, double ptc) async {
if (walletInfo.isRecovery) {
_askForUpdateTransactionHistory();
_askForUpdateBalance();
}
if (blocksLeft < 100) {
_askForUpdateBalance();
syncStatus = SyncedSyncStatus();
await _afterSyncSave();
try {
if (walletInfo.isRecovery) {
setAsRecovered();
await _askForUpdateTransactionHistory();
_askForUpdateBalance();
accountList.update();
}
} else {
syncStatus = SyncingSyncStatus(blocksLeft, ptc);
if (blocksLeft < 100) {
await _askForUpdateTransactionHistory();
_askForUpdateBalance();
accountList.update();
syncStatus = SyncedSyncStatus();
await _afterSyncSave();
if (walletInfo.isRecovery) {
await setAsRecovered();
}
} else {
syncStatus = SyncingSyncStatus(blocksLeft, ptc);
}
} catch (e) {
print(e.toString());
}
}
void _onNewTransaction() {
_askForUpdateTransactionHistory();
_askForUpdateBalance();
Timer(Duration(seconds: 1), () => _afterNewTransactionSave());
try {
_askForUpdateTransactionHistory();
_askForUpdateBalance();
Timer(Duration(seconds: 1), () => _afterNewTransactionSave());
} catch (e) {
print(e.toString());
}
}
}
+11 -25
View File
@@ -4,7 +4,7 @@ class Palette {
static const Color green = Color.fromRGBO(39, 206, 80, 1.0);
static const Color red = Color.fromRGBO(255, 51, 51, 1.0);
static const Color darkRed = Color.fromRGBO(204, 38, 38, 1.0);
static const Color blueAlice = Color.fromRGBO(231, 240, 253, 1.0);
static const Color blueAlice = Color.fromRGBO(229, 247, 255, 1.0);
static const Color lightBlue = Color.fromRGBO(172, 203, 238, 1.0);
static const Color lavender = Color.fromRGBO(237, 245, 252, 1.0);
static const Color oceanBlue = Color.fromRGBO(30, 52, 78, 1.0);
@@ -13,7 +13,6 @@ class Palette {
static const Color blue = Color.fromRGBO(88, 143, 252, 1.0);
static const Color darkLavender = Color.fromRGBO(229, 238, 250, 1.0);
static const Color nightBlue = Color.fromRGBO(46, 57, 96, 1.0);
static const Color moderateOrangeYellow = Color.fromRGBO(245, 134, 82, 1.0);
static const Color moderateOrange = Color.fromRGBO(235, 117, 63, 1.0);
static const Color shineGreen = Color.fromRGBO(76, 189, 87, 1.0);
@@ -22,9 +21,8 @@ class Palette {
static const Color royalBlue = Color.fromRGBO(43, 114, 221, 1.0);
static const Color lightRed = Color.fromRGBO(227, 87, 87, 1.0);
static const Color persianRed = Color.fromRGBO(206, 55, 55, 1.0);
// NEW DESIGN
static const Color blueCraiola = Color.fromRGBO(69, 110, 255, 1.0);
static const Color blueGreyCraiola = Color.fromRGBO(106, 177, 207, 1.0);
static const Color darkBlueCraiola = Color.fromRGBO(53, 86, 136, 1.0);
static const Color pinkFlamingo = Color.fromRGBO(240, 60, 243, 1.0);
static const Color redHat = Color.fromRGBO(209, 68, 37, 1.0);
@@ -43,26 +41,17 @@ class Palette {
static const Color alizarinRed = Color.fromRGBO(233, 45, 45, 1.0);
static const Color moderateSlateBlue = Color.fromRGBO(129, 93, 251, 1.0);
static const Color brightOrange = Color.fromRGBO(255, 102, 0, 1.0);
// FIXME: Rename.
static const Color eee = Color.fromRGBO(236, 239, 245, 1.0);
static const Color xxx = Color.fromRGBO(72, 89, 109, 1);
static const Color dullGray = Color.fromRGBO(98, 98, 98, 1.0);
static const Color protectiveBlue = Color.fromRGBO(33, 148, 255, 1.0);
}
class PaletteDark {
//static const Color distantBlue = Color.fromRGBO(70, 85, 133, 1.0); // mainBackgroundColor
static const Color lightDistantBlue = Color.fromRGBO(81, 96, 147, 1.0); // borderCardColor
static const Color gray = Color.fromRGBO(140, 153, 201, 1.0); // walletCardText
//static const Color violetBlue = Color.fromRGBO(51, 63, 104, 1.0); // walletCardAddressField
//static const Color moderateBlue = Color.fromRGBO(63, 77, 122, 1.0); // walletCardSubAddressField
//static const Color darkNightBlue = Color.fromRGBO(33, 43, 73, 1.0); // historyPanel
static const Color pigeonBlue = Color.fromRGBO(91, 112, 146, 1.0); // historyPanelText
static const Color moderateNightBlue = Color.fromRGBO(39, 53, 96, 1.0); // historyPanelButton
static const Color headerNightBlue = Color.fromRGBO(41, 52, 84, 1.0); // menuHeader
//static const Color lightNightBlue = Color.fromRGBO(48, 59, 95, 1.0); // menuList
static const Color moderatePurpleBlue = Color.fromRGBO(57, 74, 95, 1.0); // selectButtonText
// NEW DESIGN
static const Color lightDistantBlue = Color.fromRGBO(81, 96, 147, 1.0);
static const Color gray = Color.fromRGBO(140, 153, 201, 1.0);
static const Color pigeonBlue = Color.fromRGBO(91, 112, 146, 1.0);
static const Color moderateNightBlue = Color.fromRGBO(39, 53, 96, 1.0);
static const Color headerNightBlue = Color.fromRGBO(41, 52, 84, 1.0);
static const Color moderatePurpleBlue = Color.fromRGBO(57, 74, 95, 1.0);
static const Color backgroundColor = Color.fromRGBO(25, 35, 60, 1.0);
static const Color nightBlue = Color.fromRGBO(35, 47, 79, 1.0);
static const Color wildNightBlue = Color.fromRGBO(39, 53, 96, 1.0);
@@ -94,8 +83,5 @@ class PaletteDark {
static const Color deepVioletBlue = Color.fromRGBO(52, 66, 104, 1.0);
static const Color lightPurpleBlue = Color.fromRGBO(120, 133, 170, 1.0);
static const Color indicatorVioletBlue = Color.fromRGBO(59, 72, 119, 1.0);
// FIXME: Rename.
static const Color eee = Color.fromRGBO(236, 239, 245, 1.0);
static const Color xxx = Color.fromRGBO(72, 89, 109, 1);
static const Color granite = Color.fromRGBO(48, 51, 60, 1.0);
}
+4 -3
View File
@@ -12,12 +12,13 @@ Future<void> startFiatRateUpdate(AppStore appStore, SettingsStore settingsStore,
return;
}
fiatConversionStore.price = await FiatConversionService.fetchPrice(
appStore.wallet.currency, settingsStore.fiatCurrency);
fiatConversionStore.prices[appStore.wallet.currency] =
await FiatConversionService.fetchPrice(
appStore.wallet.currency, settingsStore.fiatCurrency);
_timer = Timer.periodic(
Duration(seconds: 30),
(_) async => fiatConversionStore.price =
(_) async => fiatConversionStore.prices[appStore.wallet.currency] =
await FiatConversionService.fetchPrice(
appStore.wallet.currency, settingsStore.fiatCurrency));
}
+6 -5
View File
@@ -7,12 +7,13 @@ import 'package:cake_wallet/entities/fiat_currency.dart';
ReactionDisposer _onCurrentFiatCurrencyChangeDisposer;
void startCurrentFiatChangeReaction(AppStore appStore, SettingsStore settingsStore, FiatConversionStore fiatConversionStore) {
void startCurrentFiatChangeReaction(AppStore appStore,
SettingsStore settingsStore, FiatConversionStore fiatConversionStore) {
_onCurrentFiatCurrencyChangeDisposer?.reaction?.dispose();
_onCurrentFiatCurrencyChangeDisposer = reaction(
(_) => settingsStore.fiatCurrency, (FiatCurrency fiatCurrency) async {
(_) => settingsStore.fiatCurrency, (FiatCurrency fiatCurrency) async {
final cryptoCurrency = appStore.wallet.currency;
fiatConversionStore.price = await FiatConversionService.fetchPrice(
cryptoCurrency, fiatCurrency);
fiatConversionStore.prices[appStore.wallet.currency] =
await FiatConversionService.fetchPrice(cryptoCurrency, fiatCurrency);
});
}
}
+2 -3
View File
@@ -6,10 +6,9 @@ ReactionDisposer _onCurrentNodeChangeReaction;
void startOnCurrentNodeChangeReaction(AppStore appStore) {
_onCurrentNodeChangeReaction?.reaction?.dispose();
_onCurrentNodeChangeReaction =
reaction((_) => appStore.settingsStore.currentNode, (Node node) async {
appStore.settingsStore.nodes.observe((change) async {
try {
await appStore.wallet.connectToNode(node: node);
await appStore.wallet.connectToNode(node: change.newValue);
} catch (e) {
print(e.toString());
}
+10 -1
View File
@@ -12,6 +12,7 @@ import 'package:cake_wallet/core/wallet_base.dart';
import 'package:cake_wallet/entities/wallet_type.dart';
ReactionDisposer _onCurrentWalletChangeReaction;
ReactionDisposer _onCurrentWalletChangeFiatRateUpdateReaction;
void startCurrentWalletChangeReaction(AppStore appStore,
SettingsStore settingsStore, FiatConversionStore fiatConversionStore) {
@@ -29,8 +30,16 @@ void startCurrentWalletChangeReaction(AppStore appStore,
await getIt.get<SharedPreferences>().setInt(
PreferencesKey.currentWalletType, serializeToInt(wallet.type));
await wallet.connectToNode(node: node);
} catch (e) {
print(e.toString());
}
});
fiatConversionStore.price = await FiatConversionService.fetchPrice(
_onCurrentWalletChangeFiatRateUpdateReaction =
reaction((_) => appStore.wallet, (WalletBase wallet) async {
try {
fiatConversionStore.prices[wallet.currency] = 0;
fiatConversionStore.prices[wallet.currency] = await FiatConversionService.fetchPrice(
wallet.currency, settingsStore.fiatCurrency);
} catch (e) {
print(e.toString());
+29 -35
View File
@@ -2,7 +2,9 @@ import 'package:cake_wallet/entities/contact_record.dart';
import 'package:cake_wallet/entities/transaction_description.dart';
import 'package:cake_wallet/src/screens/pin_code/pin_code_widget.dart';
import 'package:cake_wallet/src/screens/restore/wallet_restore_page.dart';
import 'package:cake_wallet/src/screens/seed/pre_seed_page.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/view_model/monero_account_list/account_list_item.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/routes.dart';
@@ -60,32 +62,22 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.newWalletFromWelcome:
return CupertinoPageRoute<void>(
builder: (_) => getIt.get<SetupPinCodePage>(param1:
(PinCodeState<PinCodeWidget> context, dynamic _) async {
try {
context.changeProcessText(
'Creating new wallet'); // FIXME: Unnamed constant
final newWalletVM =
getIt.get<WalletNewVM>(param1: WalletType.monero);
await newWalletVM.create(
options: 'English'); // FIXME: Unnamed constant
context.hideProgressText();
await Navigator.of(context.context)
.pushNamed(Routes.seed, arguments: true);
} catch (e) {
context.changeProcessText('Error: ${e.toString()}');
}
}),
builder: (_) => getIt.get<SetupPinCodePage>(
param1: (PinCodeState<PinCodeWidget> context, dynamic _) =>
Navigator.of(context.context)
.pushNamed(Routes.newWalletType)),
fullscreenDialog: true);
case Routes.newWalletType:
return CupertinoPageRoute<void>(
builder: (_) => NewWalletTypePage(
onTypeSelected: (context, type) => Navigator.of(context)
.pushNamed(Routes.newWallet, arguments: type)));
builder: (_) => getIt.get<NewWalletTypePage>(
param1: (BuildContext context, WalletType type) =>
Navigator.of(context)
.pushNamed(Routes.preSeed, arguments: type),
param2: true));
case Routes.newWallet:
final type = WalletType.monero; // settings.arguments as WalletType;
final type = settings.arguments as WalletType;
final walletNewVM = getIt.get<WalletNewVM>(param1: type);
return CupertinoPageRoute<void>(
@@ -104,11 +96,11 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.restoreWalletType:
return CupertinoPageRoute<void>(
builder: (_) => NewWalletTypePage(
onTypeSelected: (context, type) => Navigator.of(context)
.pushNamed(Routes.restoreWalletOptions, arguments: type),
isNewWallet: false,
));
builder: (_) => getIt.get<NewWalletTypePage>(
param1: (BuildContext context, WalletType type) =>
Navigator.of(context)
.pushNamed(Routes.restoreWallet, arguments: type),
param2: false));
case Routes.restoreOptions:
final type = settings.arguments as WalletType;
@@ -146,7 +138,8 @@ Route<dynamic> createRoute(RouteSettings settings) {
return CupertinoPageRoute<void>(
builder: (_) => getIt.get<SetupPinCodePage>(
param1: (PinCodeState<PinCodeWidget> context, dynamic _) =>
Navigator.pushNamed(context.context, Routes.restoreWallet)),
Navigator.pushNamed(
context.context, Routes.restoreWalletType)),
fullscreenDialog: true);
case Routes.seed:
@@ -156,16 +149,11 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.restoreWallet:
return MaterialPageRoute<void>(
builder: (_) =>
getIt.get<WalletRestorePage>(param1: WalletType.monero));
builder: (_) => getIt.get<WalletRestorePage>(
param1: settings.arguments as WalletType));
case Routes.restoreWalletFromSeed:
// final args = settings.arguments as List<dynamic>;
final type = WalletType.monero; //args.first as WalletType;
// final language = type == WalletType.monero
// ? args[1] as String
// : LanguageList.english;
final type = settings.arguments as WalletType;
return CupertinoPageRoute<void>(
builder: (_) => RestoreWalletFromSeedPage(type: type));
@@ -261,7 +249,8 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.accountCreation:
return CupertinoPageRoute<String>(
builder: (_) => getIt.get<MoneroAccountEditOrCreatePage>());
builder: (_) => getIt.get<MoneroAccountEditOrCreatePage>(
param1: settings.arguments as AccountListItem));
case Routes.addressBook:
return MaterialPageRoute<void>(
@@ -322,6 +311,11 @@ Route<dynamic> createRoute(RouteSettings settings) {
return MaterialPageRoute<void>(
builder: (_) => getIt.get<LanguageListPage>());
case Routes.preSeed:
return MaterialPageRoute<void>(
builder: (_) =>
getIt.get<PreSeedPage>(param1: settings.arguments as WalletType));
default:
return MaterialPageRoute<void>(
builder: (_) => Scaffold(
+1
View File
@@ -47,4 +47,5 @@ class Routes {
static const exchangeTemplate = '/exchange_template';
static const restoreWalletType = '/restore_wallet_type';
static const restoreWallet = '/restore_wallet';
static const preSeed = '/pre_seed';
}
+16 -13
View File
@@ -1,3 +1,4 @@
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/palette.dart';
@@ -9,13 +10,13 @@ enum AppBarStyle { regular, withShadow, transparent }
abstract class BasePage extends StatelessWidget {
BasePage()
: _scaffoldKey = GlobalKey<ScaffoldState>(),
_closeButtonImage = Image.asset('assets/images/close_button.png'),
_closeButtonImageDarkTheme =
Image.asset('assets/images/close_button_dark_theme.png');
: _scaffoldKey = GlobalKey<ScaffoldState>();
final GlobalKey<ScaffoldState> _scaffoldKey;
final Image _closeButtonImage;
final Image _closeButtonImageDarkTheme;
final Image closeButtonImage =
Image.asset('assets/images/close_button.png');
final Image closeButtonImageDarkTheme =
Image.asset('assets/images/close_button_dark_theme.png');
String get title => null;
@@ -37,7 +38,7 @@ abstract class BasePage extends StatelessWidget {
Widget Function(BuildContext, Widget) get rootWrapper => null;
bool get isDarkTheme => getIt.get<SettingsStore>().isDarkTheme;
ThemeBase get currentTheme => getIt.get<SettingsStore>().currentTheme;
void onOpenEndDrawer() => _scaffoldKey.currentState.openEndDrawer();
@@ -51,8 +52,8 @@ abstract class BasePage extends StatelessWidget {
final _backButton = Icon(Icons.arrow_back_ios,
color: titleColor ?? Theme.of(context).primaryTextTheme.title.color,
size: 16,);
final _closeButton =
isDarkTheme ? _closeButtonImageDarkTheme : _closeButtonImage;
final _closeButton = currentTheme.type == ThemeType.dark
? closeButtonImageDarkTheme : closeButtonImage;
return SizedBox(
height: 37,
@@ -88,8 +89,8 @@ abstract class BasePage extends StatelessWidget {
Widget floatingActionButton(BuildContext context) => null;
ObstructingPreferredSizeWidget appBar(BuildContext context) {
final appBarColor =
isDarkTheme ? backgroundDarkColor : backgroundLightColor;
final appBarColor = currentTheme.type == ThemeType.dark
? backgroundDarkColor : backgroundLightColor;
switch (appBarStyle) {
case AppBarStyle.regular:
@@ -131,10 +132,12 @@ abstract class BasePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final _backgroundColor = currentTheme.type == ThemeType.dark
? backgroundDarkColor : backgroundLightColor;
final root = Scaffold(
key: _scaffoldKey,
backgroundColor:
isDarkTheme ? backgroundDarkColor : backgroundLightColor,
backgroundColor: _backgroundColor,
resizeToAvoidBottomPadding: resizeToAvoidBottomPadding,
extendBodyBehindAppBar: extendBodyBehindAppBar,
endDrawer: endDrawer,
+16 -9
View File
@@ -1,5 +1,6 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
@@ -20,7 +21,8 @@ class DashboardPage extends BasePage {
});
@override
Color get backgroundLightColor => Colors.transparent;
Color get backgroundLightColor => currentTheme.type == ThemeType.bright
? Colors.transparent : Colors.white;
@override
Color get backgroundDarkColor => Colors.transparent;
@@ -50,7 +52,8 @@ class DashboardPage extends BasePage {
@override
Widget trailing(BuildContext context) {
final menuButton =
Image.asset('assets/images/menu.png', color: Colors.white);
Image.asset('assets/images/menu.png',
color: Theme.of(context).accentTextTheme.display3.backgroundColor);
return Container(
alignment: Alignment.centerRight,
@@ -65,12 +68,6 @@ class DashboardPage extends BasePage {
final DashboardViewModel walletViewModel;
final WalletAddressListViewModel addressListViewModel;
final sendImage = Image.asset('assets/images/upload.png',
height: 22.24, width: 24, color: Colors.white);
final exchangeImage = Image.asset('assets/images/transfer.png',
height: 24.27, width: 22.25, color: Colors.white);
final receiveImage = Image.asset('assets/images/download.png',
height: 22.24, width: 24, color: Colors.white);
final controller = PageController(initialPage: 1);
var pages = <Widget>[];
@@ -78,6 +75,15 @@ class DashboardPage extends BasePage {
@override
Widget body(BuildContext context) {
final sendImage = Image.asset('assets/images/upload.png',
height: 22.24, width: 24,
color: Theme.of(context).accentTextTheme.display3.backgroundColor);
final exchangeImage = Image.asset('assets/images/transfer.png',
height: 24.27, width: 22.25,
color: Theme.of(context).accentTextTheme.display3.backgroundColor);
final receiveImage = Image.asset('assets/images/download.png',
height: 22.24, width: 24,
color: Theme.of(context).accentTextTheme.display3.backgroundColor);
_setEffects();
return SafeArea(
@@ -100,7 +106,8 @@ class DashboardPage extends BasePage {
dotWidth: 6.0,
dotHeight: 6.0,
dotColor: Theme.of(context).indicatorColor,
activeDotColor: Colors.white),
activeDotColor: Theme.of(context).accentTextTheme.display1
.backgroundColor),
)),
Container(
padding: EdgeInsets.only(left: 45, right: 45, bottom: 24),
+42 -33
View File
@@ -9,44 +9,53 @@ import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
// FIXME: terrible design
class WalletMenu {
WalletMenu(this.context, this.reconnect);
final List<WalletMenuItem> items = [
WalletMenuItem(
title: S.current.reconnect,
image: Image.asset('assets/images/reconnect_menu.png',
height: 16, width: 16)),
WalletMenuItem(
title: S.current.rescan,
image: Image.asset('assets/images/filter_icon.png',
height: 16, width: 16)),
WalletMenuItem(
title: S.current.wallets,
image: Image.asset('assets/images/wallet_menu.png',
height: 16, width: 16)),
WalletMenuItem(
title: S.current.nodes,
image:
Image.asset('assets/images/nodes_menu.png', height: 16, width: 16)),
WalletMenuItem(
title: S.current.show_keys,
image:
Image.asset('assets/images/key_menu.png', height: 16, width: 16)),
WalletMenuItem(
title: S.current.address_book_menu,
image: Image.asset('assets/images/open_book_menu.png',
height: 16, width: 16)),
WalletMenuItem(
title: S.current.settings_title,
image: Image.asset('assets/images/settings_menu.png',
height: 16, width: 16)),
];
WalletMenu(this.context, this.reconnect, this.hasRescan) : items = [] {
items.addAll([
WalletMenuItem(
title: S.current.reconnect,
image: Image.asset('assets/images/reconnect_menu.png',
height: 16, width: 16)),
if (hasRescan)
WalletMenuItem(
title: S.current.rescan,
image: Image.asset('assets/images/filter_icon.png',
height: 16, width: 16)),
WalletMenuItem(
title: S.current.wallets,
image: Image.asset('assets/images/wallet_menu.png',
height: 16, width: 16)),
WalletMenuItem(
title: S.current.nodes,
image: Image.asset('assets/images/nodes_menu.png',
height: 16, width: 16)),
WalletMenuItem(
title: S.current.show_keys,
image:
Image.asset('assets/images/key_menu.png', height: 16, width: 16)),
WalletMenuItem(
title: S.current.address_book_menu,
image: Image.asset('assets/images/open_book_menu.png',
height: 16, width: 16)),
WalletMenuItem(
title: S.current.settings_title,
image: Image.asset('assets/images/settings_menu.png',
height: 16, width: 16)),
]);
}
final List<WalletMenuItem> items;
final BuildContext context;
final Future<void> Function() reconnect;
final bool hasRescan;
void action(int index) {
switch (index) {
var indx = index;
if (index > 0 && !hasRescan) {
indx += 1;
}
switch (indx) {
case 0:
_presentReconnectAlert(context);
break;
@@ -39,7 +39,10 @@ class ActionButton extends StatelessWidget {
SizedBox(height: 15),
Text(
title,
style: TextStyle(fontSize: 14, color: Colors.white),
style: TextStyle(
fontSize: 14,
color: Theme.of(context).accentTextTheme.display3
.backgroundColor),
)
],
),
@@ -3,6 +3,7 @@ import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_v
import 'package:cake_wallet/src/screens/receive/widgets/qr_widget.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
class AddressPage extends StatelessWidget {
AddressPage({@required this.addressListViewModel});
@@ -16,10 +17,9 @@ class AddressPage extends StatelessWidget {
child: Column(
children: <Widget>[
Expanded(
child: Center(
child: QRWidget(addressListViewModel: addressListViewModel),
)
),
child: Center(
child: QRWidget(addressListViewModel: addressListViewModel),
)),
GestureDetector(
onTap: () => Navigator.of(context).pushNamed(Routes.receive),
child: Container(
@@ -27,29 +27,35 @@ class AddressPage extends StatelessWidget {
padding: EdgeInsets.only(left: 24, right: 12),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(25)),
border: Border.all(
color: Theme.of(context).textTheme.subhead.color,
width: 1
),
color: Theme.of(context).buttonColor
),
borderRadius: BorderRadius.all(Radius.circular(25)),
border: Border.all(
color: Theme.of(context).textTheme.subhead.color,
width: 1),
color: Theme.of(context).buttonColor),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
S.of(context).addresses,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Colors.white
),
),
Observer(
builder: (_) => Text(
addressListViewModel.hasAccounts
? S.of(context).accounts_subaddresses
: S.of(context).addresses,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w500,
color: Theme.of(context)
.accentTextTheme
.display3
.backgroundColor),
)),
Icon(
Icons.arrow_forward_ios,
size: 14,
color: Colors.white,
color: Theme.of(context)
.accentTextTheme
.display3
.backgroundColor,
)
],
),
@@ -59,4 +65,4 @@ class AddressPage extends StatelessWidget {
),
);
}
}
}
@@ -10,59 +10,77 @@ class BalancePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(24),
child: GestureDetector(
onTapUp: (_) => dashboardViewModel.balanceViewModel.isReversing = false,
onTapDown: (_) => dashboardViewModel.balanceViewModel.isReversing = true,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Observer(builder: (_) {
return Text(
dashboardViewModel.balanceViewModel.currency.toString(),
style: TextStyle(
fontSize: 40,
fontWeight: FontWeight.bold,
color: Theme.of(context).indicatorColor,
height: 1),
);
}),
Observer(builder: (_) {
return Text(
dashboardViewModel.balanceViewModel.displayMode.toString(),
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Theme.of(context).indicatorColor,
height: 1),
);
}),
SizedBox(height: 10),
Observer(builder: (_) {
return AutoSizeText(dashboardViewModel.balanceViewModel.cryptoBalance,
return GestureDetector(
onTapUp: (_) {
if (dashboardViewModel.balanceViewModel.canReverse) {
dashboardViewModel.balanceViewModel.isReversing = false;
}
},
onTapDown: (_) {
if (dashboardViewModel.balanceViewModel.canReverse) {
dashboardViewModel.balanceViewModel.isReversing = true;
}
},
child: Container(
color: Colors.transparent,
padding: EdgeInsets.all(24),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Observer(builder: (_) {
return Text(
dashboardViewModel.balanceViewModel.currency.toString(),
style: TextStyle(
fontSize: 40,
fontWeight: FontWeight.bold,
color: Theme.of(context)
.accentTextTheme
.display2
.backgroundColor,
height: 1),
);
}),
Observer(builder: (_) {
return Text(
dashboardViewModel.balanceViewModel.displayMode.toString(),
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.accentTextTheme
.display2
.backgroundColor,
height: 1),
);
}),
SizedBox(height: 10),
Observer(builder: (_) {
return AutoSizeText(
dashboardViewModel.balanceViewModel.cryptoBalance,
style: TextStyle(
fontSize: 54,
fontWeight: FontWeight.bold,
color: Colors.white,
color: Theme.of(context)
.accentTextTheme
.display3
.backgroundColor,
height: 1),
maxLines: 1,
textAlign: TextAlign.center);
}),
SizedBox(height: 10),
Observer(builder: (_) {
return Text(dashboardViewModel.balanceViewModel.fiatBalance,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
color: Theme.of(context).indicatorColor,
height: 1),
textAlign: TextAlign.center);
}),
],
),
)
);
maxLines: 1,
textAlign: TextAlign.center);
}),
SizedBox(height: 10),
Observer(builder: (_) {
return Text(dashboardViewModel.balanceViewModel.fiatBalance,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
color: Theme.of(context).indicatorColor,
height: 1),
textAlign: TextAlign.center);
}),
],
),
));
}
}
@@ -27,14 +27,15 @@ class HeaderRow extends StatelessWidget {
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
color: Colors.white
color: Theme.of(context).accentTextTheme.display3.backgroundColor
),
),
GestureDetector(
onTap: () {
showPopUp<void>(
context: context,
builder: (context) => FilterWidget(dashboardViewModel: dashboardViewModel)
builder: (context) =>
FilterWidget(dashboardViewModel: dashboardViewModel)
);
},
child: Container(
@@ -5,6 +5,7 @@ import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/entities/wallet_type.dart';
import 'package:cake_wallet/src/screens/dashboard/wallet_menu.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
// FIXME: terrible design.
@@ -65,8 +66,10 @@ class MenuWidgetState extends State<MenuWidget> {
@override
Widget build(BuildContext context) {
final walletMenu =
WalletMenu(context, () async => widget.dashboardViewModel.reconnect());
final walletMenu = WalletMenu(
context,
() async => widget.dashboardViewModel.reconnect(),
widget.dashboardViewModel.hasRescan);
final itemCount = walletMenu.items.length;
moneroIcon = Image.asset('assets/images/monero_menu.png',
@@ -147,16 +150,19 @@ class MenuWidgetState extends State<MenuWidget> {
),
if (widget.dashboardViewModel.subname !=
null)
Text(
widget.dashboardViewModel.subname,
style: TextStyle(
color: Theme.of(context)
.accentTextTheme
.overline
.decorationColor,
fontWeight: FontWeight.w500,
fontSize: 12),
)
Observer(
builder: (_) => Text(
widget.dashboardViewModel
.subname,
style: TextStyle(
color: Theme.of(context)
.accentTextTheme
.overline
.decorationColor,
fontWeight:
FontWeight.w500,
fontSize: 12),
))
],
),
))
@@ -25,54 +25,53 @@ class TradeRow extends StatelessWidget {
return InkWell(
onTap: onTap,
child: Container(
height: 52,
padding: EdgeInsets.fromLTRB(24, 8, 24, 8),
color: Colors.transparent,
padding: EdgeInsets.only(left: 24, right: 24),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
_getPoweredImage(provider),
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 12),
child: Container(
height: 46,
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
_getPoweredImage(provider),
SizedBox(width: 12),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text('${from.toString()} → ${to.toString()}',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.white
)),
formattedAmount != null
? Text(formattedAmount + ' ' + amountCrypto,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.white
))
: Container()
]),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(createdAtFormattedDate,
style: TextStyle(
fontSize: 14,
color: Theme.of(context).textTheme
.overline.backgroundColor))
]),
],
),
),
))
]),
Text('${from.toString()} → ${to.toString()}',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).accentTextTheme.
display3.backgroundColor
)),
formattedAmount != null
? Text(formattedAmount + ' ' + amountCrypto,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).accentTextTheme.
display3.backgroundColor
))
: Container()
]),
SizedBox(height: 5),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(createdAtFormattedDate,
style: TextStyle(
fontSize: 14,
color: Theme.of(context).textTheme
.overline.backgroundColor))
])
],
)
)
],
),
));
}
@@ -23,73 +23,73 @@ class TransactionRow extends StatelessWidget {
return InkWell(
onTap: onTap,
child: Container(
height: 62,
padding: EdgeInsets.fromLTRB(24, 8, 24, 8),
color: Colors.transparent,
padding: EdgeInsets.only(left: 24, right: 24),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
height: 36,
width: 36,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Theme.of(context).textTheme.overline.decorationColor
),
child: Image.asset(
direction == TransactionDirection.incoming
? 'assets/images/down_arrow.png'
: 'assets/images/up_arrow.png'),
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
height: 36,
width: 36,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Theme.of(context).textTheme.overline.decorationColor
),
Expanded(
child: Container(
padding: const EdgeInsets.only(left: 12),
height: 56,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
(direction == TransactionDirection.incoming
? S.of(context).received
: S.of(context).sent) +
(isPending ? S.of(context).pending : ''),
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.white)),
Text(formattedAmount,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.white))
]),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(formattedDate,
style: TextStyle(
fontSize: 14,
color: Theme.of(context)
.textTheme
.overline
.backgroundColor)),
Text(formattedFiatAmount,
style: TextStyle(
fontSize: 14,
color: Theme.of(context)
.textTheme
.overline
.backgroundColor))
]),
],
),
),
)
]),
child: Image.asset(
direction == TransactionDirection.incoming
? 'assets/images/down_arrow.png'
: 'assets/images/up_arrow.png'),
),
SizedBox(width: 12),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
(direction == TransactionDirection.incoming
? S.of(context).received
: S.of(context).sent) +
(isPending ? S.of(context).pending : ''),
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).accentTextTheme.
display3.backgroundColor)),
Text(formattedAmount,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Theme.of(context).accentTextTheme.
display3.backgroundColor))
]),
SizedBox(height: 5),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(formattedDate,
style: TextStyle(
fontSize: 14,
color: Theme.of(context)
.textTheme
.overline
.backgroundColor)),
Text(formattedFiatAmount,
style: TextStyle(
fontSize: 14,
color: Theme.of(context)
.textTheme
.overline
.backgroundColor))
])
],
)
)
],
),
));
}
}
@@ -46,7 +46,8 @@ class TransactionsPage extends StatelessWidget {
if (item is TransactionListItem) {
final transaction = item.transaction;
return TransactionRow(
return Observer(
builder: (_) => TransactionRow(
onTap: () => Navigator.of(context).pushNamed(
Routes.transactionDetails,
arguments: transaction),
@@ -55,7 +56,7 @@ class TransactionsPage extends StatelessWidget {
.format(transaction.date),
formattedAmount: item.formattedCryptoAmount,
formattedFiatAmount: item.formattedFiatAmount,
isPending: transaction.isPending);
isPending: transaction.isPending));
}
if (item is TradeListItem) {
+4 -4
View File
@@ -95,9 +95,8 @@ class ExchangePage extends BasePage {
return KeyboardActions(
config: KeyboardActionsConfig(
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
keyboardBarColor: isDarkTheme
? Color.fromRGBO(48, 51, 60, 1.0)
: Color.fromRGBO(98, 98, 98, 1.0),
keyboardBarColor: Theme.of(context).accentTextTheme.body2
.backgroundColor,
nextFocus: false,
actions: [
KeyboardActionsItem(
@@ -547,7 +546,7 @@ class ExchangePage extends BasePage {
context: context,
builder: (BuildContext context) {
return AlertWithOneAction(
alertTitle: S.of(context).error,
alertTitle: S.of(context).provider_error(state.title),
alertContent: state.error,
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop());
@@ -555,6 +554,7 @@ class ExchangePage extends BasePage {
});
}
if (state is TradeIsCreatedSuccessfully) {
exchangeViewModel.reset();
Navigator.of(context).pushNamed(Routes.exchangeConfirm);
}
});
@@ -166,8 +166,8 @@ class ExchangeCardState extends State<ExchangeCard> {
fontSize: 16,
fontWeight: FontWeight.w600,
color: Theme.of(context)
.textTheme
.subhead
.accentTextTheme
.display4
.decorationColor),
validator: _isAmountEditable
? widget.currencyValueValidator
@@ -211,8 +211,8 @@ class ExchangeCardState extends State<ExchangeCard> {
fontSize: 10,
height: 1.2,
color: Theme.of(context)
.textTheme
.subhead
.accentTextTheme
.display4
.decorationColor),
)
: Offstage(),
@@ -224,8 +224,8 @@ class ExchangeCardState extends State<ExchangeCard> {
fontSize: 10,
height: 1.2,
color: Theme.of(context)
.textTheme
.subhead
.accentTextTheme
.display4
.decorationColor))
: Offstage(),
]),
@@ -239,7 +239,10 @@ class ExchangeCardState extends State<ExchangeCard> {
fontSize: 14,
fontWeight: FontWeight.w500,
color:
Theme.of(context).textTheme.subhead.decorationColor),
Theme.of(context)
.accentTextTheme
.display4
.decorationColor),
))
: Offstage(),
_isAddressEditable
@@ -263,7 +266,10 @@ class ExchangeCardState extends State<ExchangeCard> {
fontSize: 16,
fontWeight: FontWeight.w600,
color:
Theme.of(context).textTheme.subhead.decorationColor),
Theme.of(context)
.accentTextTheme
.display4
.decorationColor),
buttonColor: widget.addressButtonsColor,
validator: widget.addressTextFieldValidator,
),
@@ -227,16 +227,15 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
final sendingState =
widget.exchangeTradeViewModel.sendViewModel.state;
return trade.from == CryptoCurrency.xmr && !(sendingState is TransactionCommitted)
return widget.exchangeTradeViewModel.isSendable &&
!(sendingState is TransactionCommitted)
? LoadingPrimaryButton(
isDisabled: trade.inputAddress == null ||
trade.inputAddress.isEmpty,
isLoading: sendingState is IsExecutingState,
onPressed: () =>
widget.exchangeTradeViewModel.confirmSending(),
text: trade.provider == ExchangeProviderDescription.xmrto
? S.of(context).confirm
: S.of(context).send_xmr,
text: S.of(context).confirm,
color: Theme.of(context).accentTextTheme.body2.color,
textColor: Colors.white)
: Offstage();
@@ -306,7 +305,11 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
padding: EdgeInsets.only(
top: 220, left: 24, right: 24),
child: Text(
S.of(context).send_success,
S.of(context).send_success(widget
.exchangeTradeViewModel
.wallet
.currency
.toString()),
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 22,
@@ -103,7 +103,12 @@ class MoneroAccountListPage extends StatelessWidget {
accountListViewModel
.select(account);
Navigator.of(context).pop();
});
},
onEdit: () async =>
await Navigator.of(context)
.pushNamed(
Routes.accountCreation,
arguments: account));
},
),
isAlwaysShowScrollThumb
@@ -1,15 +1,19 @@
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:cake_wallet/generated/i18n.dart';
class AccountTile extends StatelessWidget {
AccountTile({
@required this.isCurrent,
@required this.accountName,
@required this.onTap
@required this.onTap,
@required this.onEdit
});
final bool isCurrent;
final String accountName;
final VoidCallback onTap;
final Function() onTap;
final Function() onEdit;
@override
Widget build(BuildContext context) {
@@ -20,7 +24,7 @@ class AccountTile extends StatelessWidget {
? Theme.of(context).textTheme.subtitle.color
: Theme.of(context).textTheme.display4.color;
return GestureDetector(
final Widget cell = GestureDetector(
onTap: onTap,
child: Container(
height: 77,
@@ -39,5 +43,17 @@ class AccountTile extends StatelessWidget {
),
),
);
return isCurrent ? cell : Slidable(
key: Key(accountName),
child: cell,
actionPane: SlidableDrawerActionPane(),
secondaryActions: <Widget>[
IconSlideAction(
caption: S.of(context).edit,
color: Colors.blue,
icon: Icons.edit,
onTap: () => onEdit?.call())
]);
}
}
+11 -12
View File
@@ -1,6 +1,5 @@
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:mobx/mobx.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@@ -22,17 +21,24 @@ class NewWalletPage extends BasePage {
final WalletNewVM _walletNewVM;
final walletNameImage = Image.asset('assets/images/wallet_name.png');
final walletNameLightImage =
Image.asset('assets/images/wallet_name_light.png');
@override
String get title => S.current.new_wallet;
@override
Widget body(BuildContext context) => WalletNameForm(_walletNewVM);
Widget body(BuildContext context) => WalletNameForm(_walletNewVM,
currentTheme.type == ThemeType.dark
? walletNameImage : walletNameLightImage);
}
class WalletNameForm extends StatefulWidget {
WalletNameForm(this._walletNewVM);
WalletNameForm(this._walletNewVM, this.walletImage);
final WalletNewVM _walletNewVM;
final Image walletImage;
@override
_WalletNameFormState createState() => _WalletNameFormState(_walletNewVM);
@@ -43,9 +49,6 @@ class _WalletNameFormState extends State<WalletNameForm> {
static const aspectRatioImage = 1.22;
final walletNameImage = Image.asset('assets/images/wallet_name.png');
final walletNameLightImage =
Image.asset('assets/images/wallet_name_light.png');
final _formKey = GlobalKey<FormState>();
final _languageSelectorKey = GlobalKey<SeedLanguageSelectorState>();
ReactionDisposer _stateReaction;
@@ -78,10 +81,6 @@ class _WalletNameFormState extends State<WalletNameForm> {
@override
Widget build(BuildContext context) {
final walletImage = getIt.get<SettingsStore>().isDarkTheme
? walletNameImage
: walletNameLightImage;
return Container(
padding: EdgeInsets.only(top: 24),
child: ScrollableWithBottomSection(
@@ -92,7 +91,7 @@ class _WalletNameFormState extends State<WalletNameForm> {
padding: EdgeInsets.only(left: 12, right: 12),
child: AspectRatio(
aspectRatio: aspectRatioImage,
child: FittedBox(child: walletImage, fit: BoxFit.fill)),
child: FittedBox(child: widget.walletImage, fit: BoxFit.fill)),
),
Padding(
padding: EdgeInsets.only(top: 24),
@@ -1,6 +1,13 @@
import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/entities/wallet_type.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/view_model/wallet_new_vm.dart';
import 'package:flushbar/flushbar.dart';
import 'package:cake_wallet/entities/wallet_type.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:cake_wallet/generated/i18n.dart';
@@ -10,25 +17,36 @@ import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
import 'package:cake_wallet/src/screens/new_wallet/widgets/select_button.dart';
class NewWalletTypePage extends BasePage {
NewWalletTypePage({this.onTypeSelected, this.isNewWallet = true});
NewWalletTypePage(this.walletNewVM, {this.onTypeSelected, this.isNewWallet});
final void Function(BuildContext, WalletType) onTypeSelected;
final bool isNewWallet;
final WalletNewVM walletNewVM;
final walletTypeImage = Image.asset('assets/images/wallet_type.png');
final walletTypeLightImage =
Image.asset('assets/images/wallet_type_light.png');
@override
String get title => isNewWallet
? S.current.new_wallet
: S.current.wallet_list_restore_wallet;
String get title =>
isNewWallet ? S.current.new_wallet : S.current.wallet_list_restore_wallet;
@override
Widget body(BuildContext context) =>
WalletTypeForm(onTypeSelected: onTypeSelected);
Widget body(BuildContext context) => WalletTypeForm(walletNewVM, isNewWallet,
onTypeSelected: onTypeSelected,
walletImage: currentTheme.type == ThemeType.dark
? walletTypeImage
: walletTypeLightImage);
}
class WalletTypeForm extends StatefulWidget {
WalletTypeForm({this.onTypeSelected});
WalletTypeForm(this.walletNewVM, this.isNewWallet,
{this.onTypeSelected, this.walletImage});
final void Function(BuildContext, WalletType) onTypeSelected;
final WalletNewVM walletNewVM;
final bool isNewWallet;
final Image walletImage;
@override
WalletTypeFormState createState() => WalletTypeFormState();
@@ -42,10 +60,12 @@ class WalletTypeFormState extends State<WalletTypeForm> {
final bitcoinIcon =
Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
final walletTypeImage = Image.asset('assets/images/wallet_type.png');
final walletTypeLightImage = Image.asset('assets/images/wallet_type_light.png');
final walletTypeLightImage =
Image.asset('assets/images/wallet_type_light.png');
WalletType selected;
List<WalletType> types;
Flushbar<void> _progressBar;
@override
void initState() {
@@ -55,11 +75,8 @@ class WalletTypeFormState extends State<WalletTypeForm> {
@override
Widget build(BuildContext context) {
final walletImage = getIt.get<SettingsStore>().isDarkTheme
? walletTypeImage : walletTypeLightImage;
return Container(
padding: EdgeInsets.only(top: 24),
padding: EdgeInsets.only(top: 24, bottom: 24),
child: ScrollableWithBottomSection(
contentPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
content: Column(
@@ -69,7 +86,8 @@ class WalletTypeFormState extends State<WalletTypeForm> {
padding: EdgeInsets.only(left: 12, right: 12),
child: AspectRatio(
aspectRatio: aspectRatioImage,
child: FittedBox(child: walletImage, fit: BoxFit.fill)),
child:
FittedBox(child: widget.walletImage, fit: BoxFit.fill)),
),
Padding(
padding: EdgeInsets.only(top: 48),
@@ -86,7 +104,7 @@ class WalletTypeFormState extends State<WalletTypeForm> {
padding: EdgeInsets.only(top: 24),
child: SelectButton(
image: _iconFor(type),
text: walletTypeToString(type),
text: walletTypeToDisplayName(type),
isSelected: selected == type,
onTap: () => setState(() => selected = type)),
))
@@ -94,9 +112,9 @@ class WalletTypeFormState extends State<WalletTypeForm> {
),
bottomSectionPadding: EdgeInsets.only(left: 24, right: 24, bottom: 24),
bottomSection: PrimaryButton(
onPressed: () => widget.onTypeSelected(context, selected),
onPressed: () => onTypeSelected(),
text: S.of(context).seed_language_next,
color: Colors.green,
color: Theme.of(context).accentTextTheme.body2.color,
textColor: Colors.white,
isDisabled: selected == null,
),
@@ -114,4 +132,35 @@ class WalletTypeFormState extends State<WalletTypeForm> {
return null;
}
}
Future<void> onTypeSelected() async {
if (!widget.isNewWallet) {
widget.onTypeSelected(context, selected);
return;
}
try {
_changeProcessText(S.of(context).creating_new_wallet);
widget.walletNewVM.type = selected;
await widget.walletNewVM
.create(options: 'English'); // FIXME: Unnamed constant
await _progressBar?.dismiss();
final state = widget.walletNewVM.state;
if (state is ExecutedSuccessfullyState) {
widget.onTypeSelected(context, selected);
}
if (state is FailureState) {
_changeProcessText(
S.of(context).creating_new_wallet_error(state.error));
}
} catch (e) {
_changeProcessText(S.of(context).creating_new_wallet_error(e.toString()));
}
}
void _changeProcessText(String text) {
_progressBar = createBar<void>(text, duration: null)..show(context);
}
}
@@ -16,7 +16,7 @@ class SelectButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
final color = isSelected
? Theme.of(context).accentTextTheme.subtitle.decorationColor
? Colors.green
: Theme.of(context).accentTextTheme.caption.color;
final textColor = isSelected
? Theme.of(context).accentTextTheme.headline.decorationColor
@@ -1,3 +1,7 @@
import 'package:cake_wallet/core/execution_state.dart';
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
import 'package:cake_wallet/src/widgets/standard_checkbox.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
@@ -67,6 +71,39 @@ class NodeCreateOrEditPage extends BasePage {
@override
Widget body(BuildContext context) {
reaction((_) => nodeCreateOrEditViewModel.connectionState,
(ExecutionState state) {
if (state is ExecutedSuccessfullyState) {
WidgetsBinding.instance.addPostFrameCallback((_) {
showPopUp<void>(
context: context,
builder: (BuildContext context) =>
AlertWithOneAction(
alertTitle: S.of(context).new_node_testing,
alertContent: state.payload as bool
? S.of(context).node_connection_successful
: S.of(context).node_connection_failed,
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop()));
});
}
if (state is FailureState) {
WidgetsBinding.instance.addPostFrameCallback((_) {
showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithOneAction(
alertTitle: S.of(context).error,
alertContent: state.error,
buttonText: S.of(context).ok,
buttonAction: () => Navigator.of(context).pop());
});
});
}
});
return Container(
padding: EdgeInsets.only(left: 24, right: 24),
child: ScrollableWithBottomSection(
@@ -122,7 +159,22 @@ class NodeCreateOrEditPage extends BasePage {
)
)
],
)
),
Padding(
padding: EdgeInsets.only(top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
Observer(
builder: (_) => StandardCheckbox(
value: nodeCreateOrEditViewModel.useSSL,
onChanged: (value) =>
nodeCreateOrEditViewModel.useSSL = value,
caption: S.of(context).use_ssl,
))
],
))
]
],
)),
@@ -133,9 +185,18 @@ class NodeCreateOrEditPage extends BasePage {
Flexible(
child: Container(
padding: EdgeInsets.only(right: 8.0),
child: PrimaryButton(
onPressed: () => nodeCreateOrEditViewModel.reset(),
text: S.of(context).reset,
child: LoadingPrimaryButton(
onPressed: () async {
if (!_formKey.currentState.validate()) {
return;
}
await nodeCreateOrEditViewModel.connect();
},
isLoading: nodeCreateOrEditViewModel
.connectionState is IsExecutingState,
text: S.of(context).node_test,
isDisabled: !nodeCreateOrEditViewModel.isReady,
color: Colors.orange,
textColor: Colors.white),
)),
@@ -154,7 +215,9 @@ class NodeCreateOrEditPage extends BasePage {
text: S.of(context).save,
color: Theme.of(context).accentTextTheme.body2.color,
textColor: Colors.white,
isDisabled: !nodeCreateOrEditViewModel.isReady,
isDisabled: (!nodeCreateOrEditViewModel.isReady)||
(nodeCreateOrEditViewModel
.connectionState is IsExecutingState),
),
)),
],
+80 -88
View File
@@ -65,98 +65,90 @@ class NodeListPage extends BasePage {
padding: EdgeInsets.only(top: 10),
child: Observer(
builder: (BuildContext context) {
return nodeListViewModel.nodes.isNotEmpty
? SectionStandardList(
sectionCount: 2,
context: context,
itemCounter: (int sectionIndex) {
if (sectionIndex == 0) {
return 1;
}
return SectionStandardList(
sectionCount: 2,
context: context,
itemCounter: (int sectionIndex) {
if (sectionIndex == 0) {
return 1;
}
return nodeListViewModel.nodes.length;
},
itemBuilder: (_, sectionIndex, index) {
if (sectionIndex == 0) {
return NodeHeaderListRow(
title: S.of(context).add_new_node,
onTap: (_) async => await Navigator.of(context)
.pushNamed(Routes.newNode));
}
return nodeListViewModel.nodes.length;
},
itemBuilder: (_, sectionIndex, index) {
if (sectionIndex == 0) {
return NodeHeaderListRow(
title: S.of(context).add_new_node,
onTap: (_) async => await Navigator.of(context)
.pushNamed(Routes.newNode));
}
final node = nodeListViewModel.nodes[index];
final isSelected = node.keyIndex ==
nodeListViewModel.settingsStore.currentNode.keyIndex;
final nodeListRow = NodeListRow(
title: node.uri,
isSelected: isSelected,
isAlive: node.requestNode(),
onTap: (_) async {
if (isSelected) {
return;
final node = nodeListViewModel.nodes[index];
final isSelected =
node.keyIndex == nodeListViewModel.currentNode?.keyIndex;
final nodeListRow = NodeListRow(
title: node.uri,
isSelected: isSelected,
isAlive: node.requestNode(),
onTap: (_) async {
if (isSelected) {
return;
}
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
return AlertWithTwoActions(
alertTitle:
S.of(context).change_current_node_title,
alertContent:
S.of(context).change_current_node(node.uri),
leftButtonText: S.of(context).cancel,
rightButtonText: S.of(context).change,
actionLeftButton: () =>
Navigator.of(context).pop(),
actionRightButton: () async {
await nodeListViewModel.setAsCurrent(node);
Navigator.of(context).pop();
});
});
});
final dismissibleRow = Slidable(
key: Key('${node.keyIndex}'),
actionPane: SlidableDrawerActionPane(),
child: nodeListRow,
secondaryActions: <Widget>[
IconSlideAction(
caption: S.of(context).delete,
color: Colors.red,
icon: CupertinoIcons.delete,
onTap: () 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);
}
},
),
]);
await showPopUp<void>(
context: context,
builder: (BuildContext context) {
// FIXME: Add translation.
return AlertWithTwoActions(
alertTitle: 'Change current node',
alertContent: S
.of(context)
.change_current_node(node.uri),
leftButtonText: S.of(context).cancel,
rightButtonText: S.of(context).change,
actionLeftButton: () =>
Navigator.of(context).pop(),
actionRightButton: () async {
await nodeListViewModel
.setAsCurrent(node);
Navigator.of(context).pop();
});
});
});
final dismissibleRow = Slidable(
key: Key('${node.keyIndex}'),
actionPane: SlidableDrawerActionPane(),
child: nodeListRow,
secondaryActions: <Widget>[
IconSlideAction(
caption: S.of(context).delete,
color: Colors.red,
icon: CupertinoIcons.delete,
onTap: () 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);
}
},
),
]);
return isSelected ? nodeListRow : dismissibleRow;
})
: Container();
return isSelected ? nodeListRow : dismissibleRow;
});
},
),
);
+54 -23
View File
@@ -1,4 +1,5 @@
import 'package:cake_wallet/src/widgets/keyboard_done_button.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
@@ -27,16 +28,47 @@ class ReceivePage extends BasePage {
String get title => S.current.receive;
@override
Color get backgroundLightColor => Colors.transparent;
Color get backgroundLightColor => currentTheme.type == ThemeType.bright
? Colors.transparent : Colors.white;
@override
Color get backgroundDarkColor => Colors.transparent;
@override
Color get titleColor => Colors.white;
final FocusNode _cryptoAmountFocus;
@override
Widget leading(BuildContext context) {
final _backButton = Icon(Icons.arrow_back_ios,
color: Theme.of(context).accentTextTheme.display3.backgroundColor,
size: 16,);
return SizedBox(
height: 37,
width: 37,
child: ButtonTheme(
minWidth: double.minPositive,
child: FlatButton(
highlightColor: Colors.transparent,
splashColor: Colors.transparent,
padding: EdgeInsets.all(0),
onPressed: () => onClose(context),
child: _backButton),
),
);
}
@override
Widget middle(BuildContext context) {
return Text(
title,
style: TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.bold,
fontFamily: 'Lato',
color: Theme.of(context).accentTextTheme.display3.backgroundColor),
);
}
@override
Widget Function(BuildContext, Widget) get rootWrapper =>
(BuildContext context, Widget scaffold) => Container(
@@ -51,7 +83,8 @@ class ReceivePage extends BasePage {
@override
Widget trailing(BuildContext context) {
final shareImage =
Image.asset('assets/images/share.png', color: Colors.white);
Image.asset('assets/images/share.png',
color: Theme.of(context).accentTextTheme.display3.backgroundColor);
return SizedBox(
height: 20.0,
@@ -74,9 +107,8 @@ class ReceivePage extends BasePage {
return KeyboardActions(
config: KeyboardActionsConfig(
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
keyboardBarColor: isDarkTheme
? Color.fromRGBO(48, 51, 60, 1.0)
: Color.fromRGBO(98, 98, 98, 1.0),
keyboardBarColor: Theme.of(context).accentTextTheme.body2
.backgroundColor,
nextFocus: false,
actions: [
KeyboardActionsItem(
@@ -117,7 +149,7 @@ class ReceivePage extends BasePage {
Icons.arrow_forward_ios,
size: 14,
color:
Theme.of(context).textTheme.display1.color,
Theme.of(context).textTheme.display1.color,
));
}
@@ -130,7 +162,7 @@ class ReceivePage extends BasePage {
Icons.add,
size: 20,
color:
Theme.of(context).textTheme.display1.color,
Theme.of(context).textTheme.display1.color,
));
}
@@ -140,13 +172,13 @@ class ReceivePage extends BasePage {
addressListViewModel.address.address;
final backgroundColor = isCurrent
? Theme.of(context)
.textTheme
.display3
.decorationColor
.textTheme
.display3
.decorationColor
: Theme.of(context)
.textTheme
.display2
.decorationColor;
.textTheme
.display2
.decorationColor;
final textColor = isCurrent
? Theme.of(context).textTheme.display3.color
: Theme.of(context).textTheme.display2.color;
@@ -155,8 +187,7 @@ class ReceivePage extends BasePage {
isCurrent: isCurrent,
backgroundColor: backgroundColor,
textColor: textColor,
onTap: (_) =>
addressListViewModel.setAddress(item),
onTap: (_) => addressListViewModel.setAddress(item),
onEdit: () => Navigator.of(context).pushNamed(
Routes.newSubaddress,
arguments: item));
@@ -166,11 +197,11 @@ class ReceivePage extends BasePage {
return index != 0
? cell
: ClipRRect(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30),
topRight: Radius.circular(30)),
child: cell,
);
borderRadius: BorderRadius.only(
topLeft: Radius.circular(30),
topRight: Radius.circular(30)),
child: cell,
);
})),
],
),
@@ -14,6 +14,7 @@ class AddressCell extends StatelessWidget {
address: item.address,
name: item.name,
isCurrent: isCurrent,
isPrimary: item.isPrimary,
backgroundColor: backgroundColor,
textColor: textColor,
onTap: onTap,
@@ -23,6 +24,7 @@ class AddressCell extends StatelessWidget {
{@required this.address,
@required this.name,
@required this.isCurrent,
@required this.isPrimary,
@required this.backgroundColor,
@required this.textColor,
this.onTap,
@@ -31,6 +33,7 @@ class AddressCell extends StatelessWidget {
final String address;
final String name;
final bool isCurrent;
final bool isPrimary;
final Color backgroundColor;
final Color textColor;
final Function(String) onTap;
@@ -56,7 +59,7 @@ class AddressCell extends StatelessWidget {
),
));
return isCurrent
return (isCurrent || isPrimary)
? cell
: Slidable(
key: Key(address),
+8 -16
View File
@@ -47,24 +47,14 @@ class QRWidget extends StatelessWidget {
child: QrImage(
data: addressListViewModel.uri.toString(),
backgroundColor: Colors.transparent,
foregroundColor: Colors.white,
//Theme.of(context).textTheme.headline.color,
foregroundColor: Theme.of(context).accentTextTheme.
display3.backgroundColor,
))))),
Spacer(flex: 3)
]),
Padding(
padding: EdgeInsets.only(top: 20),
child: Text(
S.of(context).scan_qr_code,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Theme.of(context).indicatorColor),
),
),
isAmountFieldShow
? Padding(
padding: EdgeInsets.only(top: 40),
padding: EdgeInsets.only(top: 60),
child: Row(
children: <Widget>[
Expanded(
@@ -77,11 +67,12 @@ class QRWidget extends StatelessWidget {
decimal: true),
inputFormatters: [
BlacklistingTextInputFormatter(
RegExp('[\\-|\\ |\\,]'))
RegExp('[\\-|\\ ]'))
],
textAlign: TextAlign.center,
hintText: S.of(context).receive_amount,
textColor: Colors.white,
textColor: Theme.of(context).accentTextTheme.
display3.backgroundColor,
borderColor: Theme.of(context)
.textTheme
.headline
@@ -120,7 +111,8 @@ class QRWidget extends StatelessWidget {
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
color: Colors.white),
color: Theme.of(context).accentTextTheme.
display3.backgroundColor),
),
),
Padding(
@@ -1,3 +1,5 @@
import 'package:cake_wallet/entities/wallet_type.dart';
import 'package:cake_wallet/view_model/wallet_restore_view_model.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
@@ -7,12 +9,20 @@ import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
class WalletRestoreFromSeedForm extends StatefulWidget {
WalletRestoreFromSeedForm({Key key, this.blockHeightFocusNode,
this.onHeightOrDateEntered})
WalletRestoreFromSeedForm(
{Key key,
@required this.displayLanguageSelector,
@required this.displayBlockHeightSelector,
@required this.type,
this.blockHeightFocusNode,
this.onHeightOrDateEntered})
: super(key: key);
final WalletType type;
final bool displayLanguageSelector;
final bool displayBlockHeightSelector;
final FocusNode blockHeightFocusNode;
final Function (bool) onHeightOrDateEntered;
final Function(bool) onHeightOrDateEntered;
@override
WalletRestoreFromSeedFormState createState() =>
@@ -41,32 +51,35 @@ class WalletRestoreFromSeedFormState extends State<WalletRestoreFromSeedForm> {
return Container(
padding: EdgeInsets.only(left: 25, right: 25),
child: Column(children: [
SeedWidget(key: seedWidgetStateKey, language: language),
GestureDetector(
onTap: () async {
final selected = await showPopUp<String>(
context: context,
builder: (BuildContext context) =>
SeedLanguagePicker(selected: language));
SeedWidget(
key: seedWidgetStateKey, language: language, type: widget.type),
if (widget.displayLanguageSelector)
GestureDetector(
onTap: () async {
final selected = await showPopUp<String>(
context: context,
builder: (BuildContext context) =>
SeedLanguagePicker(selected: language));
if (selected == null || selected.isEmpty) {
return;
}
if (selected == null || selected.isEmpty) {
return;
}
_changeLanguage(selected);
},
child: Container(
color: Colors.transparent,
padding: EdgeInsets.only(top: 20.0),
child: IgnorePointer(
child: BaseTextFormField(
controller: languageController,
enableInteractiveSelection: false,
readOnly: true)))),
BlockchainHeightWidget(
focusNode: widget.blockHeightFocusNode,
key: blockchainHeightKey,
onHeightOrDateEntered: widget.onHeightOrDateEntered)
_changeLanguage(selected);
},
child: Container(
color: Colors.transparent,
padding: EdgeInsets.only(top: 20.0),
child: IgnorePointer(
child: BaseTextFormField(
controller: languageController,
enableInteractiveSelection: false,
readOnly: true)))),
if (widget.displayBlockHeightSelector)
BlockchainHeightWidget(
focusNode: widget.blockHeightFocusNode,
key: blockchainHeightKey,
onHeightOrDateEntered: widget.onHeightOrDateEntered)
]));
}
@@ -25,16 +25,30 @@ class WalletRestorePage extends BasePage {
_pages = [],
_blockHeightFocusNode = FocusNode(),
_controller = PageController(initialPage: 0) {
_pages.addAll([
WalletRestoreFromSeedForm(
key: walletRestoreFromSeedFormKey,
blockHeightFocusNode: _blockHeightFocusNode,
onHeightOrDateEntered: (value)
=> walletRestoreViewModel.isButtonEnabled = value),
WalletRestoreFromKeysFrom(key: walletRestoreFromKeysFormKey,
onHeightOrDateEntered: (value)
=> walletRestoreViewModel.isButtonEnabled = value)
]);
walletRestoreViewModel.availableModes.forEach((mode) {
switch (mode) {
case WalletRestoreMode.seed:
_pages.add(WalletRestoreFromSeedForm(
displayBlockHeightSelector:
walletRestoreViewModel.hasBlockchainHeightLanguageSelector,
displayLanguageSelector:
walletRestoreViewModel.hasSeedLanguageSelector,
type: walletRestoreViewModel.type,
key: walletRestoreFromSeedFormKey,
blockHeightFocusNode: _blockHeightFocusNode,
onHeightOrDateEntered: (value) =>
walletRestoreViewModel.isButtonEnabled = value));
break;
case WalletRestoreMode.keys:
_pages.add(WalletRestoreFromKeysFrom(
key: walletRestoreFromKeysFormKey,
onHeightOrDateEntered: (value) =>
walletRestoreViewModel.isButtonEnabled = value));
break;
default:
break;
}
});
}
@override
@@ -76,20 +90,19 @@ class WalletRestorePage extends BasePage {
}
});
reaction((_) => walletRestoreViewModel.mode, (WalletRestoreMode mode)
{
walletRestoreViewModel.isButtonEnabled = false;
reaction((_) => walletRestoreViewModel.mode, (WalletRestoreMode mode) {
walletRestoreViewModel.isButtonEnabled = false;
walletRestoreFromSeedFormKey.currentState.blockchainHeightKey
.currentState.restoreHeightController.text = '';
walletRestoreFromSeedFormKey.currentState.blockchainHeightKey
.currentState.dateController.text = '';
walletRestoreFromSeedFormKey.currentState.blockchainHeightKey.currentState
.restoreHeightController.text = '';
walletRestoreFromSeedFormKey.currentState.blockchainHeightKey.currentState
.dateController.text = '';
walletRestoreFromKeysFormKey.currentState.blockchainHeightKey
.currentState.restoreHeightController.text = '';
walletRestoreFromKeysFormKey.currentState.blockchainHeightKey
.currentState.dateController.text = '';
});
walletRestoreFromKeysFormKey.currentState.blockchainHeightKey.currentState
.restoreHeightController.text = '';
walletRestoreFromKeysFormKey.currentState.blockchainHeightKey.currentState
.dateController.text = '';
});
return Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Expanded(
@@ -100,40 +113,37 @@ class WalletRestorePage extends BasePage {
},
controller: _controller,
itemCount: _pages.length,
itemBuilder: (_, index) => SingleChildScrollView(child: _pages[index]))),
Padding(
padding: EdgeInsets.only(top: 10),
child: SmoothPageIndicator(
controller: _controller,
count: _pages.length,
effect: ColorTransitionEffect(
spacing: 6.0,
radius: 6.0,
dotWidth: 6.0,
dotHeight: 6.0,
dotColor: Theme.of(context).hintColor.withOpacity(0.5),
activeDotColor: Theme.of(context).hintColor),
)),
itemBuilder: (_, index) =>
SingleChildScrollView(child: _pages[index]))),
if (_pages.length > 1)
Padding(
padding: EdgeInsets.only(top: 10),
child: SmoothPageIndicator(
controller: _controller,
count: _pages.length,
effect: ColorTransitionEffect(
spacing: 6.0,
radius: 6.0,
dotWidth: 6.0,
dotHeight: 6.0,
dotColor: Theme.of(context).hintColor.withOpacity(0.5),
activeDotColor: Theme.of(context).hintColor),
)),
Padding(
padding: EdgeInsets.only(top: 20, bottom: 40, left: 25, right: 25),
child: Observer(
builder: (context) {
return LoadingPrimaryButton(
onPressed: () =>
walletRestoreViewModel.create(options: _credentials()),
text: S.of(context).restore_recover,
color: Theme
.of(context)
.accentTextTheme
.subtitle
.decorationColor,
textColor: Theme
.of(context)
.accentTextTheme
.headline
.decorationColor,
isLoading: walletRestoreViewModel.state is IsExecutingState,
isDisabled: !walletRestoreViewModel.isButtonEnabled,);
onPressed: () =>
walletRestoreViewModel.create(options: _credentials()),
text: S.of(context).restore_recover,
color:
Theme.of(context).accentTextTheme.subtitle.decorationColor,
textColor:
Theme.of(context).accentTextTheme.headline.decorationColor,
isLoading: walletRestoreViewModel.state is IsExecutingState,
isDisabled: !walletRestoreViewModel.isButtonEnabled,
);
},
))
]);
@@ -145,8 +155,11 @@ class WalletRestorePage extends BasePage {
if (walletRestoreViewModel.mode == WalletRestoreMode.seed) {
credentials['seed'] = walletRestoreFromSeedFormKey
.currentState.seedWidgetStateKey.currentState.text;
credentials['height'] = walletRestoreFromSeedFormKey
.currentState.blockchainHeightKey.currentState.height;
if (walletRestoreViewModel.hasBlockchainHeightLanguageSelector) {
credentials['height'] = walletRestoreFromSeedFormKey
.currentState.blockchainHeightKey.currentState.height;
}
} else {
credentials['address'] =
walletRestoreFromKeysFormKey.currentState.addressController.text;
+75
View File
@@ -0,0 +1,75 @@
import 'package:cake_wallet/entities/wallet_type.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:flutter/cupertino.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/screens/base_page.dart';
class PreSeedPage extends BasePage {
PreSeedPage(this.type)
: imageLight = Image.asset('assets/images/pre_seed_light.png'),
imageDark = Image.asset('assets/images/pre_seed_dark.png'),
wordsCount = type == WalletType.monero
? 25
: 12; // FIXME: Stupid fast implementation
final Image imageDark;
final Image imageLight;
final WalletType type;
final int wordsCount;
@override
Widget leading(BuildContext context) => null;
@override
String get title => S.current.pre_seed_title;
@override
Widget body(BuildContext context) {
final image = currentTheme.type == ThemeType.dark ? imageDark : imageLight;
return WillPopScope(
onWillPop: () async => false,
child: Container(
padding: EdgeInsets.all(24),
child: Column(
children: [
Flexible(
flex: 2,
child: AspectRatio(
aspectRatio: 1,
child: FittedBox(child: image, fit: BoxFit.contain))),
Flexible(
flex: 3,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Padding(
padding: EdgeInsets.only(top: 70, left: 16, right: 16),
child: Text(
S.of(context).pre_seed_description(wordsCount),
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.normal,
color: Theme.of(context)
.primaryTextTheme
.caption
.color),
),
),
PrimaryButton(
onPressed: () => Navigator.of(context)
.popAndPushNamed(Routes.seed, arguments: true),
text: S.of(context).pre_seed_button_text,
color: Theme.of(context).accentTextTheme.body2.color,
textColor: Colors.white)
],
))
],
),
));
}
}
+6 -8
View File
@@ -1,7 +1,6 @@
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/palette.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/utils/show_bar.dart';
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/cupertino.dart';
@@ -17,8 +16,8 @@ import 'package:cake_wallet/view_model/wallet_seed_view_model.dart';
class WalletSeedPage extends BasePage {
WalletSeedPage(this.walletSeedViewModel, {@required this.isNewWalletCreated});
static final imageLight = Image.asset('assets/images/crypto_lock_light.png');
static final imageDark = Image.asset('assets/images/crypto_lock.png');
final imageLight = Image.asset('assets/images/crypto_lock_light.png');
final imageDark = Image.asset('assets/images/crypto_lock.png');
@override
String get title => S.current.seed_title;
@@ -83,10 +82,9 @@ class WalletSeedPage extends BasePage {
@override
Widget body(BuildContext context) {
final image =
getIt.get<SettingsStore>().isDarkTheme ? imageDark : imageLight;
final image = currentTheme.type == ThemeType.dark ? imageDark : imageLight;
return Container(
return WillPopScope(onWillPop: () async => false, child: Container(
padding: EdgeInsets.all(24),
child: Column(
children: <Widget>[
@@ -194,6 +192,6 @@ class WalletSeedPage extends BasePage {
],
))
],
));
)));
}
}
@@ -1,6 +1,5 @@
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/src/widgets/seed_language_selector.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
@@ -15,17 +14,26 @@ class SeedLanguage extends BasePage {
final Function(BuildContext, String) onConfirm;
final walletNameImage = Image.asset('assets/images/wallet_name.png');
final walletNameLightImage =
Image.asset('assets/images/wallet_name_light.png');
@override
String get title => S.current.wallet_list_restore_wallet;
@override
Widget body(BuildContext context) => SeedLanguageForm(onConfirm: onConfirm);
Widget body(BuildContext context) =>
SeedLanguageForm(
onConfirm: onConfirm,
walletImage: currentTheme.type == ThemeType.dark
? walletNameImage : walletNameLightImage);
}
class SeedLanguageForm extends StatefulWidget {
SeedLanguageForm({this.onConfirm});
SeedLanguageForm({this.onConfirm, this.walletImage});
final Function(BuildContext, String) onConfirm;
final Image walletImage;
@override
SeedLanguageFormState createState() => SeedLanguageFormState();
@@ -33,18 +41,10 @@ class SeedLanguageForm extends StatefulWidget {
class SeedLanguageFormState extends State<SeedLanguageForm> {
static const aspectRatioImage = 1.22;
final walletNameImage = Image.asset('assets/images/wallet_name.png');
final walletNameLightImage =
Image.asset('assets/images/wallet_name_light.png');
final _languageSelectorKey = GlobalKey<SeedLanguageSelectorState>();
@override
Widget build(BuildContext context) {
final walletImage = getIt.get<SettingsStore>().isDarkTheme
? walletNameImage
: walletNameLightImage;
return Container(
padding: EdgeInsets.only(top: 24),
child: ScrollableWithBottomSection(
@@ -55,7 +55,8 @@ class SeedLanguageFormState extends State<SeedLanguageForm> {
padding: EdgeInsets.only(left: 12, right: 12),
child: AspectRatio(
aspectRatio: aspectRatioImage,
child: FittedBox(child: walletImage, fit: BoxFit.fill)),
child: FittedBox(child: widget.walletImage,
fit: BoxFit.fill)),
),
Padding(
padding: EdgeInsets.only(top: 40),
+10 -14
View File
@@ -83,9 +83,8 @@ class SendPage extends BasePage {
return KeyboardActions(
config: KeyboardActionsConfig(
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
keyboardBarColor: isDarkTheme
? Color.fromRGBO(48, 51, 60, 1.0)
: Color.fromRGBO(98, 98, 98, 1.0),
keyboardBarColor: Theme.of(context).accentTextTheme.body2
.backgroundColor,
nextFocus: false,
actions: [
KeyboardActionsItem(
@@ -133,7 +132,8 @@ class SendPage extends BasePage {
if (uri != null) {
address = uri.path;
amount = uri.queryParameters['tx_amount'];
amount = uri.queryParameters['tx_amount'] ??
uri.queryParameters['amount'];
} else {
address = uri.toString();
}
@@ -497,14 +497,8 @@ class SendPage extends BasePage {
}
},
text: S.of(context).send,
color: Theme.of(context)
.accentTextTheme
.subtitle
.decorationColor,
textColor: Theme.of(context)
.accentTextTheme
.headline
.decorationColor,
color: Theme.of(context).accentTextTheme.body2.color,
textColor: Colors.white,
isLoading: sendViewModel.state is IsExecutingState ||
sendViewModel.state is TransactionCommitting,
isDisabled:
@@ -634,7 +628,9 @@ class SendPage extends BasePage {
padding: EdgeInsets.only(
top: 220, left: 24, right: 24),
child: Text(
S.of(context).send_success,
S.of(context).send_success(
sendViewModel.currency
.toString()),
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 22,
@@ -748,7 +744,7 @@ class SendPage extends BasePage {
}
Future<void> _setTransactionPriority(BuildContext context) async {
final items = TransactionPriority.all;
final items = TransactionPriority.forWalletType(sendViewModel.walletType);
final selectedItem = items.indexOf(sendViewModel.transactionPriority);
await showPopUp<void>(
+6 -7
View File
@@ -49,9 +49,8 @@ class SendTemplatePage extends BasePage {
return KeyboardActions(
config: KeyboardActionsConfig(
keyboardActionsPlatform: KeyboardActionsPlatform.IOS,
keyboardBarColor: isDarkTheme
? Color.fromRGBO(48, 51, 60, 1.0)
: Color.fromRGBO(98, 98, 98, 1.0),
keyboardBarColor: Theme.of(context).accentTextTheme.body2
.backgroundColor,
nextFocus: false,
actions: [
KeyboardActionsItem(
@@ -113,7 +112,8 @@ class SendTemplatePage extends BasePage {
if (uri != null) {
address = uri.path;
amount = uri.queryParameters['tx_amount'];
amount = uri.queryParameters['tx_amount'] ??
uri.queryParameters['amount'];
} else {
address = uri.toString();
}
@@ -246,9 +246,8 @@ class SendTemplatePage extends BasePage {
}
},
text: S.of(context).save,
color: Theme.of(context).accentTextTheme.subtitle.decorationColor,
textColor:
Theme.of(context).accentTextTheme.headline.decorationColor,
color: Colors.green,
textColor: Colors.white,
),
),
));
@@ -49,6 +49,7 @@ class TransactionDetailsPage extends BasePage {
value: tx.amountFormatted()),
StandartListItem(title: S.current.send_fee, value: tx.feeFormatted())
];
if (showRecipientAddress) {
final recipientAddress = transactionDescriptionBox.values
.firstWhere((val) => val.id == transactionInfo.id,
@@ -61,6 +62,12 @@ class TransactionDetailsPage extends BasePage {
value: recipientAddress));
}
}
if (tx.key?.isNotEmpty ?? null) {
// FIXME: add translation
items.add(StandartListItem(title: 'Transaction Key', value: tx.key));
}
_items.addAll(items);
_items.add(StandartListItem(
title: "View in Block Explorer",
@@ -81,9 +88,8 @@ class TransactionDetailsPage extends BasePage {
StandartListItem(
title: S.current.transaction_details_amount,
value: tx.amountFormatted()),
StandartListItem(
title: "View in Block Explorer",
value: "https://www.blockchain.com/btc/tx/${tx.id}"),
if (tx.feeFormatted()?.isNotEmpty)
StandartListItem(title: S.current.send_fee, value: tx.feeFormatted())
];
_items.addAll(items);
@@ -91,6 +97,18 @@ class TransactionDetailsPage extends BasePage {
title: "View in Block Explorer",
value: "https://www.blockchain.com/btc/tx/${tx.id}"));
}
if (showRecipientAddress) {
final recipientAddress = transactionDescriptionBox.values
.firstWhere((val) => val.id == transactionInfo.id, orElse: () => null)
?.recipientAddress;
if (recipientAddress?.isNotEmpty ?? false) {
_items.add(StandartListItem(
title: S.current.transaction_details_recipient_address,
value: recipientAddress));
}
}
}
@override
@@ -1,5 +1,4 @@
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
import 'package:cake_wallet/src/screens/wallet_list/widgets/wallet_menu_alert.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';
@@ -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/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
import 'package:cake_wallet/src/screens/wallet_list/wallet_menu.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
class WalletListPage extends BasePage {
@@ -51,7 +49,7 @@ class WalletListBodyState extends State<WalletListBody> {
final newWalletImage = Image.asset('assets/images/new_wallet.png',
height: 12,
width: 12,
color: Theme.of(context).accentTextTheme.headline.decorationColor);
color: Colors.white);
final restoreWalletImage = Image.asset('assets/images/restore_wallet.png',
height: 12,
width: 12,
@@ -165,17 +163,16 @@ class WalletListBodyState extends State<WalletListBody> {
),
bottomSection: Column(children: <Widget>[
PrimaryImageButton(
onPressed: () => _generateNewWallet(),
onPressed: () => Navigator.of(context).pushNamed(Routes.newWalletType),
image: newWalletImage,
text: S.of(context).wallet_list_create_new_wallet,
color: Theme.of(context).accentTextTheme.subtitle.decorationColor,
textColor:
Theme.of(context).accentTextTheme.headline.decorationColor,
color: Theme.of(context).accentTextTheme.body2.color,
textColor: Colors.white,
),
SizedBox(height: 10.0),
PrimaryImageButton(
onPressed: () =>
Navigator.of(context).pushNamed(Routes.restoreWallet),
Navigator.of(context).pushNamed(Routes.restoreWalletType),
image: restoreWalletImage,
text: S.of(context).wallet_list_restore_wallet,
color: Theme.of(context).accentTextTheme.caption.color,
@@ -243,7 +240,7 @@ class WalletListBodyState extends State<WalletListBody> {
changeProcessText(S.of(context).creating_new_wallet);
await widget.walletListViewModel.walletNewVM.create(options: 'English'); // FIXME: Unnamed constant
hideProgressText();
await Navigator.of(context).pushNamed(Routes.seed, arguments: true);
await Navigator.of(context).pushNamed(Routes.preSeed);
} catch(e) {
changeProcessText(S.of(context).creating_new_wallet_error(e.toString()));
}
+2 -5
View File
@@ -1,5 +1,4 @@
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:flutter/material.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/widgets/primary_button.dart';
@@ -23,9 +22,7 @@ class WelcomePage extends BasePage {
@override
Widget body(BuildContext context) {
final welcomeImage = getIt
.get<SettingsStore>()
.isDarkTheme
final welcomeImage = currentTheme.type == ThemeType.dark
? welcomeImageDark : welcomeImageLight;
final newWalletImage = Image.asset('assets/images/new_wallet.png',
+1 -1
View File
@@ -204,7 +204,7 @@ class AddressTextField extends StatelessWidget {
onURIScanned(uri);
}
} catch (e) {
print('Error $e');
print(e.toString());
}
}
+3 -2
View File
@@ -31,7 +31,7 @@ class AlertWithOneAction extends BaseAlertDialog {
width: 300,
height: 52,
padding: EdgeInsets.only(left: 12, right: 12),
color: Theme.of(context).accentTextTheme.body2.color,
color: Theme.of(context).accentTextTheme.body1.backgroundColor,
child: ButtonTheme(
minWidth: double.infinity,
child: FlatButton(
@@ -44,7 +44,8 @@ class AlertWithOneAction extends BaseAlertDialog {
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w600,
color: Colors.white,
color: Theme.of(context).primaryTextTheme.body1
.backgroundColor,
decoration: TextDecoration.none,
),
)),
+14 -3
View File
@@ -61,18 +61,24 @@ class BaseAlertDialog extends StatelessWidget {
fontSize: 15,
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
color: Colors.white,
color: Theme.of(context).primaryTextTheme.body2
.backgroundColor,
decoration: TextDecoration.none,
),
)),
),
)
),
Container(
width: 1,
height: 52,
color: Theme.of(context).dividerColor,
),
Flexible(
child: Container(
height: 52,
padding: EdgeInsets.only(left: 6, right: 6),
color: Theme.of(context).accentTextTheme.body2.color,
color: Theme.of(context).accentTextTheme.body1.backgroundColor,
child: ButtonTheme(
minWidth: double.infinity,
child: FlatButton(
@@ -86,7 +92,8 @@ class BaseAlertDialog extends StatelessWidget {
fontSize: 15,
fontFamily: 'Lato',
fontWeight: FontWeight.w600,
color: Colors.white,
color: Theme.of(context).primaryTextTheme.body1
.backgroundColor,
decoration: TextDecoration.none,
),
)),
@@ -133,6 +140,10 @@ class BaseAlertDialog extends StatelessWidget {
],
),
),
Container(
height: 1,
color: Theme.of(context).dividerColor,
),
actionButtons(context)
],
),
+7 -5
View File
@@ -12,20 +12,21 @@ import 'package:cake_wallet/generated/i18n.dart';
import 'package:flutter/widgets.dart';
class SeedWidget extends StatefulWidget {
SeedWidget({Key key, this.language}) : super(key: key);
SeedWidget({Key key, this.language, this.type}) : super(key: key);
final String language;
final WalletType type;
@override
SeedWidgetState createState() => SeedWidgetState(language);
SeedWidgetState createState() => SeedWidgetState(language, type);
}
class SeedWidgetState extends State<SeedWidget> {
SeedWidgetState(String language)
SeedWidgetState(String language, this.type)
: controller = TextEditingController(),
focusNode = FocusNode(),
words = SeedValidator.getWordList(
type: WalletType.monero, language: language) {
type:type, language: language) {
focusNode.addListener(() {
setState(() {
if (!focusNode.hasFocus && controller.text.isEmpty) {
@@ -41,6 +42,7 @@ class SeedWidgetState extends State<SeedWidget> {
final TextEditingController controller;
final FocusNode focusNode;
final WalletType type;
List<String> words;
bool _showPlaceholder;
@@ -55,7 +57,7 @@ class SeedWidgetState extends State<SeedWidget> {
void changeSeedLanguage(String language) {
setState(() {
words = SeedValidator.getWordList(
type: WalletType.monero, language: language);
type: type, language: language);
});
}
+76
View File
@@ -0,0 +1,76 @@
import 'dart:ui';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class StandardCheckbox extends StatefulWidget {
StandardCheckbox({
@required this.value,
this.caption = '',
@required this.onChanged});
final bool value;
final String caption;
final Function(bool) onChanged;
@override
StandardCheckboxState createState() =>
StandardCheckboxState(value, caption, onChanged);
}
class StandardCheckboxState extends State<StandardCheckbox> {
StandardCheckboxState(this.value, this.caption, this.onChanged);
bool value;
String caption;
Function(bool) onChanged;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
value = !value;
onChanged(value);
setState(() {});
},
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
height: 24.0,
width: 24.0,
margin: EdgeInsets.only(
right: 10.0,
),
decoration: BoxDecoration(
border: Border.all(
color: Theme.of(context)
.primaryTextTheme
.caption
.color,
width: 1.0),
borderRadius: BorderRadius.all(
Radius.circular(8.0)),
color: Theme.of(context).backgroundColor),
child: value
? Icon(
Icons.check,
color: Colors.blue,
size: 20.0,
)
: Offstage(),
),
Text(
caption,
style: TextStyle(
fontSize: 16.0,
color: Theme.of(context)
.primaryTextTheme
.title
.color),
)
],
),
);
}
}
+4 -1
View File
@@ -21,7 +21,10 @@ class TrailButton extends StatelessWidget {
child: Text(
caption,
style: TextStyle(
color: Theme.of(context).textTheme.subhead.decorationColor,
color: Theme.of(context)
.accentTextTheme
.display4
.decorationColor,
fontWeight: FontWeight.w500,
fontSize: 14),
),
+6
View File
@@ -26,4 +26,10 @@ abstract class AppStoreBase with Store {
SettingsStore settingsStore;
NodeListStore nodeListStore;
@action
void changeCurrentWallet(WalletBase wallet) {
this.wallet?.close();
this.wallet = wallet;
}
}
@@ -1,13 +1,13 @@
import 'package:cake_wallet/entities/crypto_currency.dart';
import 'package:mobx/mobx.dart';
part 'fiat_conversion_store.g.dart';
class FiatConversionStore = FiatConversionStoreBase
with _$FiatConversionStore;
class FiatConversionStore = FiatConversionStoreBase with _$FiatConversionStore;
abstract class FiatConversionStoreBase with Store {
FiatConversionStoreBase() : price = 0.0;
FiatConversionStoreBase() : prices = ObservableMap<CryptoCurrency, double>();
@observable
double price;
ObservableMap<CryptoCurrency, double> prices;
}
+1 -1
View File
@@ -3,7 +3,7 @@ import 'package:mobx/mobx.dart';
import 'package:cake_wallet/exchange/exchange_provider_description.dart';
import 'package:cake_wallet/view_model/dashboard/trade_list_item.dart';
part 'trade_filter_store.g.dart';
part'trade_filter_store.g.dart';
class TradeFilterStore = TradeFilterStoreBase with _$TradeFilterStore;
+22 -18
View File
@@ -1,5 +1,6 @@
import 'package:cake_wallet/entities/preferences_key.dart';
import 'package:cake_wallet/themes.dart';
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/themes/theme_list.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
@@ -28,7 +29,7 @@ abstract class SettingsStoreBase with Store {
@required BalanceDisplayMode initialBalanceDisplayMode,
@required bool initialSaveRecipientAddress,
@required bool initialAllowBiometricalAuthentication,
@required bool initialDarkTheme,
@required ThemeBase initialTheme,
@required int initialPinLength,
@required String initialLanguageCode,
// @required String initialCurrentLocale,
@@ -40,10 +41,9 @@ abstract class SettingsStoreBase with Store {
balanceDisplayMode = initialBalanceDisplayMode;
shouldSaveRecipientAddress = initialSaveRecipientAddress;
allowBiometricalAuthentication = initialAllowBiometricalAuthentication;
isDarkTheme = initialDarkTheme;
currentTheme = initialTheme;
pinCodeLength = initialPinLength;
languageCode = initialLanguageCode;
currentNode = nodes[WalletType.monero];
this.nodes = ObservableMap<WalletType, Node>.of(nodes);
_sharedPreferences = sharedPreferences;
@@ -65,9 +65,9 @@ abstract class SettingsStoreBase with Store {
shouldSaveRecipientAddress));
reaction(
(_) => isDarkTheme,
(bool isDarkTheme) => sharedPreferences.setBool(
PreferencesKey.currentDarkTheme, isDarkTheme));
(_) => currentTheme,
(ThemeBase theme) =>
sharedPreferences.setInt(PreferencesKey.currentTheme, theme.raw));
reaction(
(_) => allowBiometricalAuthentication,
@@ -80,13 +80,14 @@ abstract class SettingsStoreBase with Store {
(int pinLength) => sharedPreferences.setInt(
PreferencesKey.currentPinLength, pinLength));
reaction((_) => currentNode,
(Node node) => _saveCurrentNode(node, WalletType.monero));
reaction(
(_) => languageCode,
(String languageCode) => sharedPreferences.setString(
PreferencesKey.currentLanguageCode, languageCode));
this
.nodes
.observe((change) => _saveCurrentNode(change.newValue, change.key));
}
static const defaultPinLength = 4;
@@ -111,16 +112,13 @@ abstract class SettingsStoreBase with Store {
bool allowBiometricalAuthentication;
@observable
bool isDarkTheme;
ThemeBase currentTheme;
@observable
int pinCodeLength;
@observable
Node currentNode;
@computed
ThemeData get theme => isDarkTheme ? Themes.darkTheme : Themes.lightTheme;
ThemeData get theme => currentTheme.themeData;
@observable
String languageCode;
@@ -154,8 +152,14 @@ abstract class SettingsStoreBase with Store {
final allowBiometricalAuthentication = sharedPreferences
.getBool(PreferencesKey.allowBiometricalAuthenticationKey) ??
false;
final savedDarkTheme =
sharedPreferences.getBool(PreferencesKey.currentDarkTheme) ?? false;
final legacyTheme =
sharedPreferences.getBool(PreferencesKey.isDarkThemeLegacy)
? ThemeType.dark.index
: ThemeType.bright.index;
final savedTheme = ThemeList.deserialize(
raw: sharedPreferences.getInt(PreferencesKey.currentTheme) ??
legacyTheme ??
0);
final actionListDisplayMode = ObservableList<ActionListDisplayMode>();
actionListDisplayMode.addAll(deserializeActionlistDisplayModes(
sharedPreferences.getInt(PreferencesKey.displayActionListModeKey) ??
@@ -188,7 +192,7 @@ abstract class SettingsStoreBase with Store {
initialBalanceDisplayMode: currentBalanceDisplayMode,
initialSaveRecipientAddress: shouldSaveRecipientAddress,
initialAllowBiometricalAuthentication: allowBiometricalAuthentication,
initialDarkTheme: savedDarkTheme,
initialTheme: savedTheme,
actionlistDisplayMode: actionListDisplayMode,
initialPinLength: pinLength,
initialLanguageCode: savedLanguageCode);
-353
View File
@@ -1,353 +0,0 @@
import 'package:flutter/material.dart';
import 'palette.dart';
class Themes {
static final ThemeData lightTheme = ThemeData(
fontFamily: 'Lato',
brightness: Brightness.light,
backgroundColor: Colors.white,
accentColor: Palette.blueCraiola, // first gradient color
scaffoldBackgroundColor: Palette.pinkFlamingo, // second gradient color
primaryColor: Palette.redHat, // third gradient color
buttonColor: Colors.white.withOpacity(0.2), // action buttons on dashboard page
indicatorColor: Colors.white.withOpacity(0.5), // page indicator
hoverColor: Colors.white, // amount hint text (receive page)
dividerColor: Palette.paleBlue,
hintColor: Palette.gray,
textTheme: TextTheme(
title: TextStyle(
color: Colors.white, // sync_indicator text
backgroundColor: Colors.white.withOpacity(0.2), // synced sync_indicator
decorationColor: Colors.white.withOpacity(0.15), // not synced sync_indicator
),
caption: TextStyle(
color: Palette.shineOrange, // not synced light
decorationColor: Colors.white, // filter icon
),
overline: TextStyle(
color: Colors.white.withOpacity(0.2), // filter button
backgroundColor: Colors.white.withOpacity(0.5), // date section row
decorationColor: Colors.white.withOpacity(0.2) // icons (transaction and trade rows)
),
subhead: TextStyle(
color: Colors.white.withOpacity(0.2), // address button border
decorationColor: Colors.white.withOpacity(0.4), // copy button (qr widget)
),
headline: TextStyle(
color: Colors.white, // qr code
decorationColor: Colors.white.withOpacity(0.5), // bottom border of amount (receive page)
),
display1: TextStyle(
color: PaletteDark.lightBlueGrey, // icons color (receive page)
decorationColor: Palette.lavender, // icons background (receive page)
),
display2: TextStyle(
color: Palette.darkBlueCraiola, // text color of tiles (receive page)
decorationColor: Colors.white // background of tiles (receive page)
),
display3: TextStyle(
color: Colors.white, // text color of current tile (receive page),
//decorationColor: Palette.blueCraiola // background of current tile (receive page)
decorationColor: Palette.moderateSlateBlue // background of current tile (receive page)
),
display4: TextStyle(
color: Palette.violetBlue, // text color of tiles (account list)
decorationColor: Colors.white // background of tiles (account list)
),
subtitle: TextStyle(
color: Palette.moderateSlateBlue, // text color of current tile (account list)
decorationColor: Colors.white // background of current tile (account list)
),
body1: TextStyle(
color: Palette.moderatePurpleBlue, // scrollbar thumb
decorationColor: Palette.periwinkleCraiola // scrollbar background
),
body2: TextStyle(
color: Palette.moderateLavender, // menu header
decorationColor: Colors.white, // menu background
)
),
primaryTextTheme: TextTheme(
title: TextStyle(
color: Palette.darkBlueCraiola, // title color
backgroundColor: Palette.wildPeriwinkle // textfield underline
),
caption: TextStyle(
color: PaletteDark.pigeonBlue, // secondary text
decorationColor: Palette.wildLavender // menu divider
),
overline: TextStyle(
color: Palette.darkGray, // transaction/trade details titles
decorationColor: Colors.white.withOpacity(0.5), // placeholder
),
subhead: TextStyle(
color: Palette.blueCraiola, // first gradient color (send page)
decorationColor: Palette.pinkFlamingo // second gradient color (send page)
),
headline: TextStyle(
color: Colors.white.withOpacity(0.5), // text field border color (send page)
decorationColor: Colors.white.withOpacity(0.5), // text field hint color (send page)
),
display1: TextStyle(
color: Colors.white.withOpacity(0.2), // text field button color (send page)
decorationColor: Colors.white // text field button icon color (send page)
),
display2: TextStyle(
color: Colors.white.withOpacity(0.5), // estimated fee (send page)
decorationColor: Palette.shadowWhite // template dotted border (send page)
),
display3: TextStyle(
color: Palette.darkBlueCraiola, // template new text (send page)
decorationColor: Palette.shadowWhite // template background color (send page)
),
display4: TextStyle(
color: Palette.darkBlueCraiola, // template title (send page)
decorationColor: Palette.niagara // receive amount text (exchange page)
),
subtitle: TextStyle(
color: Palette.blueCraiola, // first gradient color top panel (exchange page)
decorationColor: Palette.pinkFlamingo // second gradient color top panel (exchange page)
),
body1: TextStyle(
color: Palette.blueCraiola.withOpacity(0.7), // first gradient color bottom panel (exchange page)
decorationColor: Palette.pinkFlamingo.withOpacity(0.7) // second gradient color bottom panel (exchange page)
),
body2: TextStyle(
color: Colors.white.withOpacity(0.5), // text field border on top panel (exchange page)
decorationColor: Colors.white.withOpacity(0.5), // text field border on bottom panel (exchange page)
)
),
focusColor: Colors.white.withOpacity(0.2), // text field button (exchange page)
accentTextTheme: TextTheme(
title: TextStyle(
color: Colors.white, // picker background
backgroundColor: Palette.periwinkleCraiola, // picker divider
decorationColor: Colors.white // dialog background
),
caption: TextStyle(
color: Palette.moderateLavender, // container (confirm exchange)
backgroundColor: Palette.moderateLavender, // button background (confirm exchange)
decorationColor: Palette.darkBlueCraiola, // text color (information page)
),
subtitle: TextStyle(
color: Palette.darkBlueCraiola, // QR code (exchange trade page)
backgroundColor: Palette.wildPeriwinkle, // divider (exchange trade page)
//decorationColor: Palette.blueCraiola // crete new wallet button background (wallet list page)
decorationColor: Palette.moderateSlateBlue // crete new wallet button background (wallet list page)
),
headline: TextStyle(
color: Palette.moderateLavender, // first gradient color of wallet action buttons (wallet list page)
backgroundColor: Palette.moderateLavender, // second gradient color of wallet action buttons (wallet list page)
decorationColor: Colors.white // restore wallet button text color (wallet list page)
),
subhead: TextStyle(
color: Palette.darkGray, // titles color (filter widget)
backgroundColor: Palette.periwinkle, // divider color (filter widget)
decorationColor: Colors.white // checkbox background (filter widget)
),
overline: TextStyle(
color: Palette.wildPeriwinkle, // checkbox bounds (filter widget)
decorationColor: Colors.white, // menu subname
),
display1: TextStyle(
color: Palette.blueCraiola, // first gradient color (menu header)
decorationColor: Palette.pinkFlamingo // second gradient color(menu header)
),
display2: TextStyle(
color: Palette.shadowWhite, // action button color (address text field)
decorationColor: Palette.darkGray // hint text (seed widget)
),
display3: TextStyle(
color: Palette.darkGray, // hint text (new wallet page)
decorationColor: Palette.periwinkleCraiola // underline (new wallet page)
),
display4: TextStyle(
color: Palette.darkGray, // switch background (settings page)
),
body1: TextStyle(
color: Palette.darkGray, // indicators (PIN code)
decorationColor: Palette.darkGray // switch (PIN code)
),
body2: TextStyle(
color: Palette.moderateSlateBlue, // primary buttons, alert right buttons
decorationColor: Palette.brightOrange // alert left button
),
),
cardColor: Palette.moderateSlateBlue // bottom button (action list)
);
static final ThemeData darkTheme = ThemeData(
fontFamily: 'Lato',
brightness: Brightness.dark,
backgroundColor: PaletteDark.backgroundColor,
accentColor: PaletteDark.backgroundColor, // first gradient color
scaffoldBackgroundColor: PaletteDark.backgroundColor, // second gradient color
primaryColor: PaletteDark.backgroundColor, // third gradient color
buttonColor: PaletteDark.nightBlue, // action buttons on dashboard page
indicatorColor: PaletteDark.cyanBlue, // page indicator
hoverColor: PaletteDark.cyanBlue, // amount hint text (receive page)
dividerColor: PaletteDark.dividerColor,
hintColor: PaletteDark.pigeonBlue, // menu
textTheme: TextTheme(
title: TextStyle(
color: PaletteDark.wildBlue, // sync_indicator text
backgroundColor: PaletteDark.lightNightBlue, // synced sync_indicator
decorationColor: PaletteDark.oceanBlue // not synced sync_indicator
),
caption: TextStyle(
color: PaletteDark.orangeYellow, // not synced light
decorationColor: PaletteDark.wildBlue, // filter icon
),
overline: TextStyle(
color: PaletteDark.oceanBlue, // filter button
backgroundColor: PaletteDark.darkCyanBlue, // date section row
decorationColor: PaletteDark.wildNightBlue // icons (transaction and trade rows)
),
subhead: TextStyle(
color: PaletteDark.nightBlue, // address button border
decorationColor: PaletteDark.lightBlueGrey, // copy button (qr widget)
),
headline: TextStyle(
color: PaletteDark.lightBlueGrey, // qr code
decorationColor: PaletteDark.darkGrey, // bottom border of amount (receive page)
),
display1: TextStyle(
color: Colors.white, // icons color (receive page)
decorationColor: PaletteDark.distantNightBlue, // icons background (receive page)
),
display2: TextStyle(
color: Colors.white, // text color of tiles (receive page)
decorationColor: PaletteDark.nightBlue // background of tiles (receive page)
),
display3: TextStyle(
color: Palette.blueCraiola, // text color of current tile (receive page)
decorationColor: PaletteDark.lightOceanBlue // background of current tile (receive page)
),
display4: TextStyle(
color: Colors.white, // text color of tiles (account list)
decorationColor: PaletteDark.darkOceanBlue // background of tiles (account list)
),
subtitle: TextStyle(
color: Palette.blueCraiola, // text color of current tile (account list)
decorationColor: PaletteDark.darkNightBlue // background of current tile (account list)
),
body1: TextStyle(
color: PaletteDark.wildBlueGrey, // scrollbar thumb
decorationColor: PaletteDark.violetBlue // scrollbar background
),
body2: TextStyle(
color: PaletteDark.deepPurpleBlue, // menu header
decorationColor: PaletteDark.deepPurpleBlue, // menu background
)
),
primaryTextTheme: TextTheme(
title: TextStyle(
color: Colors.white, // title color
backgroundColor: PaletteDark.darkOceanBlue // textfield underline
),
caption: TextStyle(
color: PaletteDark.darkCyanBlue, // secondary text
decorationColor: PaletteDark.darkOceanBlue // menu divider
),
overline: TextStyle(
color: PaletteDark.lightBlueGrey, // transaction/trade details titles
decorationColor: Colors.grey, // placeholder
),
subhead: TextStyle(
color: PaletteDark.darkNightBlue, // first gradient color (send page)
decorationColor: PaletteDark.darkNightBlue // second gradient color (send page)
),
headline: TextStyle(
color: PaletteDark.lightVioletBlue, // text field border color (send page)
decorationColor: PaletteDark.darkCyanBlue, // text field hint color (send page)
),
display1: TextStyle(
color: PaletteDark.buttonNightBlue, // text field button color (send page)
decorationColor: PaletteDark.gray // text field button icon color (send page)
),
display2: TextStyle(
color: Colors.white, // estimated fee (send page)
decorationColor: PaletteDark.darkCyanBlue // template dotted border (send page)
),
display3: TextStyle(
color: PaletteDark.darkCyanBlue, // template new text (send page)
decorationColor: PaletteDark.darkVioletBlue // template background color (send page)
),
display4: TextStyle(
color: PaletteDark.cyanBlue, // template title (send page)
decorationColor: PaletteDark.darkCyanBlue // receive amount text (exchange page)
),
subtitle: TextStyle(
color: PaletteDark.wildVioletBlue, // first gradient color top panel (exchange page)
decorationColor: PaletteDark.wildVioletBlue // second gradient color top panel (exchange page)
),
body1: TextStyle(
color: PaletteDark.darkNightBlue, // first gradient color bottom panel (exchange page)
decorationColor: PaletteDark.darkNightBlue // second gradient color bottom panel (exchange page)
),
body2: TextStyle(
color: PaletteDark.blueGrey, // text field border on top panel (exchange page)
decorationColor: PaletteDark.moderateVioletBlue, // text field border on bottom panel (exchange page)
)
),
focusColor: PaletteDark.moderateBlue, // text field button (exchange page)
accentTextTheme: TextTheme(
title: TextStyle(
color: PaletteDark.nightBlue, // picker background
backgroundColor: PaletteDark.dividerColor, // picker divider
decorationColor: PaletteDark.darkNightBlue // dialog background
),
caption: TextStyle(
color: PaletteDark.nightBlue, // container (confirm exchange)
backgroundColor: PaletteDark.deepVioletBlue, // button background (confirm exchange)
decorationColor: Palette.darkLavender, // text color (information page)
),
subtitle: TextStyle(
//color: PaletteDark.lightBlueGrey, // QR code (exchange trade page)
color: Colors.white, // QR code (exchange trade page)
backgroundColor: PaletteDark.deepVioletBlue, // divider (exchange trade page)
decorationColor: Colors.white // crete new wallet button background (wallet list page)
),
headline: TextStyle(
color: PaletteDark.distantBlue, // first gradient color of wallet action buttons (wallet list page)
backgroundColor: PaletteDark.distantNightBlue, // second gradient color of wallet action buttons (wallet list page)
decorationColor: Palette.darkBlueCraiola // restore wallet button text color (wallet list page)
),
subhead: TextStyle(
color: Colors.white, // titles color (filter widget)
backgroundColor: PaletteDark.darkOceanBlue, // divider color (filter widget)
decorationColor: PaletteDark.wildVioletBlue.withOpacity(0.3) // checkbox background (filter widget)
),
overline: TextStyle(
color: PaletteDark.wildVioletBlue, // checkbox bounds (filter widget)
decorationColor: PaletteDark.darkCyanBlue, // menu subname
),
display1: TextStyle(
color: PaletteDark.deepPurpleBlue, // first gradient color (menu header)
decorationColor: PaletteDark.deepPurpleBlue // second gradient color(menu header)
),
display2: TextStyle(
color: PaletteDark.nightBlue, // action button color (address text field)
decorationColor: PaletteDark.darkCyanBlue // hint text (seed widget)
),
display3: TextStyle(
color: PaletteDark.cyanBlue, // hint text (new wallet page)
decorationColor: PaletteDark.darkGrey // underline (new wallet page)
),
display4: TextStyle(
color: PaletteDark.deepVioletBlue, // switch background (settings page)
),
body1: TextStyle(
color: PaletteDark.indicatorVioletBlue, // indicators (PIN code)
decorationColor: PaletteDark.lightPurpleBlue // switch (PIN code)
),
body2: TextStyle(
color: Palette.blueCraiola, // primary buttons, alert right buttons
decorationColor: Palette.alizarinRed // alert left button
),
),
cardColor: PaletteDark.darkNightBlue // bottom button (action list)
);
}
+197
View File
@@ -0,0 +1,197 @@
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/palette.dart';
import 'package:flutter/material.dart';
class BrightTheme extends ThemeBase {
BrightTheme({@required int raw}) : super(raw: raw);
@override
String get title => S.current.bright_theme;
@override
ThemeType get type => ThemeType.bright;
@override
ThemeData get themeData => ThemeData(
fontFamily: 'Lato',
brightness: Brightness.light,
backgroundColor: Colors.white,
accentColor: Palette.blueCraiola, // first gradient color
scaffoldBackgroundColor: Palette.pinkFlamingo, // second gradient color
primaryColor: Palette.redHat, // third gradient color
buttonColor: Colors.white.withOpacity(0.2), // action buttons on dashboard page
indicatorColor: Colors.white.withOpacity(0.5), // page indicator
hoverColor: Colors.white, // amount hint text (receive page)
dividerColor: Palette.paleBlue,
hintColor: Palette.gray,
textTheme: TextTheme(
title: TextStyle(
color: Colors.white, // sync_indicator text
backgroundColor: Colors.white.withOpacity(0.2), // synced sync_indicator
decorationColor: Colors.white.withOpacity(0.15), // not synced sync_indicator
),
caption: TextStyle(
color: Palette.shineOrange, // not synced light
decorationColor: Colors.white, // filter icon
),
overline: TextStyle(
color: Colors.white.withOpacity(0.2), // filter button
backgroundColor: Colors.white.withOpacity(0.5), // date section row
decorationColor: Colors.white.withOpacity(0.2) // icons (transaction and trade rows)
),
subhead: TextStyle(
color: Colors.white.withOpacity(0.2), // address button border
decorationColor: Colors.white.withOpacity(0.4), // copy button (qr widget)
),
headline: TextStyle(
color: Colors.white, // qr code
decorationColor: Colors.white.withOpacity(0.5), // bottom border of amount (receive page)
),
display1: TextStyle(
color: PaletteDark.lightBlueGrey, // icons color (receive page)
decorationColor: Palette.lavender, // icons background (receive page)
),
display2: TextStyle(
color: Palette.darkBlueCraiola, // text color of tiles (receive page)
decorationColor: Colors.white // background of tiles (receive page)
),
display3: TextStyle(
color: Colors.white, // text color of current tile (receive page),
//decorationColor: Palette.blueCraiola // background of current tile (receive page)
decorationColor: Palette.moderateSlateBlue // background of current tile (receive page)
),
display4: TextStyle(
color: Palette.violetBlue, // text color of tiles (account list)
decorationColor: Colors.white // background of tiles (account list)
),
subtitle: TextStyle(
color: Palette.moderateSlateBlue, // text color of current tile (account list)
decorationColor: Colors.white // background of current tile (account list)
),
body1: TextStyle(
color: Palette.moderatePurpleBlue, // scrollbar thumb
decorationColor: Palette.periwinkleCraiola // scrollbar background
),
body2: TextStyle(
color: Palette.moderateLavender, // menu header
decorationColor: Colors.white, // menu background
)
),
primaryTextTheme: TextTheme(
title: TextStyle(
color: Palette.darkBlueCraiola, // title color
backgroundColor: Palette.wildPeriwinkle // textfield underline
),
caption: TextStyle(
color: PaletteDark.pigeonBlue, // secondary text
decorationColor: Palette.wildLavender // menu divider
),
overline: TextStyle(
color: Palette.darkGray, // transaction/trade details titles
decorationColor: Colors.white.withOpacity(0.5), // placeholder
),
subhead: TextStyle(
color: Palette.blueCraiola, // first gradient color (send page)
decorationColor: Palette.pinkFlamingo // second gradient color (send page)
),
headline: TextStyle(
color: Colors.white.withOpacity(0.5), // text field border color (send page)
decorationColor: Colors.white.withOpacity(0.5), // text field hint color (send page)
),
display1: TextStyle(
color: Colors.white.withOpacity(0.2), // text field button color (send page)
decorationColor: Colors.white // text field button icon color (send page)
),
display2: TextStyle(
color: Colors.white.withOpacity(0.5), // estimated fee (send page)
decorationColor: Palette.shadowWhite // template dotted border (send page)
),
display3: TextStyle(
color: Palette.darkBlueCraiola, // template new text (send page)
decorationColor: Palette.shadowWhite // template background color (send page)
),
display4: TextStyle(
color: Palette.darkBlueCraiola, // template title (send page)
decorationColor: Palette.niagara // receive amount text (exchange page)
),
subtitle: TextStyle(
color: Palette.blueCraiola, // first gradient color top panel (exchange page)
decorationColor: Palette.pinkFlamingo // second gradient color top panel (exchange page)
),
body1: TextStyle(
color: Palette.blueCraiola.withOpacity(0.7), // first gradient color bottom panel (exchange page)
decorationColor: Palette.pinkFlamingo.withOpacity(0.7), // second gradient color bottom panel (exchange page)
backgroundColor: Palette.moderateSlateBlue // alert right button text
),
body2: TextStyle(
color: Colors.white.withOpacity(0.5), // text field border on top panel (exchange page)
decorationColor: Colors.white.withOpacity(0.5), // text field border on bottom panel (exchange page)
backgroundColor: Palette.brightOrange // alert left button text
)
),
focusColor: Colors.white.withOpacity(0.2), // text field button (exchange page)
accentTextTheme: TextTheme(
title: TextStyle(
color: Colors.white, // picker background
backgroundColor: Palette.periwinkleCraiola, // picker divider
decorationColor: Colors.white // dialog background
),
caption: TextStyle(
color: Palette.moderateLavender, // container (confirm exchange)
backgroundColor: Palette.moderateLavender, // button background (confirm exchange)
decorationColor: Palette.darkBlueCraiola, // text color (information page)
),
subtitle: TextStyle(
color: Palette.darkBlueCraiola, // QR code (exchange trade page)
backgroundColor: Palette.wildPeriwinkle, // divider (exchange trade page)
//decorationColor: Palette.blueCraiola // crete new wallet button background (wallet list page)
decorationColor: Palette.moderateSlateBlue // crete new wallet button background (wallet list page)
),
headline: TextStyle(
color: Palette.moderateLavender, // first gradient color of wallet action buttons (wallet list page)
backgroundColor: Palette.moderateLavender, // second gradient color of wallet action buttons (wallet list page)
decorationColor: Colors.white // restore wallet button text color (wallet list page)
),
subhead: TextStyle(
color: Palette.darkGray, // titles color (filter widget)
backgroundColor: Palette.periwinkle, // divider color (filter widget)
decorationColor: Colors.white // checkbox background (filter widget)
),
overline: TextStyle(
color: Palette.wildPeriwinkle, // checkbox bounds (filter widget)
decorationColor: Colors.white, // menu subname
),
display1: TextStyle(
color: Palette.blueCraiola, // first gradient color (menu header)
decorationColor: Palette.pinkFlamingo, // second gradient color(menu header)
backgroundColor: Colors.white // active dot color
),
display2: TextStyle(
color: Palette.shadowWhite, // action button color (address text field)
decorationColor: Palette.darkGray, // hint text (seed widget)
backgroundColor: Colors.white.withOpacity(0.5) // text on balance page
),
display3: TextStyle(
color: Palette.darkGray, // hint text (new wallet page)
decorationColor: Palette.periwinkleCraiola, // underline (new wallet page)
backgroundColor: Colors.white // menu, icons, balance (dashboard page)
),
display4: TextStyle(
color: Palette.darkGray, // switch background (settings page)
decorationColor: Colors.white.withOpacity(0.4) // hint text (exchange page)
),
body1: TextStyle(
color: Palette.darkGray, // indicators (PIN code)
decorationColor: Palette.darkGray, // switch (PIN code)
backgroundColor: Colors.white // alert right button
),
body2: TextStyle(
color: Palette.moderateSlateBlue, // primary buttons
decorationColor: Colors.white, // alert left button,
backgroundColor: Palette.dullGray // keyboard bar color
),
),
cardColor: Palette.moderateSlateBlue // bottom button (action list)
);
}
+196
View File
@@ -0,0 +1,196 @@
import 'package:cake_wallet/themes/theme_base.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/palette.dart';
import 'package:flutter/material.dart';
class DarkTheme extends ThemeBase {
DarkTheme({@required int raw}) : super(raw: raw);
@override
String get title => S.current.dark_theme;
@override
ThemeType get type => ThemeType.dark;
@override
ThemeData get themeData => ThemeData(
fontFamily: 'Lato',
brightness: Brightness.dark,
backgroundColor: PaletteDark.backgroundColor,
accentColor: PaletteDark.backgroundColor, // first gradient color
scaffoldBackgroundColor: PaletteDark.backgroundColor, // second gradient color
primaryColor: PaletteDark.backgroundColor, // third gradient color
buttonColor: PaletteDark.nightBlue, // action buttons on dashboard page
indicatorColor: PaletteDark.cyanBlue, // page indicator
hoverColor: PaletteDark.cyanBlue, // amount hint text (receive page)
dividerColor: PaletteDark.dividerColor,
hintColor: PaletteDark.pigeonBlue, // menu
textTheme: TextTheme(
title: TextStyle(
color: PaletteDark.wildBlue, // sync_indicator text
backgroundColor: PaletteDark.lightNightBlue, // synced sync_indicator
decorationColor: PaletteDark.oceanBlue // not synced sync_indicator
),
caption: TextStyle(
color: PaletteDark.orangeYellow, // not synced light
decorationColor: PaletteDark.wildBlue, // filter icon
),
overline: TextStyle(
color: PaletteDark.oceanBlue, // filter button
backgroundColor: PaletteDark.darkCyanBlue, // date section row
decorationColor: PaletteDark.wildNightBlue // icons (transaction and trade rows)
),
subhead: TextStyle(
color: PaletteDark.nightBlue, // address button border
decorationColor: PaletteDark.lightBlueGrey, // copy button (qr widget)
),
headline: TextStyle(
color: PaletteDark.lightBlueGrey, // qr code
decorationColor: PaletteDark.darkGrey, // bottom border of amount (receive page)
),
display1: TextStyle(
color: Colors.white, // icons color (receive page)
decorationColor: PaletteDark.distantNightBlue, // icons background (receive page)
),
display2: TextStyle(
color: Colors.white, // text color of tiles (receive page)
decorationColor: PaletteDark.nightBlue // background of tiles (receive page)
),
display3: TextStyle(
color: Palette.blueCraiola, // text color of current tile (receive page)
decorationColor: PaletteDark.lightOceanBlue // background of current tile (receive page)
),
display4: TextStyle(
color: Colors.white, // text color of tiles (account list)
decorationColor: PaletteDark.darkOceanBlue // background of tiles (account list)
),
subtitle: TextStyle(
color: Palette.blueCraiola, // text color of current tile (account list)
decorationColor: PaletteDark.darkNightBlue // background of current tile (account list)
),
body1: TextStyle(
color: PaletteDark.wildBlueGrey, // scrollbar thumb
decorationColor: PaletteDark.violetBlue // scrollbar background
),
body2: TextStyle(
color: PaletteDark.deepPurpleBlue, // menu header
decorationColor: PaletteDark.deepPurpleBlue, // menu background
)
),
primaryTextTheme: TextTheme(
title: TextStyle(
color: Colors.white, // title color
backgroundColor: PaletteDark.darkOceanBlue // textfield underline
),
caption: TextStyle(
color: PaletteDark.darkCyanBlue, // secondary text
decorationColor: PaletteDark.darkOceanBlue // menu divider
),
overline: TextStyle(
color: PaletteDark.lightBlueGrey, // transaction/trade details titles
decorationColor: Colors.grey, // placeholder
),
subhead: TextStyle(
color: PaletteDark.darkNightBlue, // first gradient color (send page)
decorationColor: PaletteDark.darkNightBlue // second gradient color (send page)
),
headline: TextStyle(
color: PaletteDark.lightVioletBlue, // text field border color (send page)
decorationColor: PaletteDark.darkCyanBlue, // text field hint color (send page)
),
display1: TextStyle(
color: PaletteDark.buttonNightBlue, // text field button color (send page)
decorationColor: PaletteDark.gray // text field button icon color (send page)
),
display2: TextStyle(
color: Colors.white, // estimated fee (send page)
decorationColor: PaletteDark.darkCyanBlue // template dotted border (send page)
),
display3: TextStyle(
color: PaletteDark.darkCyanBlue, // template new text (send page)
decorationColor: PaletteDark.darkVioletBlue // template background color (send page)
),
display4: TextStyle(
color: PaletteDark.cyanBlue, // template title (send page)
decorationColor: PaletteDark.darkCyanBlue // receive amount text (exchange page)
),
subtitle: TextStyle(
color: PaletteDark.wildVioletBlue, // first gradient color top panel (exchange page)
decorationColor: PaletteDark.wildVioletBlue // second gradient color top panel (exchange page)
),
body1: TextStyle(
color: PaletteDark.darkNightBlue, // first gradient color bottom panel (exchange page)
decorationColor: PaletteDark.darkNightBlue, // second gradient color bottom panel (exchange page)
backgroundColor: Palette.blueCraiola // alert right button text
),
body2: TextStyle(
color: PaletteDark.blueGrey, // text field border on top panel (exchange page)
decorationColor: PaletteDark.moderateVioletBlue, // text field border on bottom panel (exchange page)
backgroundColor: Palette.alizarinRed // alert left button text
)
),
focusColor: PaletteDark.moderateBlue, // text field button (exchange page)
accentTextTheme: TextTheme(
title: TextStyle(
color: PaletteDark.nightBlue, // picker background
backgroundColor: PaletteDark.dividerColor, // picker divider
decorationColor: PaletteDark.darkNightBlue // dialog background
),
caption: TextStyle(
color: PaletteDark.nightBlue, // container (confirm exchange)
backgroundColor: PaletteDark.deepVioletBlue, // button background (confirm exchange)
decorationColor: Palette.darkLavender, // text color (information page)
),
subtitle: TextStyle(
//color: PaletteDark.lightBlueGrey, // QR code (exchange trade page)
color: Colors.white, // QR code (exchange trade page)
backgroundColor: PaletteDark.deepVioletBlue, // divider (exchange trade page)
decorationColor: Colors.white // crete new wallet button background (wallet list page)
),
headline: TextStyle(
color: PaletteDark.distantBlue, // first gradient color of wallet action buttons (wallet list page)
backgroundColor: PaletteDark.distantNightBlue, // second gradient color of wallet action buttons (wallet list page)
decorationColor: Palette.darkBlueCraiola // restore wallet button text color (wallet list page)
),
subhead: TextStyle(
color: Colors.white, // titles color (filter widget)
backgroundColor: PaletteDark.darkOceanBlue, // divider color (filter widget)
decorationColor: PaletteDark.wildVioletBlue.withOpacity(0.3) // checkbox background (filter widget)
),
overline: TextStyle(
color: PaletteDark.wildVioletBlue, // checkbox bounds (filter widget)
decorationColor: PaletteDark.darkCyanBlue, // menu subname
),
display1: TextStyle(
color: PaletteDark.deepPurpleBlue, // first gradient color (menu header)
decorationColor: PaletteDark.deepPurpleBlue, // second gradient color(menu header)
backgroundColor: Colors.white // active dot color
),
display2: TextStyle(
color: PaletteDark.nightBlue, // action button color (address text field)
decorationColor: PaletteDark.darkCyanBlue, // hint text (seed widget)
backgroundColor: PaletteDark.cyanBlue // text on balance page
),
display3: TextStyle(
color: PaletteDark.cyanBlue, // hint text (new wallet page)
decorationColor: PaletteDark.darkGrey, // underline (new wallet page)
backgroundColor: Colors.white // menu, icons, balance (dashboard page)
),
display4: TextStyle(
color: PaletteDark.deepVioletBlue, // switch background (settings page)
decorationColor: PaletteDark.lightBlueGrey // hint text (exchange page)
),
body1: TextStyle(
color: PaletteDark.indicatorVioletBlue, // indicators (PIN code)
decorationColor: PaletteDark.lightPurpleBlue, // switch (PIN code)
backgroundColor: PaletteDark.darkNightBlue // alert right button
),
body2: TextStyle(
color: Palette.blueCraiola, // primary buttons
decorationColor: PaletteDark.darkNightBlue, // alert left button
backgroundColor: PaletteDark.granite // keyboard bar color
),
),
cardColor: PaletteDark.darkNightBlue // bottom button (action list)
);
}

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