mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-11-17 01:37:40 +00:00
Merge pull request #2 from cake-tech/basic-refactor
Fixed issues for linter and analyzer
This commit is contained in:
commit
9e00a6ee2d
168 changed files with 2274 additions and 1971 deletions
|
@ -5,17 +5,14 @@ analyzer:
|
||||||
implicit-casts: false
|
implicit-casts: false
|
||||||
implicit-dynamic: false
|
implicit-dynamic: false
|
||||||
exclude:
|
exclude:
|
||||||
- **/*.yaml
|
- "build/**"
|
||||||
- build/**
|
- "**/*.g.dart"
|
||||||
- **/*.g.dart
|
- "lib/generated/*.dart"
|
||||||
- lib/generated/*.dart
|
|
||||||
|
|
||||||
linter:
|
linter:
|
||||||
rules:
|
rules:
|
||||||
- always_declare_return_types
|
- always_declare_return_types
|
||||||
- always_specify_types
|
|
||||||
- annotate_overrides
|
- annotate_overrides
|
||||||
- avoid_as
|
|
||||||
- avoid_empty_else
|
- avoid_empty_else
|
||||||
- avoid_init_to_null
|
- avoid_init_to_null
|
||||||
- avoid_return_types_on_setters
|
- avoid_return_types_on_setters
|
||||||
|
@ -48,17 +45,13 @@ linter:
|
||||||
- prefer_final_fields
|
- prefer_final_fields
|
||||||
- prefer_final_locals
|
- prefer_final_locals
|
||||||
- prefer_is_not_empty
|
- prefer_is_not_empty
|
||||||
- public_member_api_docs
|
|
||||||
- slash_for_doc_comments
|
- slash_for_doc_comments
|
||||||
- sort_constructors_first
|
- sort_constructors_first
|
||||||
- sort_unnamed_constructors_first
|
- sort_unnamed_constructors_first
|
||||||
- super_goes_last
|
|
||||||
- test_types_in_equals
|
- test_types_in_equals
|
||||||
- throw_in_finally
|
- throw_in_finally
|
||||||
- type_annotate_public_apis
|
|
||||||
- type_init_formals
|
- type_init_formals
|
||||||
- unawaited_futures
|
- unawaited_futures
|
||||||
- unnecessary_brace_in_string_interp
|
|
||||||
- unnecessary_getters_setters
|
- unnecessary_getters_setters
|
||||||
- unrelated_type_equality_checks
|
- unrelated_type_equality_checks
|
||||||
- valid_regexps
|
- valid_regexps
|
|
@ -26,7 +26,7 @@ final accountSetLabelNative = moneroApi
|
||||||
.lookup<NativeFunction<account_set_label>>('account_set_label_row')
|
.lookup<NativeFunction<account_set_label>>('account_set_label_row')
|
||||||
.asFunction<AccountSetLabel>();
|
.asFunction<AccountSetLabel>();
|
||||||
|
|
||||||
refreshAccounts() => accountRefreshNative();
|
void refreshAccounts() => accountRefreshNative();
|
||||||
|
|
||||||
List<AccountRow> getAllAccount() {
|
List<AccountRow> getAllAccount() {
|
||||||
final size = accountSizeNative();
|
final size = accountSizeNative();
|
||||||
|
@ -38,24 +38,29 @@ List<AccountRow> getAllAccount() {
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
addAccountSync({String label}) {
|
void addAccountSync({String label}) {
|
||||||
final labelPointer = Utf8.toUtf8(label);
|
final labelPointer = Utf8.toUtf8(label);
|
||||||
accountAddNewNative(labelPointer);
|
accountAddNewNative(labelPointer);
|
||||||
free(labelPointer);
|
free(labelPointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
setLabelForAccountSync({int accountIndex, String label}) {
|
void setLabelForAccountSync({int accountIndex, String label}) {
|
||||||
final labelPointer = Utf8.toUtf8(label);
|
final labelPointer = Utf8.toUtf8(label);
|
||||||
accountSetLabelNative(accountIndex, labelPointer);
|
accountSetLabelNative(accountIndex, labelPointer);
|
||||||
free(labelPointer);
|
free(labelPointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
_addAccount(String label) => addAccountSync(label: label);
|
void _addAccount(String label) => addAccountSync(label: label);
|
||||||
|
|
||||||
_setLabelForAccount(Map args) => setLabelForAccountSync(
|
void _setLabelForAccount(Map<String, dynamic> args) {
|
||||||
label: args['label'], accountIndex: args['accountIndex']);
|
final label = args['label'] as String;
|
||||||
|
final accountIndex = args['accountIndex'] as int;
|
||||||
|
|
||||||
Future addAccount({String label}) async => compute(_addAccount, label);
|
setLabelForAccountSync(label: label, accountIndex: accountIndex);
|
||||||
|
}
|
||||||
|
|
||||||
Future setLabelForAccount({int accountIndex, String label}) async => compute(
|
Future<void> addAccount({String label}) async => compute(_addAccount, label);
|
||||||
|
|
||||||
|
Future<void> setLabelForAccount({int accountIndex, String label}) async =>
|
||||||
|
compute(
|
||||||
_setLabelForAccount, {'accountIndex': accountIndex, 'label': label});
|
_setLabelForAccount, {'accountIndex': accountIndex, 'label': label});
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
class ConnectionToNodeException implements Exception {
|
class ConnectionToNodeException implements Exception {
|
||||||
final String message;
|
|
||||||
|
|
||||||
ConnectionToNodeException({this.message});
|
ConnectionToNodeException({this.message});
|
||||||
|
|
||||||
|
final String message;
|
||||||
}
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
class CreationTransactionException implements Exception {
|
class CreationTransactionException implements Exception {
|
||||||
final String message;
|
|
||||||
|
|
||||||
CreationTransactionException({this.message});
|
CreationTransactionException({this.message});
|
||||||
|
|
||||||
|
final String message;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => message;
|
String toString() => message;
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
class SetupWalletException implements Exception {
|
class SetupWalletException implements Exception {
|
||||||
final String message;
|
|
||||||
|
|
||||||
SetupWalletException({this.message});
|
SetupWalletException({this.message});
|
||||||
|
|
||||||
|
final String message;
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
class WalletCreationException implements Exception {
|
class WalletCreationException implements Exception {
|
||||||
final String message;
|
|
||||||
|
|
||||||
WalletCreationException({this.message});
|
WalletCreationException({this.message});
|
||||||
|
|
||||||
|
final String message;
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
class WalletRestoreFromKeysException implements Exception {
|
class WalletRestoreFromKeysException implements Exception {
|
||||||
final String message;
|
|
||||||
|
|
||||||
WalletRestoreFromKeysException({this.message});
|
WalletRestoreFromKeysException({this.message});
|
||||||
|
|
||||||
|
final String message;
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
class WalletRestoreFromSeedException implements Exception {
|
class WalletRestoreFromSeedException implements Exception {
|
||||||
final String message;
|
|
||||||
|
|
||||||
WalletRestoreFromSeedException({this.message});
|
WalletRestoreFromSeedException({this.message});
|
||||||
|
|
||||||
|
final String message;
|
||||||
}
|
}
|
|
@ -14,10 +14,10 @@ class PendingTransactionRaw extends Struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
class PendingTransactionDescription {
|
class PendingTransactionDescription {
|
||||||
|
PendingTransactionDescription({this.amount, this.fee, this.hash, this.pointerAddress});
|
||||||
|
|
||||||
final int amount;
|
final int amount;
|
||||||
final int fee;
|
final int fee;
|
||||||
final String hash;
|
final String hash;
|
||||||
final int pointerAddress;
|
final int pointerAddress;
|
||||||
|
|
||||||
PendingTransactionDescription({this.amount, this.fee, this.hash, this.pointerAddress});
|
|
||||||
}
|
}
|
|
@ -26,7 +26,7 @@ final subaddrressSetLabelNative = moneroApi
|
||||||
.lookup<NativeFunction<subaddress_set_label>>('subaddress_set_label')
|
.lookup<NativeFunction<subaddress_set_label>>('subaddress_set_label')
|
||||||
.asFunction<SubaddressSetLabel>();
|
.asFunction<SubaddressSetLabel>();
|
||||||
|
|
||||||
refreshSubaddresses({int accountIndex}) =>
|
void refreshSubaddresses({int accountIndex}) =>
|
||||||
subaddressRefreshNative(accountIndex);
|
subaddressRefreshNative(accountIndex);
|
||||||
|
|
||||||
List<SubaddressRow> getAllSubaddresses() {
|
List<SubaddressRow> getAllSubaddresses() {
|
||||||
|
@ -40,25 +40,35 @@ List<SubaddressRow> getAllSubaddresses() {
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
addSubaddressSync({int accountIndex, String label}) {
|
void addSubaddressSync({int accountIndex, String label}) {
|
||||||
final labelPointer = Utf8.toUtf8(label);
|
final labelPointer = Utf8.toUtf8(label);
|
||||||
subaddrressAddNewNative(accountIndex, labelPointer);
|
subaddrressAddNewNative(accountIndex, labelPointer);
|
||||||
free(labelPointer);
|
free(labelPointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
setLabelForSubaddressSync({int accountIndex, int addressIndex, String label}) {
|
void setLabelForSubaddressSync(
|
||||||
|
{int accountIndex, int addressIndex, String label}) {
|
||||||
final labelPointer = Utf8.toUtf8(label);
|
final labelPointer = Utf8.toUtf8(label);
|
||||||
|
|
||||||
subaddrressSetLabelNative(accountIndex, addressIndex, labelPointer);
|
subaddrressSetLabelNative(accountIndex, addressIndex, labelPointer);
|
||||||
free(labelPointer);
|
free(labelPointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
_addSubaddress(Map args) =>
|
void _addSubaddress(Map<String, dynamic> args) {
|
||||||
addSubaddressSync(accountIndex: args['accountIndex'], label: args['label']);
|
final label = args['label'] as String;
|
||||||
|
final accountIndex = args['accountIndex'] as int;
|
||||||
|
|
||||||
_setLabelForSubaddress(Map args) => setLabelForSubaddressSync(
|
addSubaddressSync(accountIndex: accountIndex, label: label);
|
||||||
accountIndex: args['accountIndex'],
|
}
|
||||||
addressIndex: args['addressIndex'],
|
|
||||||
label: args['label']);
|
void _setLabelForSubaddress(Map<String, dynamic> args) {
|
||||||
|
final label = args['label'] as String;
|
||||||
|
final accountIndex = args['accountIndex'] as int;
|
||||||
|
final addressIndex = args['addressIndex'] as int;
|
||||||
|
|
||||||
|
setLabelForSubaddressSync(
|
||||||
|
accountIndex: accountIndex, addressIndex: addressIndex, label: label);
|
||||||
|
}
|
||||||
|
|
||||||
Future addSubaddress({int accountIndex, String label}) async =>
|
Future addSubaddress({int accountIndex, String label}) async =>
|
||||||
compute(_addSubaddress, {'accountIndex': accountIndex, 'label': label});
|
compute(_addSubaddress, {'accountIndex': accountIndex, 'label': label});
|
||||||
|
|
|
@ -29,7 +29,7 @@ final transactionCommitNative = moneroApi
|
||||||
.lookup<NativeFunction<transaction_commit>>('transaction_commit')
|
.lookup<NativeFunction<transaction_commit>>('transaction_commit')
|
||||||
.asFunction<TransactionCommit>();
|
.asFunction<TransactionCommit>();
|
||||||
|
|
||||||
refreshTransactions() => transactionsRefreshNative();
|
void refreshTransactions() => transactionsRefreshNative();
|
||||||
|
|
||||||
int countOfTransactions() => transactionsCountNative();
|
int countOfTransactions() => transactionsCountNative();
|
||||||
|
|
||||||
|
@ -84,10 +84,10 @@ PendingTransactionDescription createTransactionSync(
|
||||||
pointerAddress: pendingTransactionRawPointer.address);
|
pointerAddress: pendingTransactionRawPointer.address);
|
||||||
}
|
}
|
||||||
|
|
||||||
commitTransactionFromPointerAddress({int address}) => commitTransaction(
|
void commitTransactionFromPointerAddress({int address}) => commitTransaction(
|
||||||
transactionPointer: Pointer<PendingTransactionRaw>.fromAddress(address));
|
transactionPointer: Pointer<PendingTransactionRaw>.fromAddress(address));
|
||||||
|
|
||||||
commitTransaction({Pointer<PendingTransactionRaw> transactionPointer}) {
|
void commitTransaction({Pointer<PendingTransactionRaw> transactionPointer}) {
|
||||||
final errorMessagePointer = allocate<Utf8Box>();
|
final errorMessagePointer = allocate<Utf8Box>();
|
||||||
final isCommited =
|
final isCommited =
|
||||||
transactionCommitNative(transactionPointer, errorMessagePointer) != 0;
|
transactionCommitNative(transactionPointer, errorMessagePointer) != 0;
|
||||||
|
@ -99,13 +99,20 @@ commitTransaction({Pointer<PendingTransactionRaw> transactionPointer}) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PendingTransactionDescription _createTransactionSync(Map args) =>
|
PendingTransactionDescription _createTransactionSync(Map args) {
|
||||||
createTransactionSync(
|
final address = args['address'] as String;
|
||||||
address: args['address'],
|
final paymentId = args['paymentId'] as String;
|
||||||
paymentId: args['paymentId'],
|
final amount = args['amount'] as String;
|
||||||
amount: args['amount'],
|
final priorityRaw = args['priorityRaw'] as int;
|
||||||
priorityRaw: args['priorityRaw'],
|
final accountIndex = args['accountIndex'] as int;
|
||||||
accountIndex: args['accountIndex']);
|
|
||||||
|
return createTransactionSync(
|
||||||
|
address: address,
|
||||||
|
paymentId: paymentId,
|
||||||
|
amount: amount,
|
||||||
|
priorityRaw: priorityRaw,
|
||||||
|
accountIndex: accountIndex);
|
||||||
|
}
|
||||||
|
|
||||||
Future<PendingTransactionDescription> createTransaction(
|
Future<PendingTransactionDescription> createTransaction(
|
||||||
{String address,
|
{String address,
|
||||||
|
|
|
@ -179,23 +179,23 @@ bool setupNodeSync(
|
||||||
return isSetupNode;
|
return isSetupNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
startRefreshSync() => startRefreshNative();
|
void startRefreshSync() => startRefreshNative();
|
||||||
|
|
||||||
Future<bool> connectToNode() async => connecToNodeNative() != 0;
|
Future<bool> connectToNode() async => connecToNodeNative() != 0;
|
||||||
|
|
||||||
setRefreshFromBlockHeight({int height}) =>
|
void setRefreshFromBlockHeight({int height}) =>
|
||||||
setRefreshFromBlockHeightNative(height);
|
setRefreshFromBlockHeightNative(height);
|
||||||
|
|
||||||
setRecoveringFromSeed({bool isRecovery}) =>
|
void setRecoveringFromSeed({bool isRecovery}) =>
|
||||||
setRecoveringFromSeedNative(_boolToInt(isRecovery));
|
setRecoveringFromSeedNative(_boolToInt(isRecovery));
|
||||||
|
|
||||||
storeSync() {
|
void storeSync() {
|
||||||
final pathPointer = Utf8.toUtf8('');
|
final pathPointer = Utf8.toUtf8('');
|
||||||
storeNative(pathPointer);
|
storeNative(pathPointer);
|
||||||
free(pathPointer);
|
free(pathPointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
closeCurrentWallet() => closeCurrentWalletNative();
|
void closeCurrentWallet() => closeCurrentWalletNative();
|
||||||
|
|
||||||
String getSecretViewKey() =>
|
String getSecretViewKey() =>
|
||||||
convertUTF8ToString(pointer: getSecretViewKeyNative());
|
convertUTF8ToString(pointer: getSecretViewKeyNative());
|
||||||
|
@ -213,8 +213,8 @@ Timer _updateSyncInfoTimer;
|
||||||
|
|
||||||
int _lastKnownBlockHeight = 0;
|
int _lastKnownBlockHeight = 0;
|
||||||
|
|
||||||
setListeners(Future Function(int) onNewBlock, Future Function() onNeedToRefresh,
|
void setListeners(Future Function(int) onNewBlock,
|
||||||
Future Function() onNewTransaction) {
|
Future Function() onNeedToRefresh, Future Function() onNewTransaction) {
|
||||||
if (_updateSyncInfoTimer != null) {
|
if (_updateSyncInfoTimer != null) {
|
||||||
_updateSyncInfoTimer.cancel();
|
_updateSyncInfoTimer.cancel();
|
||||||
}
|
}
|
||||||
|
@ -240,25 +240,36 @@ setListeners(Future Function(int) onNewBlock, Future Function() onNeedToRefresh,
|
||||||
setListenerNative();
|
setListenerNative();
|
||||||
}
|
}
|
||||||
|
|
||||||
closeListeners() {
|
void closeListeners() {
|
||||||
if (_updateSyncInfoTimer != null) {
|
if (_updateSyncInfoTimer != null) {
|
||||||
_updateSyncInfoTimer.cancel();
|
_updateSyncInfoTimer.cancel();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onStartup() => onStartupNative();
|
void onStartup() => onStartupNative();
|
||||||
|
|
||||||
_storeSync(_) => storeSync();
|
void _storeSync(Object _) => storeSync();
|
||||||
bool _setupNodeSync(Map args) => setupNodeSync(
|
|
||||||
address: args['address'],
|
|
||||||
login: args['login'] ?? '',
|
|
||||||
password: args['password'] ?? '',
|
|
||||||
useSSL: args['useSSL'],
|
|
||||||
isLightWallet: args['isLightWallet']);
|
|
||||||
bool _isConnected(_) => isConnectedSync();
|
|
||||||
int _getNodeHeight(_) => getNodeHeightSync();
|
|
||||||
|
|
||||||
startRefresh() => startRefreshSync();
|
bool _setupNodeSync(Map args) {
|
||||||
|
final address = args['address'] as String;
|
||||||
|
final login = (args['login'] ?? '') as String;
|
||||||
|
final password = (args['password'] ?? '') as String;
|
||||||
|
final useSSL = args['useSSL'] as bool;
|
||||||
|
final isLightWallet = args['isLightWallet'] as bool;
|
||||||
|
|
||||||
|
return setupNodeSync(
|
||||||
|
address: address,
|
||||||
|
login: login,
|
||||||
|
password: password,
|
||||||
|
useSSL: useSSL,
|
||||||
|
isLightWallet: isLightWallet);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _isConnected(Object _) => isConnectedSync();
|
||||||
|
|
||||||
|
int _getNodeHeight(Object _) => getNodeHeightSync();
|
||||||
|
|
||||||
|
void startRefresh() => startRefreshSync();
|
||||||
|
|
||||||
Future setupNode(
|
Future setupNode(
|
||||||
{String address,
|
{String address,
|
||||||
|
@ -280,4 +291,4 @@ Future<bool> isConnected() => compute(_isConnected, 0);
|
||||||
|
|
||||||
Future<int> getNodeHeight() => compute(_getNodeHeight, 0);
|
Future<int> getNodeHeight() => compute(_getNodeHeight, 0);
|
||||||
|
|
||||||
rescanBlockchainAsync() => rescanBlockchainAsyncNative();
|
void rescanBlockchainAsync() => rescanBlockchainAsyncNative();
|
||||||
|
|
|
@ -31,7 +31,7 @@ final loadWalletNative = moneroApi
|
||||||
.lookup<NativeFunction<load_wallet>>('load_wallet')
|
.lookup<NativeFunction<load_wallet>>('load_wallet')
|
||||||
.asFunction<LoadWallet>();
|
.asFunction<LoadWallet>();
|
||||||
|
|
||||||
createWalletSync(
|
void createWalletSync(
|
||||||
{String path,
|
{String path,
|
||||||
String password,
|
String password,
|
||||||
String language = 'English',
|
String language = 'English',
|
||||||
|
@ -63,7 +63,7 @@ bool isWalletExistSync({String path}) {
|
||||||
return isExist;
|
return isExist;
|
||||||
}
|
}
|
||||||
|
|
||||||
restoreWalletFromSeedSync(
|
void restoreWalletFromSeedSync(
|
||||||
{String path,
|
{String path,
|
||||||
String password,
|
String password,
|
||||||
String seed,
|
String seed,
|
||||||
|
@ -92,7 +92,7 @@ restoreWalletFromSeedSync(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
restoreWalletFromKeysSync(
|
void restoreWalletFromKeysSync(
|
||||||
{String path,
|
{String path,
|
||||||
String password,
|
String password,
|
||||||
String language = 'English',
|
String language = 'English',
|
||||||
|
@ -133,7 +133,7 @@ restoreWalletFromKeysSync(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadWallet({String path, String password, int nettype = 0}) {
|
void loadWallet({String path, String password, int nettype = 0}) {
|
||||||
final pathPointer = Utf8.toUtf8(path);
|
final pathPointer = Utf8.toUtf8(path);
|
||||||
final passwordPointer = Utf8.toUtf8(password);
|
final passwordPointer = Utf8.toUtf8(password);
|
||||||
|
|
||||||
|
@ -142,34 +142,52 @@ loadWallet({String path, String password, int nettype = 0}) {
|
||||||
free(passwordPointer);
|
free(passwordPointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
_createWallet(args) =>
|
void _createWallet(Map<String, dynamic> args) {
|
||||||
createWalletSync(path: args['path'], password: args['password']);
|
final path = args['path'] as String;
|
||||||
|
final password = args['password'] as String;
|
||||||
|
|
||||||
_restoreFromSeed(args) => restoreWalletFromSeedSync(
|
createWalletSync(path: path, password: password);
|
||||||
path: args['path'],
|
}
|
||||||
password: args['password'],
|
|
||||||
seed: args['seed'],
|
|
||||||
restoreHeight: args['restoreHeight']);
|
|
||||||
|
|
||||||
_restoreFromKeys(args) => restoreWalletFromKeysSync(
|
void _restoreFromSeed(Map<String, dynamic> args) {
|
||||||
path: args['path'],
|
final path = args['path'] as String;
|
||||||
password: args['password'],
|
final password = args['password'] as String;
|
||||||
restoreHeight: args['restoreHeight'],
|
final seed = args['seed'] as String;
|
||||||
address: args['address'],
|
final restoreHeight = args['restoreHeight'] as int;
|
||||||
viewKey: args['viewKey'],
|
|
||||||
spendKey: args['spendKey']);
|
|
||||||
|
|
||||||
_openWallet(Map args) async =>
|
restoreWalletFromSeedSync(
|
||||||
|
path: path, password: password, seed: seed, restoreHeight: restoreHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _restoreFromKeys(Map<String, dynamic> args) {
|
||||||
|
final path = args['path'] as String;
|
||||||
|
final password = args['password'] as String;
|
||||||
|
final restoreHeight = args['restoreHeight'] as int;
|
||||||
|
final address = args['address'] as String;
|
||||||
|
final viewKey = args['viewKey'] as String;
|
||||||
|
final spendKey = args['spendKey'] as String;
|
||||||
|
|
||||||
|
restoreWalletFromKeysSync(
|
||||||
|
path: path,
|
||||||
|
password: password,
|
||||||
|
restoreHeight: restoreHeight,
|
||||||
|
address: address,
|
||||||
|
viewKey: viewKey,
|
||||||
|
spendKey: spendKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _openWallet(Map<String, String> args) async =>
|
||||||
loadWallet(path: args['path'], password: args['password']);
|
loadWallet(path: args['path'], password: args['password']);
|
||||||
|
|
||||||
bool _isWalletExist(String path) => isWalletExistSync(path: path);
|
bool _isWalletExist(String path) => isWalletExistSync(path: path);
|
||||||
|
|
||||||
openWallet({String path, String password, int nettype = 0}) async =>
|
void openWallet({String path, String password, int nettype = 0}) async =>
|
||||||
loadWallet(path: path, password: password);
|
loadWallet(path: path, password: password);
|
||||||
|
|
||||||
Future openWalletAsync(Map args) async => compute(_openWallet, args);
|
Future<void> openWalletAsync(Map<String, String> args) async =>
|
||||||
|
compute(_openWallet, args);
|
||||||
|
|
||||||
Future createWallet(
|
Future<void> createWallet(
|
||||||
{String path,
|
{String path,
|
||||||
String password,
|
String password,
|
||||||
String language = 'English',
|
String language = 'English',
|
||||||
|
|
|
@ -6,7 +6,7 @@ import 'package:provider/provider.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:cw_monero/wallet.dart' as moneroWallet;
|
import 'package:cw_monero/wallet.dart' as monero_wallet;
|
||||||
import 'package:cake_wallet/router.dart';
|
import 'package:cake_wallet/router.dart';
|
||||||
import 'theme_changer.dart';
|
import 'theme_changer.dart';
|
||||||
import 'themes.dart';
|
import 'themes.dart';
|
||||||
|
@ -39,7 +39,7 @@ import 'package:cake_wallet/src/domain/common/language.dart';
|
||||||
void main() async {
|
void main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
var appDir = await getApplicationDocumentsDirectory();
|
final appDir = await getApplicationDocumentsDirectory();
|
||||||
Hive.init(appDir.path);
|
Hive.init(appDir.path);
|
||||||
Hive.registerAdapter(ContactAdapter(), 0);
|
Hive.registerAdapter(ContactAdapter(), 0);
|
||||||
Hive.registerAdapter(NodeAdapter(), 1);
|
Hive.registerAdapter(NodeAdapter(), 1);
|
||||||
|
@ -50,18 +50,20 @@ void main() async {
|
||||||
|
|
||||||
final secureStorage = FlutterSecureStorage();
|
final secureStorage = FlutterSecureStorage();
|
||||||
final transactionDescriptionsBoxKey = await getEncryptionKey(
|
final transactionDescriptionsBoxKey = await getEncryptionKey(
|
||||||
secureStorage: secureStorage, forKey: 'transactionDescriptionsBoxKey'); // FIXME: Unnamed constant
|
secureStorage: secureStorage,
|
||||||
|
forKey: 'transactionDescriptionsBoxKey'); // FIXME: Unnamed constant
|
||||||
final tradesBoxKey = await getEncryptionKey(
|
final tradesBoxKey = await getEncryptionKey(
|
||||||
secureStorage: secureStorage, forKey: 'tradesBoxKey'); // FIXME: Unnamed constant
|
secureStorage: secureStorage,
|
||||||
|
forKey: 'tradesBoxKey'); // FIXME: Unnamed constant
|
||||||
|
|
||||||
var contacts = await Hive.openBox<Contact>(Contact.boxName);
|
final contacts = await Hive.openBox<Contact>(Contact.boxName);
|
||||||
var nodes = await Hive.openBox<Node>(Node.boxName);
|
final nodes = await Hive.openBox<Node>(Node.boxName);
|
||||||
var transactionDescriptions = await Hive.openBox<TransactionDescription>(
|
final transactionDescriptions = await Hive.openBox<TransactionDescription>(
|
||||||
TransactionDescription.boxName,
|
TransactionDescription.boxName,
|
||||||
encryptionKey: transactionDescriptionsBoxKey);
|
encryptionKey: transactionDescriptionsBoxKey);
|
||||||
var trades =
|
final trades =
|
||||||
await Hive.openBox<Trade>(Trade.boxName, encryptionKey: tradesBoxKey);
|
await Hive.openBox<Trade>(Trade.boxName, encryptionKey: tradesBoxKey);
|
||||||
var walletInfoSource = await Hive.openBox<WalletInfo>(WalletInfo.boxName);
|
final walletInfoSource = await Hive.openBox<WalletInfo>(WalletInfo.boxName);
|
||||||
|
|
||||||
final sharedPreferences = await SharedPreferences.getInstance();
|
final sharedPreferences = await SharedPreferences.getInstance();
|
||||||
final walletService = WalletService();
|
final walletService = WalletService();
|
||||||
|
@ -124,7 +126,7 @@ void main() async {
|
||||||
], child: CakeWalletApp()));
|
], child: CakeWalletApp()));
|
||||||
}
|
}
|
||||||
|
|
||||||
initialSetup(
|
Future<void> initialSetup(
|
||||||
{WalletListService walletListService,
|
{WalletListService walletListService,
|
||||||
SharedPreferences sharedPreferences,
|
SharedPreferences sharedPreferences,
|
||||||
Box<Node> nodes,
|
Box<Node> nodes,
|
||||||
|
@ -137,7 +139,7 @@ initialSetup(
|
||||||
sharedPreferences: sharedPreferences,
|
sharedPreferences: sharedPreferences,
|
||||||
nodes: nodes);
|
nodes: nodes);
|
||||||
await authStore.started();
|
await authStore.started();
|
||||||
moneroWallet.onStartup();
|
monero_wallet.onStartup();
|
||||||
}
|
}
|
||||||
|
|
||||||
class CakeWalletApp extends StatelessWidget {
|
class CakeWalletApp extends StatelessWidget {
|
||||||
|
|
117
lib/router.dart
117
lib/router.dart
|
@ -19,6 +19,10 @@ import 'package:cake_wallet/src/domain/exchange/xmrto/xmrto_exchange_provider.da
|
||||||
import 'package:cake_wallet/src/domain/common/node.dart';
|
import 'package:cake_wallet/src/domain/common/node.dart';
|
||||||
import 'package:cake_wallet/src/domain/monero/transaction_description.dart';
|
import 'package:cake_wallet/src/domain/monero/transaction_description.dart';
|
||||||
import 'package:cake_wallet/src/domain/exchange/trade.dart';
|
import 'package:cake_wallet/src/domain/exchange/trade.dart';
|
||||||
|
import 'package:cake_wallet/src/domain/monero/account.dart';
|
||||||
|
import 'package:cake_wallet/src/domain/common/mnemotic_item.dart';
|
||||||
|
import 'package:cake_wallet/src/domain/common/transaction_info.dart';
|
||||||
|
import 'package:cake_wallet/src/domain/monero/subaddress.dart';
|
||||||
|
|
||||||
// MARK: Import stores
|
// MARK: Import stores
|
||||||
|
|
||||||
|
@ -101,10 +105,10 @@ class Router {
|
||||||
Box<Trade> trades}) {
|
Box<Trade> trades}) {
|
||||||
switch (settings.name) {
|
switch (settings.name) {
|
||||||
case Routes.welcome:
|
case Routes.welcome:
|
||||||
return MaterialPageRoute(builder: (_) => createWelcomePage());
|
return MaterialPageRoute<void>(builder: (_) => createWelcomePage());
|
||||||
|
|
||||||
case Routes.newWalletFromWelcome:
|
case Routes.newWalletFromWelcome:
|
||||||
return CupertinoPageRoute(
|
return CupertinoPageRoute<void>(
|
||||||
builder: (_) => Provider(
|
builder: (_) => Provider(
|
||||||
create: (_) => UserStore(
|
create: (_) => UserStore(
|
||||||
accountService: UserService(
|
accountService: UserService(
|
||||||
|
@ -115,7 +119,7 @@ class Router {
|
||||||
Navigator.pushNamed(context, Routes.newWallet))));
|
Navigator.pushNamed(context, Routes.newWallet))));
|
||||||
|
|
||||||
case Routes.newWallet:
|
case Routes.newWallet:
|
||||||
return CupertinoPageRoute(
|
return CupertinoPageRoute<void>(
|
||||||
builder:
|
builder:
|
||||||
(_) =>
|
(_) =>
|
||||||
ProxyProvider<AuthenticationStore, WalletCreationStore>(
|
ProxyProvider<AuthenticationStore, WalletCreationStore>(
|
||||||
|
@ -132,10 +136,10 @@ class Router {
|
||||||
Function(BuildContext, String) callback;
|
Function(BuildContext, String) callback;
|
||||||
|
|
||||||
if (settings.arguments is Function(BuildContext, String)) {
|
if (settings.arguments is Function(BuildContext, String)) {
|
||||||
callback = settings.arguments;
|
callback = settings.arguments as Function(BuildContext, String);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CupertinoPageRoute(
|
return CupertinoPageRoute<void>(
|
||||||
builder: (_) => Provider(
|
builder: (_) => Provider(
|
||||||
create: (_) => UserStore(
|
create: (_) => UserStore(
|
||||||
accountService: UserService(
|
accountService: UserService(
|
||||||
|
@ -147,13 +151,14 @@ class Router {
|
||||||
fullscreenDialog: true);
|
fullscreenDialog: true);
|
||||||
|
|
||||||
case Routes.restoreOptions:
|
case Routes.restoreOptions:
|
||||||
return CupertinoPageRoute(builder: (_) => RestoreOptionsPage());
|
return CupertinoPageRoute<void>(builder: (_) => RestoreOptionsPage());
|
||||||
|
|
||||||
case Routes.restoreWalletOptions:
|
case Routes.restoreWalletOptions:
|
||||||
return CupertinoPageRoute(builder: (_) => RestoreWalletOptionsPage());
|
return CupertinoPageRoute<void>(
|
||||||
|
builder: (_) => RestoreWalletOptionsPage());
|
||||||
|
|
||||||
case Routes.restoreWalletOptionsFromWelcome:
|
case Routes.restoreWalletOptionsFromWelcome:
|
||||||
return CupertinoPageRoute(
|
return CupertinoPageRoute<void>(
|
||||||
builder: (_) => Provider(
|
builder: (_) => Provider(
|
||||||
create: (_) => UserStore(
|
create: (_) => UserStore(
|
||||||
accountService: UserService(
|
accountService: UserService(
|
||||||
|
@ -164,14 +169,14 @@ class Router {
|
||||||
context, Routes.restoreWalletOptions))));
|
context, Routes.restoreWalletOptions))));
|
||||||
|
|
||||||
case Routes.seed:
|
case Routes.seed:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute<void>(
|
||||||
builder: (_) => createSeedPage(
|
builder: (_) => createSeedPage(
|
||||||
settingsStore: settingsStore,
|
settingsStore: settingsStore,
|
||||||
walletService: walletService,
|
walletService: walletService,
|
||||||
callback: settings.arguments));
|
callback: settings.arguments as void Function()));
|
||||||
|
|
||||||
case Routes.restoreWalletFromSeed:
|
case Routes.restoreWalletFromSeed:
|
||||||
return CupertinoPageRoute(
|
return CupertinoPageRoute<void>(
|
||||||
builder: (_) =>
|
builder: (_) =>
|
||||||
ProxyProvider<AuthenticationStore, WalletRestorationStore>(
|
ProxyProvider<AuthenticationStore, WalletRestorationStore>(
|
||||||
update: (_, authStore, __) => WalletRestorationStore(
|
update: (_, authStore, __) => WalletRestorationStore(
|
||||||
|
@ -184,7 +189,7 @@ class Router {
|
||||||
sharedPreferences: sharedPreferences)));
|
sharedPreferences: sharedPreferences)));
|
||||||
|
|
||||||
case Routes.restoreWalletFromKeys:
|
case Routes.restoreWalletFromKeys:
|
||||||
return CupertinoPageRoute(
|
return CupertinoPageRoute<void>(
|
||||||
builder: (_) =>
|
builder: (_) =>
|
||||||
ProxyProvider<AuthenticationStore, WalletRestorationStore>(
|
ProxyProvider<AuthenticationStore, WalletRestorationStore>(
|
||||||
update: (_, authStore, __) => WalletRestorationStore(
|
update: (_, authStore, __) => WalletRestorationStore(
|
||||||
|
@ -197,7 +202,7 @@ class Router {
|
||||||
sharedPreferences: sharedPreferences)));
|
sharedPreferences: sharedPreferences)));
|
||||||
|
|
||||||
case Routes.dashboard:
|
case Routes.dashboard:
|
||||||
return CupertinoPageRoute(
|
return CupertinoPageRoute<void>(
|
||||||
builder: (_) => createDashboardPage(
|
builder: (_) => createDashboardPage(
|
||||||
walletService: walletService,
|
walletService: walletService,
|
||||||
priceStore: priceStore,
|
priceStore: priceStore,
|
||||||
|
@ -207,7 +212,7 @@ class Router {
|
||||||
walletStore: walletStore));
|
walletStore: walletStore));
|
||||||
|
|
||||||
case Routes.send:
|
case Routes.send:
|
||||||
return CupertinoPageRoute(
|
return CupertinoPageRoute<void>(
|
||||||
fullscreenDialog: true,
|
fullscreenDialog: true,
|
||||||
builder: (_) => MultiProvider(providers: [
|
builder: (_) => MultiProvider(providers: [
|
||||||
ProxyProvider<SettingsStore, BalanceStore>(
|
ProxyProvider<SettingsStore, BalanceStore>(
|
||||||
|
@ -227,7 +232,7 @@ class Router {
|
||||||
], child: SendPage()));
|
], child: SendPage()));
|
||||||
|
|
||||||
case Routes.receive:
|
case Routes.receive:
|
||||||
return CupertinoPageRoute(
|
return CupertinoPageRoute<void>(
|
||||||
fullscreenDialog: true,
|
fullscreenDialog: true,
|
||||||
builder: (_) => MultiProvider(providers: [
|
builder: (_) => MultiProvider(providers: [
|
||||||
Provider(
|
Provider(
|
||||||
|
@ -236,30 +241,30 @@ class Router {
|
||||||
], child: ReceivePage()));
|
], child: ReceivePage()));
|
||||||
|
|
||||||
case Routes.transactionDetails:
|
case Routes.transactionDetails:
|
||||||
return CupertinoPageRoute(
|
return CupertinoPageRoute<void>(
|
||||||
fullscreenDialog: true,
|
fullscreenDialog: true,
|
||||||
builder: (_) =>
|
builder: (_) => TransactionDetailsPage(
|
||||||
TransactionDetailsPage(transactionInfo: settings.arguments));
|
transactionInfo: settings.arguments as TransactionInfo));
|
||||||
|
|
||||||
case Routes.newSubaddress:
|
case Routes.newSubaddress:
|
||||||
return CupertinoPageRoute(
|
return CupertinoPageRoute<void>(
|
||||||
builder: (_) => Provider(
|
builder: (_) => Provider(
|
||||||
create: (_) =>
|
create: (_) =>
|
||||||
SubadrressCreationStore(walletService: walletService),
|
SubadrressCreationStore(walletService: walletService),
|
||||||
child: NewSubaddressPage()));
|
child: NewSubaddressPage()));
|
||||||
|
|
||||||
case Routes.disclaimer:
|
case Routes.disclaimer:
|
||||||
return CupertinoPageRoute(builder: (_) => DisclaimerPage());
|
return CupertinoPageRoute<void>(builder: (_) => DisclaimerPage());
|
||||||
|
|
||||||
case Routes.readDisclaimer:
|
case Routes.readDisclaimer:
|
||||||
return CupertinoPageRoute(
|
return CupertinoPageRoute<void>(
|
||||||
builder: (_) => DisclaimerPage(isReadOnly: true));
|
builder: (_) => DisclaimerPage(isReadOnly: true));
|
||||||
|
|
||||||
case Routes.seedAlert:
|
case Routes.seedAlert:
|
||||||
return CupertinoPageRoute(builder: (_) => SeedAlert());
|
return CupertinoPageRoute<void>(builder: (_) => SeedAlert());
|
||||||
|
|
||||||
case Routes.walletList:
|
case Routes.walletList:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute<void>(
|
||||||
fullscreenDialog: true,
|
fullscreenDialog: true,
|
||||||
builder: (_) => Provider(
|
builder: (_) => Provider(
|
||||||
create: (_) => WalletListStore(
|
create: (_) => WalletListStore(
|
||||||
|
@ -268,40 +273,43 @@ class Router {
|
||||||
child: WalletListPage()));
|
child: WalletListPage()));
|
||||||
|
|
||||||
case Routes.auth:
|
case Routes.auth:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute<void>(
|
||||||
fullscreenDialog: true,
|
fullscreenDialog: true,
|
||||||
builder: (_) => Provider(
|
builder: (_) => Provider(
|
||||||
create: (_) => AuthStore(
|
create: (_) => AuthStore(
|
||||||
sharedPreferences: sharedPreferences,
|
sharedPreferences: sharedPreferences,
|
||||||
userService: userService,
|
userService: userService,
|
||||||
walletService: walletService),
|
walletService: walletService),
|
||||||
child: AuthPage(onAuthenticationFinished: settings.arguments),
|
child: AuthPage(
|
||||||
|
onAuthenticationFinished:
|
||||||
|
settings.arguments as OnAuthenticationFinished),
|
||||||
));
|
));
|
||||||
|
|
||||||
case Routes.unlock:
|
case Routes.unlock:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute<void>(
|
||||||
fullscreenDialog: true,
|
fullscreenDialog: true,
|
||||||
builder: (_) => createUnlockPage(
|
builder: (_) => createUnlockPage(
|
||||||
sharedPreferences: sharedPreferences,
|
sharedPreferences: sharedPreferences,
|
||||||
userService: userService,
|
userService: userService,
|
||||||
walletService: walletService,
|
walletService: walletService,
|
||||||
onAuthenticationFinished: settings.arguments));
|
onAuthenticationFinished:
|
||||||
|
settings.arguments as OnAuthenticationFinished));
|
||||||
|
|
||||||
case Routes.nodeList:
|
case Routes.nodeList:
|
||||||
return CupertinoPageRoute(builder: (context) {
|
return CupertinoPageRoute<void>(builder: (context) {
|
||||||
return Provider(
|
return Provider(
|
||||||
create: (_) => NodeListStore(nodesSource: nodes),
|
create: (_) => NodeListStore(nodesSource: nodes),
|
||||||
child: NodeListPage());
|
child: NodeListPage());
|
||||||
});
|
});
|
||||||
|
|
||||||
case Routes.newNode:
|
case Routes.newNode:
|
||||||
return CupertinoPageRoute(
|
return CupertinoPageRoute<void>(
|
||||||
builder: (_) => Provider<NodeListStore>(
|
builder: (_) => Provider<NodeListStore>(
|
||||||
create: (_) => NodeListStore(nodesSource: nodes),
|
create: (_) => NodeListStore(nodesSource: nodes),
|
||||||
child: NewNodePage()));
|
child: NewNodePage()));
|
||||||
|
|
||||||
case Routes.login:
|
case Routes.login:
|
||||||
return CupertinoPageRoute(builder: (context) {
|
return CupertinoPageRoute<void>(builder: (context) {
|
||||||
final authenticationStore = Provider.of<AuthenticationStore>(context);
|
final authenticationStore = Provider.of<AuthenticationStore>(context);
|
||||||
|
|
||||||
return createLoginPage(
|
return createLoginPage(
|
||||||
|
@ -313,7 +321,7 @@ class Router {
|
||||||
});
|
});
|
||||||
|
|
||||||
case Routes.accountList:
|
case Routes.accountList:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute<void>(
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return MultiProvider(providers: [
|
return MultiProvider(providers: [
|
||||||
Provider(
|
Provider(
|
||||||
|
@ -324,14 +332,14 @@ class Router {
|
||||||
fullscreenDialog: true);
|
fullscreenDialog: true);
|
||||||
|
|
||||||
case Routes.accountCreation:
|
case Routes.accountCreation:
|
||||||
return CupertinoPageRoute(builder: (context) {
|
return CupertinoPageRoute<String>(builder: (context) {
|
||||||
return Provider(
|
return Provider(
|
||||||
create: (_) => AccountListStore(walletService: walletService),
|
create: (_) => AccountListStore(walletService: walletService),
|
||||||
child: AccountPage(account: settings.arguments));
|
child: AccountPage(account: settings.arguments as Account));
|
||||||
});
|
});
|
||||||
|
|
||||||
case Routes.addressBook:
|
case Routes.addressBook:
|
||||||
return MaterialPageRoute(builder: (context) {
|
return MaterialPageRoute<void>(builder: (context) {
|
||||||
return MultiProvider(
|
return MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
Provider(
|
Provider(
|
||||||
|
@ -344,7 +352,7 @@ class Router {
|
||||||
});
|
});
|
||||||
|
|
||||||
case Routes.pickerAddressBook:
|
case Routes.pickerAddressBook:
|
||||||
return MaterialPageRoute(builder: (context) {
|
return MaterialPageRoute<void>(builder: (context) {
|
||||||
return MultiProvider(
|
return MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
Provider(
|
Provider(
|
||||||
|
@ -357,7 +365,7 @@ class Router {
|
||||||
});
|
});
|
||||||
|
|
||||||
case Routes.addressBookAddContact:
|
case Routes.addressBookAddContact:
|
||||||
return CupertinoPageRoute(builder: (context) {
|
return CupertinoPageRoute<void>(builder: (context) {
|
||||||
return MultiProvider(
|
return MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
Provider(
|
Provider(
|
||||||
|
@ -365,12 +373,12 @@ class Router {
|
||||||
AccountListStore(walletService: walletService)),
|
AccountListStore(walletService: walletService)),
|
||||||
Provider(create: (_) => AddressBookStore(contacts: contacts))
|
Provider(create: (_) => AddressBookStore(contacts: contacts))
|
||||||
],
|
],
|
||||||
child: ContactPage(contact: settings.arguments),
|
child: ContactPage(contact: settings.arguments as Contact),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
case Routes.showKeys:
|
case Routes.showKeys:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute<void>(
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return Provider(
|
return Provider(
|
||||||
create: (_) => WalletKeysStore(walletService: walletService),
|
create: (_) => WalletKeysStore(walletService: walletService),
|
||||||
|
@ -380,12 +388,13 @@ class Router {
|
||||||
fullscreenDialog: true);
|
fullscreenDialog: true);
|
||||||
|
|
||||||
case Routes.exchangeTrade:
|
case Routes.exchangeTrade:
|
||||||
return CupertinoPageRoute(
|
return CupertinoPageRoute<void>(
|
||||||
builder: (_) => MultiProvider(
|
builder: (_) => MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
ProxyProvider<SettingsStore, ExchangeTradeStore>(
|
ProxyProvider<SettingsStore, ExchangeTradeStore>(
|
||||||
update: (_, settingsStore, __) => ExchangeTradeStore(
|
update: (_, settingsStore, __) => ExchangeTradeStore(
|
||||||
trade: settings.arguments, walletStore: walletStore),
|
trade: settings.arguments as Trade,
|
||||||
|
walletStore: walletStore),
|
||||||
),
|
),
|
||||||
ProxyProvider<SettingsStore, SendStore>(
|
ProxyProvider<SettingsStore, SendStore>(
|
||||||
update: (_, settingsStore, __) => SendStore(
|
update: (_, settingsStore, __) => SendStore(
|
||||||
|
@ -398,21 +407,22 @@ class Router {
|
||||||
));
|
));
|
||||||
|
|
||||||
case Routes.exchangeConfirm:
|
case Routes.exchangeConfirm:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute<void>(
|
||||||
builder: (_) => ExchangeConfirmPage(trade: settings.arguments));
|
builder: (_) =>
|
||||||
|
ExchangeConfirmPage(trade: settings.arguments as Trade));
|
||||||
|
|
||||||
case Routes.tradeDetails:
|
case Routes.tradeDetails:
|
||||||
return MaterialPageRoute(builder: (context) {
|
return MaterialPageRoute<void>(builder: (context) {
|
||||||
return MultiProvider(providers: [
|
return MultiProvider(providers: [
|
||||||
ProxyProvider<SettingsStore, ExchangeTradeStore>(
|
ProxyProvider<SettingsStore, ExchangeTradeStore>(
|
||||||
update: (_, settingsStore, __) => ExchangeTradeStore(
|
update: (_, settingsStore, __) => ExchangeTradeStore(
|
||||||
trade: settings.arguments, walletStore: walletStore),
|
trade: settings.arguments as Trade, walletStore: walletStore),
|
||||||
)
|
)
|
||||||
], child: TradeDetailsPage());
|
], child: TradeDetailsPage());
|
||||||
});
|
});
|
||||||
|
|
||||||
case Routes.subaddressList:
|
case Routes.subaddressList:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute<Subaddress>(
|
||||||
builder: (_) => MultiProvider(providers: [
|
builder: (_) => MultiProvider(providers: [
|
||||||
Provider(
|
Provider(
|
||||||
create: (_) =>
|
create: (_) =>
|
||||||
|
@ -420,17 +430,18 @@ class Router {
|
||||||
], child: SubaddressListPage()));
|
], child: SubaddressListPage()));
|
||||||
|
|
||||||
case Routes.restoreWalletFromSeedDetails:
|
case Routes.restoreWalletFromSeedDetails:
|
||||||
return CupertinoPageRoute(
|
return CupertinoPageRoute<void>(
|
||||||
builder: (_) =>
|
builder: (_) =>
|
||||||
ProxyProvider<AuthenticationStore, WalletRestorationStore>(
|
ProxyProvider<AuthenticationStore, WalletRestorationStore>(
|
||||||
update: (_, authStore, __) => WalletRestorationStore(
|
update: (_, authStore, __) => WalletRestorationStore(
|
||||||
authStore: authStore,
|
authStore: authStore,
|
||||||
sharedPreferences: sharedPreferences,
|
sharedPreferences: sharedPreferences,
|
||||||
walletListService: walletListService,
|
walletListService: walletListService,
|
||||||
seed: settings.arguments),
|
seed: settings.arguments as List<MnemoticItem>),
|
||||||
child: RestoreWalletFromSeedDetailsPage()));
|
child: RestoreWalletFromSeedDetailsPage()));
|
||||||
|
|
||||||
case Routes.exchange:
|
case Routes.exchange:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute<void>(
|
||||||
builder: (_) => MultiProvider(providers: [
|
builder: (_) => MultiProvider(providers: [
|
||||||
Provider(create: (_) {
|
Provider(create: (_) {
|
||||||
final xmrtoprovider = XMRTOExchangeProvider();
|
final xmrtoprovider = XMRTOExchangeProvider();
|
||||||
|
@ -449,25 +460,25 @@ class Router {
|
||||||
], child: ExchangePage()));
|
], child: ExchangePage()));
|
||||||
|
|
||||||
case Routes.settings:
|
case Routes.settings:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute<void>(
|
||||||
builder: (_) => Provider(
|
builder: (_) => Provider(
|
||||||
create: (_) => NodeListStore(nodesSource: nodes),
|
create: (_) => NodeListStore(nodesSource: nodes),
|
||||||
child: SettingsPage()));
|
child: SettingsPage()));
|
||||||
|
|
||||||
case Routes.rescan:
|
case Routes.rescan:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute<void>(
|
||||||
builder: (_) => Provider(
|
builder: (_) => Provider(
|
||||||
create: (_) => RescanWalletStore(walletService: walletService),
|
create: (_) => RescanWalletStore(walletService: walletService),
|
||||||
child: RescanPage()));
|
child: RescanPage()));
|
||||||
|
|
||||||
case Routes.faq:
|
case Routes.faq:
|
||||||
return MaterialPageRoute(builder: (_) => FaqPage());
|
return MaterialPageRoute<void>(builder: (_) => FaqPage());
|
||||||
|
|
||||||
case Routes.changeLanguage:
|
case Routes.changeLanguage:
|
||||||
return MaterialPageRoute(builder: (_) => ChangeLanguage());
|
return MaterialPageRoute<void>(builder: (_) => ChangeLanguage());
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return MaterialPageRoute(
|
return MaterialPageRoute<void>(
|
||||||
builder: (_) => Scaffold(
|
builder: (_) => Scaffold(
|
||||||
body: Center(
|
body: Center(
|
||||||
child: Text(S.current.router_no_route(settings.name))),
|
child: Text(S.current.router_no_route(settings.name))),
|
||||||
|
|
|
@ -3,6 +3,9 @@ import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/src/domain/common/enumerable_item.dart';
|
import 'package:cake_wallet/src/domain/common/enumerable_item.dart';
|
||||||
|
|
||||||
class BalanceDisplayMode extends EnumerableItem<int> with Serializable<int> {
|
class BalanceDisplayMode extends EnumerableItem<int> with Serializable<int> {
|
||||||
|
const BalanceDisplayMode({@required String title, @required int raw})
|
||||||
|
: super(title: title, raw: raw);
|
||||||
|
|
||||||
static const all = [
|
static const all = [
|
||||||
BalanceDisplayMode.fullBalance,
|
BalanceDisplayMode.fullBalance,
|
||||||
BalanceDisplayMode.availableBalance,
|
BalanceDisplayMode.availableBalance,
|
||||||
|
@ -27,9 +30,6 @@ class BalanceDisplayMode extends EnumerableItem<int> with Serializable<int> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const BalanceDisplayMode({@required String title, @required int raw})
|
|
||||||
: super(title: title, raw: raw);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
|
|
|
@ -6,6 +6,9 @@ part 'contact.g.dart';
|
||||||
|
|
||||||
@HiveType()
|
@HiveType()
|
||||||
class Contact extends HiveObject {
|
class Contact extends HiveObject {
|
||||||
|
Contact({@required this.name, @required this.address, CryptoCurrency type})
|
||||||
|
: raw = type?.raw;
|
||||||
|
|
||||||
static const boxName = 'Contacts';
|
static const boxName = 'Contacts';
|
||||||
|
|
||||||
@HiveField(0)
|
@HiveField(0)
|
||||||
|
@ -19,12 +22,6 @@ class Contact extends HiveObject {
|
||||||
|
|
||||||
CryptoCurrency get type => CryptoCurrency.deserialize(raw: raw);
|
CryptoCurrency get type => CryptoCurrency.deserialize(raw: raw);
|
||||||
|
|
||||||
Contact(
|
void updateCryptoCurrency({@required CryptoCurrency currency}) =>
|
||||||
{@required this.name,
|
|
||||||
@required this.address,
|
|
||||||
CryptoCurrency type})
|
|
||||||
: raw = type?.raw;
|
|
||||||
|
|
||||||
updateCryptoCurrency({@required CryptoCurrency currency}) =>
|
|
||||||
raw = currency.raw;
|
raw = currency.raw;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,9 @@ part 'crypto_currency.g.dart';
|
||||||
|
|
||||||
@HiveType()
|
@HiveType()
|
||||||
class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
|
class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
|
||||||
|
const CryptoCurrency({final String title, final int raw})
|
||||||
|
: super(title: title, raw: raw);
|
||||||
|
|
||||||
static const all = [
|
static const all = [
|
||||||
CryptoCurrency.xmr,
|
CryptoCurrency.xmr,
|
||||||
CryptoCurrency.btc,
|
CryptoCurrency.btc,
|
||||||
|
@ -58,9 +61,6 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const CryptoCurrency({final String title, final int raw})
|
|
||||||
: super(title: title, raw: raw);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => title;
|
String toString() => title;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ Future defaultSettingsMigration(
|
||||||
{@required int version,
|
{@required int version,
|
||||||
@required SharedPreferences sharedPreferences,
|
@required SharedPreferences sharedPreferences,
|
||||||
@required Box<Node> nodes}) async {
|
@required Box<Node> nodes}) async {
|
||||||
int currentVersion =
|
final currentVersion =
|
||||||
sharedPreferences.getInt('current_default_settings_migration_version') ??
|
sharedPreferences.getInt('current_default_settings_migration_version') ??
|
||||||
0;
|
0;
|
||||||
|
|
||||||
|
@ -22,17 +22,17 @@ Future defaultSettingsMigration(
|
||||||
try {
|
try {
|
||||||
switch (version) {
|
switch (version) {
|
||||||
case 1:
|
case 1:
|
||||||
sharedPreferences.setString(
|
await sharedPreferences.setString(
|
||||||
'current_fiat_currency', FiatCurrency.usd.toString());
|
'current_fiat_currency', FiatCurrency.usd.toString());
|
||||||
sharedPreferences.setInt(
|
await sharedPreferences.setInt(
|
||||||
'current_fee_priority', TransactionPriority.standart.raw);
|
'current_fee_priority', TransactionPriority.standart.raw);
|
||||||
sharedPreferences.setInt('current_balance_display_mode',
|
await sharedPreferences.setInt('current_balance_display_mode',
|
||||||
BalanceDisplayMode.availableBalance.raw);
|
BalanceDisplayMode.availableBalance.raw);
|
||||||
sharedPreferences.setInt(
|
await sharedPreferences.setInt(
|
||||||
'current_default_settings_migration_version', 1);
|
'current_default_settings_migration_version', 1);
|
||||||
sharedPreferences.setBool('save_recipient_address', false);
|
await sharedPreferences.setBool('save_recipient_address', false);
|
||||||
await resetToDefault(nodes);
|
await resetToDefault(nodes);
|
||||||
sharedPreferences.setInt('current_node_id', 0);
|
await sharedPreferences.setInt('current_node_id', 0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -41,6 +41,6 @@ Future defaultSettingsMigration(
|
||||||
print('Migration error: ${e.toString()}');
|
print('Migration error: ${e.toString()}');
|
||||||
}
|
}
|
||||||
|
|
||||||
sharedPreferences.setInt(
|
await sharedPreferences.setInt(
|
||||||
'current_default_settings_migration_version', version);
|
'current_default_settings_migration_version', version);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:dio/dio.dart' as Dio;
|
import 'package:dio/dio.dart' as __dio;
|
||||||
import 'package:crypto/crypto.dart' as crypto;
|
import 'package:crypto/crypto.dart' as crypto;
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ class DigestRequest {
|
||||||
|
|
||||||
String generateCnonce() {
|
String generateCnonce() {
|
||||||
final rnd = math.Random.secure();
|
final rnd = math.Random.secure();
|
||||||
var values = List<int>.generate(32, (i) => rnd.nextInt(256));
|
final values = List<int>.generate(32, (i) => rnd.nextInt(256));
|
||||||
return base64Url.encode(values).substring(0, 8);
|
return base64Url.encode(values).substring(0, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ class DigestRequest {
|
||||||
Map<String, String> parsetAuthorizationHeader({String source}) {
|
Map<String, String> parsetAuthorizationHeader({String source}) {
|
||||||
final authHeaderParts =
|
final authHeaderParts =
|
||||||
source.substring(7).split(',').map((item) => item.trim());
|
source.substring(7).split(',').map((item) => item.trim());
|
||||||
var authenticate = Map<String, String>();
|
final authenticate = Map<String, String>();
|
||||||
|
|
||||||
for (final part in authHeaderParts) {
|
for (final part in authHeaderParts) {
|
||||||
final kv = part.split('=');
|
final kv = part.split('=');
|
||||||
|
@ -55,30 +55,25 @@ class DigestRequest {
|
||||||
return authenticate;
|
return authenticate;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Dio.Response> request(
|
Future<__dio.Response> request(
|
||||||
{String uri, String login, String password}) async {
|
{String uri, String login, String password}) async {
|
||||||
final path = '/json_rpc';
|
const path = '/json_rpc';
|
||||||
final method = 'POST';
|
const method = 'POST';
|
||||||
final url = Uri.http(uri, path);
|
final url = Uri.http(uri, path);
|
||||||
final dio = Dio.Dio();
|
final dio = __dio.Dio();
|
||||||
|
final headers = {'Content-type': 'application/json'};
|
||||||
Map<String, String> headers = {'Content-type': 'application/json'};
|
final body =
|
||||||
String body =
|
|
||||||
json.encode({"jsonrpc": "2.0", "id": "0", "method": "get_info"});
|
json.encode({"jsonrpc": "2.0", "id": "0", "method": "get_info"});
|
||||||
|
final credentialsResponse = await dio.post<Object>(url.toString(),
|
||||||
var credentialsResponse = await dio.post(url.toString(),
|
options: __dio.Options(headers: headers, validateStatus: (_) => true));
|
||||||
options: Dio.Options(headers: headers, validateStatus: (_) => true));
|
final authenticate = parsetAuthorizationHeader(
|
||||||
var resHeaeders = credentialsResponse.headers;
|
source: credentialsResponse.headers['www-authenticate'].first);
|
||||||
final authenticate =
|
|
||||||
parsetAuthorizationHeader(source: resHeaeders['www-authenticate'].first);
|
|
||||||
final qop = authenticate['qop'];
|
final qop = authenticate['qop'];
|
||||||
final algorithm = 'MD5';
|
final algorithm = 'MD5';
|
||||||
final realm = 'monero-rpc';
|
final realm = 'monero-rpc';
|
||||||
final nonce = authenticate['nonce'];
|
final nonce = authenticate['nonce'];
|
||||||
final cnonce = generateCnonce();
|
final cnonce = generateCnonce();
|
||||||
|
final nonceCount = '00000001';
|
||||||
var nonceCount = '00000001';
|
|
||||||
|
|
||||||
final ha1 = generateHA1(realm: realm, username: login, password: password);
|
final ha1 = generateHA1(realm: realm, username: login, password: password);
|
||||||
final ha2 = generateHA2(method: method, uri: path);
|
final ha2 = generateHA2(method: method, uri: path);
|
||||||
final response = generateResponseString(
|
final response = generateResponseString(
|
||||||
|
@ -95,8 +90,7 @@ class DigestRequest {
|
||||||
'Digest username="$login",realm="$realm",nonce="$nonce",uri="$path",algorithm="$algorithm",qop=$qop,nc=$nonceCount,cnonce="$cnonce",response="$response"'
|
'Digest username="$login",realm="$realm",nonce="$nonce",uri="$path",algorithm="$algorithm",qop=$qop,nc=$nonceCount,cnonce="$cnonce",response="$response"'
|
||||||
};
|
};
|
||||||
|
|
||||||
final res = await dio.post(url.toString(),
|
return await dio.post<Object>(url.toString(),
|
||||||
options: Dio.Options(headers: authorizationHeaders), data: body);
|
options: __dio.Options(headers: authorizationHeaders), data: body);
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,11 +1,11 @@
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
|
|
||||||
abstract class EnumerableItem<T> {
|
abstract class EnumerableItem<T> {
|
||||||
|
const EnumerableItem({@required this.title, @required this.raw});
|
||||||
|
|
||||||
final T raw;
|
final T raw;
|
||||||
final String title;
|
final String title;
|
||||||
|
|
||||||
const EnumerableItem({@required this.title, @required this.raw});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => title;
|
String toString() => title;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,12 +20,12 @@ Future<double> fetchPriceFor({CryptoCurrency crypto, FiatCurrency fiat}) async {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
final responseJSON = json.decode(response.body);
|
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||||
final data = responseJSON['data'];
|
final data = responseJSON['data'] as List<Map<String, dynamic>>;
|
||||||
|
|
||||||
for (final item in data) {
|
for (final item in data) {
|
||||||
if (item['symbol'] == cryptoToString(crypto)) {
|
if (item['symbol'] == cryptoToString(crypto)) {
|
||||||
price = item['quote'][fiatStringified]['price'];
|
price = item['quote'][fiatStringified]['price'] as double;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,11 @@
|
||||||
import 'package:cake_wallet/src/domain/common/enumerable_item.dart';
|
import 'package:cake_wallet/src/domain/common/enumerable_item.dart';
|
||||||
|
|
||||||
class FiatCurrency extends EnumerableItem<String> with Serializable<String> {
|
class FiatCurrency extends EnumerableItem<String> with Serializable<String> {
|
||||||
|
const FiatCurrency({String symbol}) : super(title: symbol, raw: symbol);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) => other is FiatCurrency && other.raw == raw;
|
||||||
|
|
||||||
static const all = [
|
static const all = [
|
||||||
FiatCurrency.aud,
|
FiatCurrency.aud,
|
||||||
FiatCurrency.bgn,
|
FiatCurrency.bgn,
|
||||||
|
@ -71,10 +76,6 @@ class FiatCurrency extends EnumerableItem<String> with Serializable<String> {
|
||||||
static const zar = FiatCurrency(symbol: 'ZAR');
|
static const zar = FiatCurrency(symbol: 'ZAR');
|
||||||
static const vef = FiatCurrency(symbol: 'VEF');
|
static const vef = FiatCurrency(symbol: 'VEF');
|
||||||
|
|
||||||
const FiatCurrency({String symbol}) : super(title: symbol, raw: symbol);
|
|
||||||
|
|
||||||
operator ==(o) => o is FiatCurrency && o.raw == raw;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => raw.hashCode ^ title.hashCode;
|
int get hashCode => raw.hashCode ^ title.hashCode;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,14 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class Language with ChangeNotifier {
|
class Language with ChangeNotifier {
|
||||||
|
Language(this._currentLanguage);
|
||||||
|
|
||||||
String _currentLanguage;
|
String _currentLanguage;
|
||||||
|
|
||||||
Language(this._currentLanguage);
|
String getCurrentLanguage() => _currentLanguage;
|
||||||
|
|
||||||
getCurrentLanguage() => _currentLanguage;
|
void setCurrentLanguage(String language) {
|
||||||
|
|
||||||
setCurrentLanguage(String language){
|
|
||||||
_currentLanguage = language;
|
_currentLanguage = language;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,13 +1,11 @@
|
||||||
class MnemoticItem {
|
class MnemoticItem {
|
||||||
|
MnemoticItem({String text, this.dic}) : _text = text;
|
||||||
|
|
||||||
String get text => _text;
|
String get text => _text;
|
||||||
final List<String> dic;
|
final List<String> dic;
|
||||||
|
|
||||||
String _text;
|
String _text;
|
||||||
|
|
||||||
MnemoticItem({String text, this.dic}) {
|
|
||||||
_text = text;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isCorrect() => dic.contains(text);
|
bool isCorrect() => dic.contains(text);
|
||||||
|
|
||||||
void changeText(String text) {
|
void changeText(String text) {
|
||||||
|
|
|
@ -8,6 +8,13 @@ part 'node.g.dart';
|
||||||
|
|
||||||
@HiveType()
|
@HiveType()
|
||||||
class Node extends HiveObject {
|
class Node extends HiveObject {
|
||||||
|
Node({@required this.uri, this.login, this.password});
|
||||||
|
|
||||||
|
Node.fromMap(Map map)
|
||||||
|
: uri = (map['uri'] ?? '') as String,
|
||||||
|
login = map['login'] as String,
|
||||||
|
password = map['password'] as String;
|
||||||
|
|
||||||
static const boxName = 'Nodes';
|
static const boxName = 'Nodes';
|
||||||
|
|
||||||
@HiveField(0)
|
@HiveField(0)
|
||||||
|
@ -19,31 +26,24 @@ class Node extends HiveObject {
|
||||||
@HiveField(2)
|
@HiveField(2)
|
||||||
String password;
|
String password;
|
||||||
|
|
||||||
Node({@required this.uri, this.login, this.password});
|
|
||||||
|
|
||||||
Node.fromMap(Map map)
|
|
||||||
: uri = map['uri'] ?? '',
|
|
||||||
login = map['login'],
|
|
||||||
password = map['password'];
|
|
||||||
|
|
||||||
Future<bool> requestNode(String uri, {String login, String password}) async {
|
Future<bool> requestNode(String uri, {String login, String password}) async {
|
||||||
var resBody;
|
Map<String, dynamic> resBody;
|
||||||
|
|
||||||
if (login != null && password != null) {
|
if (login != null && password != null) {
|
||||||
final digestRequest = DigestRequest();
|
final digestRequest = DigestRequest();
|
||||||
var response = await digestRequest.request(
|
final response = await digestRequest.request(
|
||||||
uri: uri, login: login, password: password);
|
uri: uri, login: login, password: password);
|
||||||
resBody = response.data;
|
resBody = response.data as Map<String, dynamic>;
|
||||||
} else {
|
} else {
|
||||||
final url = Uri.http(uri, '/json_rpc');
|
final url = Uri.http(uri, '/json_rpc');
|
||||||
Map<String, String> headers = {'Content-type': 'application/json'};
|
final headers = {'Content-type': 'application/json'};
|
||||||
String body =
|
final body =
|
||||||
json.encode({"jsonrpc": "2.0", "id": "0", "method": "get_info"});
|
json.encode({"jsonrpc": "2.0", "id": "0", "method": "get_info"});
|
||||||
var response =
|
final response =
|
||||||
await http.post(url.toString(), headers: headers, body: body);
|
await http.post(url.toString(), headers: headers, body: body);
|
||||||
resBody = json.decode(response.body);
|
resBody = json.decode(response.body) as Map<String, dynamic>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return !resBody["result"]["offline"];
|
return !(resBody["result"]["offline"] as bool);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,16 +4,17 @@ import "package:yaml/yaml.dart";
|
||||||
import 'package:cake_wallet/src/domain/common/node.dart';
|
import 'package:cake_wallet/src/domain/common/node.dart';
|
||||||
|
|
||||||
Future<List<Node>> loadDefaultNodes() async {
|
Future<List<Node>> loadDefaultNodes() async {
|
||||||
String nodesRaw = await rootBundle.loadString('assets/node_list.yml');
|
final nodesRaw = await rootBundle.loadString('assets/node_list.yml');
|
||||||
List nodes = loadYaml(nodesRaw);
|
final nodes = loadYaml(nodesRaw) as List<Map<dynamic, dynamic>>;
|
||||||
|
|
||||||
return nodes.map((raw) => Node.fromMap(raw)).toList();
|
return nodes.map((raw) => Node.fromMap(raw)).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future resetToDefault(Box<Node> nodeSource) async {
|
Future resetToDefault(Box<Node> nodeSource) async {
|
||||||
final nodes = await loadDefaultNodes();
|
final nodes = await loadDefaultNodes();
|
||||||
await nodeSource.clear();
|
final enteties = Map<int, Node>();
|
||||||
|
|
||||||
Map<int, Node> enteties = {};
|
await nodeSource.clear();
|
||||||
|
|
||||||
for (var i = 0; i < nodes.length; i++) {
|
for (var i = 0; i < nodes.length; i++) {
|
||||||
enteties[i] = nodes[i];
|
enteties[i] = nodes[i];
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:cw_monero/transaction_history.dart' as transactionHistory;
|
import 'package:cw_monero/transaction_history.dart' as transaction_history;
|
||||||
import 'package:cw_monero/structs/pending_transaction.dart';
|
import 'package:cw_monero/structs/pending_transaction.dart';
|
||||||
import 'package:cake_wallet/src/domain/monero/monero_amount_format.dart';
|
import 'package:cake_wallet/src/domain/monero/monero_amount_format.dart';
|
||||||
|
|
||||||
class PendingTransaction {
|
class PendingTransaction {
|
||||||
final String amount;
|
|
||||||
final String fee;
|
|
||||||
final String hash;
|
|
||||||
|
|
||||||
int _pointerAddress;
|
|
||||||
|
|
||||||
PendingTransaction(
|
PendingTransaction(
|
||||||
{@required this.amount, @required this.fee, @required this.hash});
|
{@required this.amount, @required this.fee, @required this.hash});
|
||||||
|
|
||||||
|
@ -20,6 +14,12 @@ class PendingTransaction {
|
||||||
hash = transactionDescription.hash,
|
hash = transactionDescription.hash,
|
||||||
_pointerAddress = transactionDescription.pointerAddress;
|
_pointerAddress = transactionDescription.pointerAddress;
|
||||||
|
|
||||||
Future commit() async => transactionHistory
|
final String amount;
|
||||||
|
final String fee;
|
||||||
|
final String hash;
|
||||||
|
|
||||||
|
int _pointerAddress;
|
||||||
|
|
||||||
|
Future<void> commit() async => transaction_history
|
||||||
.commitTransactionFromPointerAddress(address: _pointerAddress);
|
.commitTransactionFromPointerAddress(address: _pointerAddress);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,6 @@ Future<String> presentQRScanner() async {
|
||||||
return result;
|
return result;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
isQrScannerShown = false;
|
isQrScannerShown = false;
|
||||||
throw e;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,18 +9,20 @@ abstract class SyncStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
class SyncingSyncStatus extends SyncStatus {
|
class SyncingSyncStatus extends SyncStatus {
|
||||||
|
SyncingSyncStatus(this.height, this.blockchainHeight, this.refreshHeight);
|
||||||
|
|
||||||
final int height;
|
final int height;
|
||||||
final int blockchainHeight;
|
final int blockchainHeight;
|
||||||
final int refreshHeight;
|
final int refreshHeight;
|
||||||
|
|
||||||
SyncingSyncStatus(this.height, this.blockchainHeight, this.refreshHeight);
|
@override
|
||||||
|
|
||||||
double progress() {
|
double progress() {
|
||||||
final line = blockchainHeight - refreshHeight;
|
final line = blockchainHeight - refreshHeight;
|
||||||
final diff = line - (blockchainHeight - height);
|
final diff = line - (blockchainHeight - height);
|
||||||
return diff <= 0 ? 0.0 : diff / line;
|
return diff <= 0 ? 0.0 : diff / line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
String title() => S.current.sync_status_syncronizing;
|
String title() => S.current.sync_status_syncronizing;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -28,39 +30,51 @@ class SyncingSyncStatus extends SyncStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
class SyncedSyncStatus extends SyncStatus {
|
class SyncedSyncStatus extends SyncStatus {
|
||||||
|
@override
|
||||||
double progress() => 1.0;
|
double progress() => 1.0;
|
||||||
|
|
||||||
|
@override
|
||||||
String title() => S.current.sync_status_syncronized;
|
String title() => S.current.sync_status_syncronized;
|
||||||
}
|
}
|
||||||
|
|
||||||
class NotConnectedSyncStatus extends SyncStatus {
|
class NotConnectedSyncStatus extends SyncStatus {
|
||||||
const NotConnectedSyncStatus();
|
const NotConnectedSyncStatus();
|
||||||
|
|
||||||
|
@override
|
||||||
double progress() => 0.0;
|
double progress() => 0.0;
|
||||||
|
|
||||||
|
@override
|
||||||
String title() => S.current.sync_status_not_connected;
|
String title() => S.current.sync_status_not_connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
class StartingSyncStatus extends SyncStatus {
|
class StartingSyncStatus extends SyncStatus {
|
||||||
|
@override
|
||||||
double progress() => 0.0;
|
double progress() => 0.0;
|
||||||
|
|
||||||
|
@override
|
||||||
String title() => S.current.sync_status_starting_sync;
|
String title() => S.current.sync_status_starting_sync;
|
||||||
}
|
}
|
||||||
|
|
||||||
class FailedSyncStatus extends SyncStatus {
|
class FailedSyncStatus extends SyncStatus {
|
||||||
|
@override
|
||||||
double progress() => 1.0;
|
double progress() => 1.0;
|
||||||
|
|
||||||
|
@override
|
||||||
String title() => S.current.sync_status_failed_connect;
|
String title() => S.current.sync_status_failed_connect;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConnectingSyncStatus extends SyncStatus {
|
class ConnectingSyncStatus extends SyncStatus {
|
||||||
|
@override
|
||||||
double progress() => 0.0;
|
double progress() => 0.0;
|
||||||
|
|
||||||
|
@override
|
||||||
String title() => S.current.sync_status_connecting;
|
String title() => S.current.sync_status_connecting;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConnectedSyncStatus extends SyncStatus {
|
class ConnectedSyncStatus extends SyncStatus {
|
||||||
|
@override
|
||||||
double progress() => 0.0;
|
double progress() => 0.0;
|
||||||
|
|
||||||
|
@override
|
||||||
String title() => S.current.sync_status_connected;
|
String title() => S.current.sync_status_connected;
|
||||||
}
|
}
|
|
@ -4,26 +4,20 @@ import 'package:cake_wallet/src/domain/common/parseBoolFromString.dart';
|
||||||
import 'package:cake_wallet/src/domain/common/transaction_direction.dart';
|
import 'package:cake_wallet/src/domain/common/transaction_direction.dart';
|
||||||
|
|
||||||
class TransactionInfo {
|
class TransactionInfo {
|
||||||
final String id;
|
TransactionInfo(this.id, this.height, this.direction, this.date,
|
||||||
final int height;
|
this.isPending, this.amount, this.accountIndex);
|
||||||
final TransactionDirection direction;
|
|
||||||
final DateTime date;
|
|
||||||
final int accountIndex;
|
|
||||||
final bool isPending;
|
|
||||||
final int amount;
|
|
||||||
String recipientAddress;
|
|
||||||
String _fiatAmount;
|
|
||||||
|
|
||||||
TransactionInfo.fromMap(Map map)
|
TransactionInfo.fromMap(Map map)
|
||||||
: id = map['hash'] ?? '',
|
: id = (map['hash'] ?? '') as String,
|
||||||
height = map['height'] ?? '',
|
height = (map['height'] ?? 0) as int,
|
||||||
direction = parseTransactionDirectionFromNumber(map['direction']) ??
|
direction =
|
||||||
|
parseTransactionDirectionFromNumber(map['direction'] as String) ??
|
||||||
TransactionDirection.incoming,
|
TransactionDirection.incoming,
|
||||||
date = DateTime.fromMillisecondsSinceEpoch(
|
date = DateTime.fromMillisecondsSinceEpoch(
|
||||||
(int.parse(map['timestamp']) ?? 0) * 1000),
|
(int.parse(map['timestamp'] as String) ?? 0) * 1000),
|
||||||
isPending = parseBoolFromString(map['isPending']),
|
isPending = parseBoolFromString(map['isPending'] as String),
|
||||||
amount = map['amount'],
|
amount = map['amount'] as int,
|
||||||
accountIndex = int.parse(map['accountIndex']);
|
accountIndex = int.parse(map['accountIndex'] as String);
|
||||||
|
|
||||||
TransactionInfo.fromRow(TransactionInfoRow row)
|
TransactionInfo.fromRow(TransactionInfoRow row)
|
||||||
: id = row.getHash(),
|
: id = row.getHash(),
|
||||||
|
@ -35,12 +29,20 @@ class TransactionInfo {
|
||||||
amount = row.getAmount(),
|
amount = row.getAmount(),
|
||||||
accountIndex = row.subaddrAccount;
|
accountIndex = row.subaddrAccount;
|
||||||
|
|
||||||
TransactionInfo(this.id, this.height, this.direction, this.date,
|
final String id;
|
||||||
this.isPending, this.amount, this.accountIndex);
|
final int height;
|
||||||
|
final TransactionDirection direction;
|
||||||
|
final DateTime date;
|
||||||
|
final int accountIndex;
|
||||||
|
final bool isPending;
|
||||||
|
final int amount;
|
||||||
|
String recipientAddress;
|
||||||
|
|
||||||
|
String _fiatAmount;
|
||||||
|
|
||||||
String amountFormatted() => '${moneroAmountToString(amount: amount)} XMR';
|
String amountFormatted() => '${moneroAmountToString(amount: amount)} XMR';
|
||||||
|
|
||||||
String fiatAmount() => _fiatAmount ?? '';
|
String fiatAmount() => _fiatAmount ?? '';
|
||||||
|
|
||||||
changeFiatAmount(String amount) => _fiatAmount = amount;
|
void changeFiatAmount(String amount) => _fiatAmount = amount;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,9 @@ import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/src/domain/common/enumerable_item.dart';
|
import 'package:cake_wallet/src/domain/common/enumerable_item.dart';
|
||||||
|
|
||||||
class TransactionPriority extends EnumerableItem<int> with Serializable<int> {
|
class TransactionPriority extends EnumerableItem<int> with Serializable<int> {
|
||||||
|
const TransactionPriority({String title, int raw})
|
||||||
|
: super(title: title, raw: raw);
|
||||||
|
|
||||||
static const all = [
|
static const all = [
|
||||||
TransactionPriority.slow,
|
TransactionPriority.slow,
|
||||||
TransactionPriority.regular,
|
TransactionPriority.regular,
|
||||||
|
@ -33,9 +36,6 @@ class TransactionPriority extends EnumerableItem<int> with Serializable<int> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const TransactionPriority({String title, int raw})
|
|
||||||
: super(title: title, raw: raw);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
|
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
|
||||||
|
|
||||||
class WalletDescription {
|
class WalletDescription {
|
||||||
|
WalletDescription({this.name, this.type});
|
||||||
|
|
||||||
final String name;
|
final String name;
|
||||||
final WalletType type;
|
final WalletType type;
|
||||||
|
|
||||||
WalletDescription({this.name, this.type});
|
|
||||||
}
|
}
|
|
@ -5,6 +5,9 @@ part 'wallet_info.g.dart';
|
||||||
|
|
||||||
@HiveType()
|
@HiveType()
|
||||||
class WalletInfo extends HiveObject {
|
class WalletInfo extends HiveObject {
|
||||||
|
WalletInfo(
|
||||||
|
{this.id, this.name, this.type, this.isRecovery, this.restoreHeight});
|
||||||
|
|
||||||
static const boxName = 'WalletInfo';
|
static const boxName = 'WalletInfo';
|
||||||
|
|
||||||
@HiveField(0)
|
@HiveField(0)
|
||||||
|
@ -21,7 +24,4 @@ class WalletInfo extends HiveObject {
|
||||||
|
|
||||||
@HiveField(4)
|
@HiveField(4)
|
||||||
int restoreHeight;
|
int restoreHeight;
|
||||||
|
|
||||||
WalletInfo(
|
|
||||||
{this.id, this.name, this.type, this.isRecovery, this.restoreHeight});
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,18 +15,9 @@ import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.da
|
||||||
import 'package:cake_wallet/src/domain/exchange/trade_not_created_exeption.dart';
|
import 'package:cake_wallet/src/domain/exchange/trade_not_created_exeption.dart';
|
||||||
|
|
||||||
class ChangeNowExchangeProvider extends ExchangeProvider {
|
class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||||
static const apiUri = 'https://changenow.io/api/v1';
|
ChangeNowExchangeProvider()
|
||||||
static const apiKey = secrets.change_now_api_key;
|
: super(
|
||||||
static const _exchangeAmountUriSufix = '/exchange-amount/';
|
pairList: CryptoCurrency.all
|
||||||
static const _transactionsUriSufix = '/transactions/';
|
|
||||||
static const _minAmountUriSufix = '/min-amount/';
|
|
||||||
|
|
||||||
String get title => 'ChangeNOW';
|
|
||||||
ExchangeProviderDescription get description =>
|
|
||||||
ExchangeProviderDescription.changeNow;
|
|
||||||
|
|
||||||
ChangeNowExchangeProvider() {
|
|
||||||
pairList = CryptoCurrency.all
|
|
||||||
.map((i) {
|
.map((i) {
|
||||||
return CryptoCurrency.all.map((k) {
|
return CryptoCurrency.all.map((k) {
|
||||||
if (i == CryptoCurrency.btc && k == CryptoCurrency.xmr) {
|
if (i == CryptoCurrency.btc && k == CryptoCurrency.xmr) {
|
||||||
|
@ -41,19 +32,33 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||||
}).where((c) => c != null);
|
}).where((c) => c != null);
|
||||||
})
|
})
|
||||||
.expand((i) => i)
|
.expand((i) => i)
|
||||||
.toList();
|
.toList());
|
||||||
}
|
|
||||||
|
|
||||||
|
static const apiUri = 'https://changenow.io/api/v1';
|
||||||
|
static const apiKey = secrets.change_now_api_key;
|
||||||
|
static const _exchangeAmountUriSufix = '/exchange-amount/';
|
||||||
|
static const _transactionsUriSufix = '/transactions/';
|
||||||
|
static const _minAmountUriSufix = '/min-amount/';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get title => 'ChangeNOW';
|
||||||
|
|
||||||
|
@override
|
||||||
|
ExchangeProviderDescription get description =>
|
||||||
|
ExchangeProviderDescription.changeNow;
|
||||||
|
|
||||||
|
@override
|
||||||
Future<Limits> fetchLimits({CryptoCurrency from, CryptoCurrency to}) async {
|
Future<Limits> fetchLimits({CryptoCurrency from, CryptoCurrency to}) async {
|
||||||
final symbol = from.toString() + '_' + to.toString();
|
final symbol = from.toString() + '_' + to.toString();
|
||||||
final url = apiUri + _minAmountUriSufix + symbol;
|
final url = apiUri + _minAmountUriSufix + symbol;
|
||||||
final response = await get(url);
|
final response = await get(url);
|
||||||
final responseJSON = json.decode(response.body);
|
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||||
final double min = responseJSON['minAmount'];
|
final min = responseJSON['minAmount'] as double;
|
||||||
|
|
||||||
return Limits(min: min, max: null);
|
return Limits(min: min, max: null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<Trade> createTrade({TradeRequest request}) async {
|
Future<Trade> createTrade({TradeRequest request}) async {
|
||||||
const url = apiUri + _transactionsUriSufix + apiKey;
|
const url = apiUri + _transactionsUriSufix + apiKey;
|
||||||
final _request = request as ChangeNowRequest;
|
final _request = request as ChangeNowRequest;
|
||||||
|
@ -70,37 +75,44 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||||
|
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
if (response.statusCode == 400) {
|
if (response.statusCode == 400) {
|
||||||
final responseJSON = json.decode(response.body);
|
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||||
final error = responseJSON['message'];
|
final error = responseJSON['message'] as String;
|
||||||
|
|
||||||
throw TradeNotCreatedException(description, description: error);
|
throw TradeNotCreatedException(description, description: error);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw TradeNotCreatedException(description);
|
throw TradeNotCreatedException(description);
|
||||||
}
|
}
|
||||||
|
|
||||||
final responseJSON = json.decode(response.body);
|
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||||
|
final id = responseJSON['id'] as String;
|
||||||
|
final inputAddress = responseJSON['payinAddress'] as String;
|
||||||
|
final refundAddress = responseJSON['refundAddress'] as String;
|
||||||
|
final extraId = responseJSON['payinExtraId'] as String;
|
||||||
|
|
||||||
return Trade(
|
return Trade(
|
||||||
id: responseJSON['id'],
|
id: id,
|
||||||
from: _request.from,
|
from: _request.from,
|
||||||
to: _request.to,
|
to: _request.to,
|
||||||
provider: description,
|
provider: description,
|
||||||
inputAddress: responseJSON['payinAddress'],
|
inputAddress: inputAddress,
|
||||||
refundAddress: responseJSON['refundAddress'],
|
refundAddress: refundAddress,
|
||||||
extraId: responseJSON["payinExtraId"],
|
extraId: extraId,
|
||||||
createdAt: DateTime.now(),
|
createdAt: DateTime.now(),
|
||||||
amount: _request.amount,
|
amount: _request.amount,
|
||||||
state: TradeState.created);
|
state: TradeState.created);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<Trade> findTradeById({@required String id}) async {
|
Future<Trade> findTradeById({@required String id}) async {
|
||||||
final url = apiUri + _transactionsUriSufix + id + '/' + apiKey;
|
final url = apiUri + _transactionsUriSufix + id + '/' + apiKey;
|
||||||
final response = await get(url);
|
final response = await get(url);
|
||||||
|
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
if (response.statusCode == 400) {
|
if (response.statusCode == 400) {
|
||||||
final responseJSON = json.decode(response.body);
|
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||||
final error = responseJSON['message'];
|
final error = responseJSON['message'] as String;
|
||||||
|
|
||||||
throw TradeNotFoundException(id,
|
throw TradeNotFoundException(id,
|
||||||
provider: description, description: error);
|
provider: description, description: error);
|
||||||
}
|
}
|
||||||
|
@ -108,20 +120,31 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||||
throw TradeNotFoundException(id, provider: description);
|
throw TradeNotFoundException(id, provider: description);
|
||||||
}
|
}
|
||||||
|
|
||||||
final responseJSON = json.decode(response.body);
|
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||||
|
final fromCurrency = responseJSON['fromCurrency'] as String;
|
||||||
|
final from = CryptoCurrency.fromString(fromCurrency);
|
||||||
|
final toCurrency = responseJSON['toCurrency'] as String;
|
||||||
|
final to = CryptoCurrency.fromString(toCurrency);
|
||||||
|
final inputAddress = responseJSON['payinAddress'] as String;
|
||||||
|
final expectedSendAmount = responseJSON['expectedSendAmount'].toString();
|
||||||
|
final status = responseJSON['status'] as String;
|
||||||
|
final state = TradeState.deserialize(raw: status);
|
||||||
|
final extraId = responseJSON['payinExtraId'] as String;
|
||||||
|
final outputTransaction = responseJSON['payoutHash'] as String;
|
||||||
|
|
||||||
return Trade(
|
return Trade(
|
||||||
id: id,
|
id: id,
|
||||||
from: CryptoCurrency.fromString(responseJSON['fromCurrency']),
|
from: from,
|
||||||
to: CryptoCurrency.fromString(responseJSON['toCurrency']),
|
to: to,
|
||||||
provider: description,
|
provider: description,
|
||||||
inputAddress: responseJSON['payinAddress'],
|
inputAddress: inputAddress,
|
||||||
amount: responseJSON['expectedSendAmount'].toString(),
|
amount: expectedSendAmount,
|
||||||
state: TradeState.deserialize(raw: responseJSON['status']),
|
state: state,
|
||||||
extraId: responseJSON['payinExtraId'],
|
extraId: extraId,
|
||||||
outputTransaction: responseJSON['payoutHash']);
|
outputTransaction: outputTransaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<double> calculateAmount(
|
Future<double> calculateAmount(
|
||||||
{CryptoCurrency from, CryptoCurrency to, double amount}) async {
|
{CryptoCurrency from, CryptoCurrency to, double amount}) async {
|
||||||
final url = apiUri +
|
final url = apiUri +
|
||||||
|
@ -132,8 +155,9 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
|
||||||
'_' +
|
'_' +
|
||||||
to.toString();
|
to.toString();
|
||||||
final response = await get(url);
|
final response = await get(url);
|
||||||
final responseJSON = json.decode(response.body);
|
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||||
|
final estimatedAmount = responseJSON['estimatedAmount'] as double;
|
||||||
|
|
||||||
return responseJSON['estimatedAmount'];
|
return estimatedAmount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,16 +3,16 @@ import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
|
||||||
import 'package:cake_wallet/src/domain/exchange/trade_request.dart';
|
import 'package:cake_wallet/src/domain/exchange/trade_request.dart';
|
||||||
|
|
||||||
class ChangeNowRequest extends TradeRequest {
|
class ChangeNowRequest extends TradeRequest {
|
||||||
CryptoCurrency from;
|
|
||||||
CryptoCurrency to;
|
|
||||||
String address;
|
|
||||||
String amount;
|
|
||||||
String refundAddress;
|
|
||||||
|
|
||||||
ChangeNowRequest(
|
ChangeNowRequest(
|
||||||
{@required this.from,
|
{@required this.from,
|
||||||
@required this.to,
|
@required this.to,
|
||||||
@required this.address,
|
@required this.address,
|
||||||
@required this.amount,
|
@required this.amount,
|
||||||
@required this.refundAddress});
|
@required this.refundAddress});
|
||||||
|
|
||||||
|
CryptoCurrency from;
|
||||||
|
CryptoCurrency to;
|
||||||
|
String address;
|
||||||
|
String amount;
|
||||||
|
String refundAddress;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
|
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
|
||||||
|
|
||||||
class ExchangePair {
|
class ExchangePair {
|
||||||
|
ExchangePair({this.from, this.to, this.reverse = true});
|
||||||
|
|
||||||
final CryptoCurrency from;
|
final CryptoCurrency from;
|
||||||
final CryptoCurrency to;
|
final CryptoCurrency to;
|
||||||
final bool reverse;
|
final bool reverse;
|
||||||
|
|
||||||
ExchangePair({this.from, this.to, this.reverse = true});
|
|
||||||
}
|
}
|
|
@ -7,6 +7,8 @@ import 'package:cake_wallet/src/domain/exchange/trade.dart';
|
||||||
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
|
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
|
||||||
|
|
||||||
abstract class ExchangeProvider {
|
abstract class ExchangeProvider {
|
||||||
|
ExchangeProvider({this.pairList});
|
||||||
|
|
||||||
String get title;
|
String get title;
|
||||||
List<ExchangePair> pairList;
|
List<ExchangePair> pairList;
|
||||||
ExchangeProviderDescription description;
|
ExchangeProviderDescription description;
|
||||||
|
|
|
@ -2,6 +2,9 @@ import 'package:cake_wallet/src/domain/common/enumerable_item.dart';
|
||||||
|
|
||||||
class ExchangeProviderDescription extends EnumerableItem<int>
|
class ExchangeProviderDescription extends EnumerableItem<int>
|
||||||
with Serializable<int> {
|
with Serializable<int> {
|
||||||
|
const ExchangeProviderDescription({String title, int raw})
|
||||||
|
: super(title: title, raw: raw);
|
||||||
|
|
||||||
static const xmrto = ExchangeProviderDescription(title: 'XMR.TO', raw: 0);
|
static const xmrto = ExchangeProviderDescription(title: 'XMR.TO', raw: 0);
|
||||||
static const changeNow =
|
static const changeNow =
|
||||||
ExchangeProviderDescription(title: 'ChangeNOW', raw: 1);
|
ExchangeProviderDescription(title: 'ChangeNOW', raw: 1);
|
||||||
|
@ -16,9 +19,4 @@ class ExchangeProviderDescription extends EnumerableItem<int>
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final String title;
|
|
||||||
|
|
||||||
const ExchangeProviderDescription({this.title, int raw})
|
|
||||||
: super(title: title, raw: raw);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
class Limits {
|
class Limits {
|
||||||
|
const Limits({this.min, this.max});
|
||||||
|
|
||||||
final double min;
|
final double min;
|
||||||
final double max;
|
final double max;
|
||||||
|
|
||||||
const Limits({this.min, this.max});
|
|
||||||
}
|
}
|
|
@ -7,6 +7,25 @@ part 'trade.g.dart';
|
||||||
|
|
||||||
@HiveType()
|
@HiveType()
|
||||||
class Trade extends HiveObject {
|
class Trade extends HiveObject {
|
||||||
|
Trade(
|
||||||
|
{this.id,
|
||||||
|
ExchangeProviderDescription provider,
|
||||||
|
CryptoCurrency from,
|
||||||
|
CryptoCurrency to,
|
||||||
|
TradeState state,
|
||||||
|
this.createdAt,
|
||||||
|
this.expiredAt,
|
||||||
|
this.amount,
|
||||||
|
this.inputAddress,
|
||||||
|
this.extraId,
|
||||||
|
this.outputTransaction,
|
||||||
|
this.refundAddress,
|
||||||
|
this.walletId})
|
||||||
|
: providerRaw = provider?.raw,
|
||||||
|
fromRaw = from?.raw,
|
||||||
|
toRaw = to?.raw,
|
||||||
|
stateRaw = state?.raw;
|
||||||
|
|
||||||
static const boxName = 'Trades';
|
static const boxName = 'Trades';
|
||||||
|
|
||||||
@HiveField(0)
|
@HiveField(0)
|
||||||
|
@ -59,38 +78,20 @@ class Trade extends HiveObject {
|
||||||
|
|
||||||
static Trade fromMap(Map map) {
|
static Trade fromMap(Map map) {
|
||||||
return Trade(
|
return Trade(
|
||||||
id: map['id'],
|
id: map['id'] as String,
|
||||||
provider: ExchangeProviderDescription.deserialize(raw: map['provider']),
|
provider: ExchangeProviderDescription.deserialize(
|
||||||
from: CryptoCurrency.deserialize(raw: map['input']),
|
raw: map['provider'] as int),
|
||||||
to: CryptoCurrency.deserialize(raw: map['output']),
|
from: CryptoCurrency.deserialize(raw: map['input'] as int),
|
||||||
|
to: CryptoCurrency.deserialize(raw: map['output'] as int),
|
||||||
createdAt: map['date'] != null
|
createdAt: map['date'] != null
|
||||||
? DateTime.fromMillisecondsSinceEpoch(map['date'])
|
? DateTime.fromMillisecondsSinceEpoch(map['date'] as int)
|
||||||
: null,
|
: null,
|
||||||
amount: map['amount'],
|
amount: map['amount'] as String,
|
||||||
walletId: map['wallet_id']);
|
walletId: map['wallet_id'] as String);
|
||||||
}
|
}
|
||||||
|
|
||||||
Trade(
|
|
||||||
{this.id,
|
|
||||||
ExchangeProviderDescription provider,
|
|
||||||
CryptoCurrency from,
|
|
||||||
CryptoCurrency to,
|
|
||||||
TradeState state,
|
|
||||||
this.createdAt,
|
|
||||||
this.expiredAt,
|
|
||||||
this.amount,
|
|
||||||
this.inputAddress,
|
|
||||||
this.extraId,
|
|
||||||
this.outputTransaction,
|
|
||||||
this.refundAddress,
|
|
||||||
this.walletId})
|
|
||||||
: providerRaw = provider?.raw,
|
|
||||||
fromRaw = from?.raw,
|
|
||||||
toRaw = to?.raw,
|
|
||||||
stateRaw = state?.raw;
|
|
||||||
|
|
||||||
Map<String, dynamic> toMap() {
|
Map<String, dynamic> toMap() {
|
||||||
return {
|
return <String, dynamic>{
|
||||||
'id': id,
|
'id': id,
|
||||||
'provider': provider.serialize(),
|
'provider': provider.serialize(),
|
||||||
'input': from.serialize(),
|
'input': from.serialize(),
|
||||||
|
|
|
@ -2,11 +2,11 @@ import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.da
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
|
||||||
class TradeNotCreatedException implements Exception {
|
class TradeNotCreatedException implements Exception {
|
||||||
|
TradeNotCreatedException(this.provider, {this.description = ''});
|
||||||
|
|
||||||
ExchangeProviderDescription provider;
|
ExchangeProviderDescription provider;
|
||||||
String description;
|
String description;
|
||||||
|
|
||||||
TradeNotCreatedException(this.provider, {this.description = ''});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
var text = provider != null
|
var text = provider != null
|
||||||
|
|
|
@ -2,12 +2,12 @@ import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.da
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
|
||||||
class TradeNotFoundException implements Exception {
|
class TradeNotFoundException implements Exception {
|
||||||
|
TradeNotFoundException(this.tradeId, {this.provider, this.description = ''});
|
||||||
|
|
||||||
String tradeId;
|
String tradeId;
|
||||||
ExchangeProviderDescription provider;
|
ExchangeProviderDescription provider;
|
||||||
String description;
|
String description;
|
||||||
|
|
||||||
TradeNotFoundException(this.tradeId, {this.provider, this.description = ''});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
var text = tradeId != null && provider != null
|
var text = tradeId != null && provider != null
|
||||||
|
|
|
@ -2,6 +2,12 @@ import 'package:flutter/foundation.dart';
|
||||||
import 'package:cake_wallet/src/domain/common/enumerable_item.dart';
|
import 'package:cake_wallet/src/domain/common/enumerable_item.dart';
|
||||||
|
|
||||||
class TradeState extends EnumerableItem<String> with Serializable<String> {
|
class TradeState extends EnumerableItem<String> with Serializable<String> {
|
||||||
|
const TradeState({@required String raw, @required String title})
|
||||||
|
: super(raw: raw, title: title);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) => other is TradeState && other.raw == raw;
|
||||||
|
|
||||||
static const pending = TradeState(raw: 'pending', title: 'Pending');
|
static const pending = TradeState(raw: 'pending', title: 'Pending');
|
||||||
static const confirming = TradeState(raw: 'confirming', title: 'Confirming');
|
static const confirming = TradeState(raw: 'confirming', title: 'Confirming');
|
||||||
static const trading = TradeState(raw: 'trading', title: 'Trading');
|
static const trading = TradeState(raw: 'trading', title: 'Trading');
|
||||||
|
@ -58,11 +64,6 @@ class TradeState extends EnumerableItem<String> with Serializable<String> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const TradeState({@required String raw, @required String title})
|
|
||||||
: super(raw: raw, title: title);
|
|
||||||
|
|
||||||
operator ==(o) => o is TradeState && o.raw == raw;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => raw.hashCode ^ title.hashCode;
|
int get hashCode => raw.hashCode ^ title.hashCode;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,12 @@ import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.da
|
||||||
import 'package:cake_wallet/src/domain/exchange/trade_not_found_exeption.dart';
|
import 'package:cake_wallet/src/domain/exchange/trade_not_found_exeption.dart';
|
||||||
|
|
||||||
class XMRTOExchangeProvider extends ExchangeProvider {
|
class XMRTOExchangeProvider extends ExchangeProvider {
|
||||||
|
XMRTOExchangeProvider()
|
||||||
|
: super(pairList: [
|
||||||
|
ExchangePair(
|
||||||
|
from: CryptoCurrency.xmr, to: CryptoCurrency.btc, reverse: false)
|
||||||
|
]);
|
||||||
|
|
||||||
static const userAgent = 'CakeWallet/XMR iOS';
|
static const userAgent = 'CakeWallet/XMR iOS';
|
||||||
static const originalApiUri = 'https://xmr.to/api/v2/xmr2btc';
|
static const originalApiUri = 'https://xmr.to/api/v2/xmr2btc';
|
||||||
static const proxyApiUri = 'https://xmrproxy.net/api/v2/xmr2btc';
|
static const proxyApiUri = 'https://xmrproxy.net/api/v2/xmr2btc';
|
||||||
|
@ -35,18 +41,16 @@ class XMRTOExchangeProvider extends ExchangeProvider {
|
||||||
return _apiUri;
|
return _apiUri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
String get title => 'XMR.TO';
|
String get title => 'XMR.TO';
|
||||||
|
|
||||||
|
@override
|
||||||
ExchangeProviderDescription get description =>
|
ExchangeProviderDescription get description =>
|
||||||
ExchangeProviderDescription.xmrto;
|
ExchangeProviderDescription.xmrto;
|
||||||
|
|
||||||
List<ExchangePair> pairList = [
|
|
||||||
ExchangePair(
|
|
||||||
from: CryptoCurrency.xmr, to: CryptoCurrency.btc, reverse: false)
|
|
||||||
];
|
|
||||||
|
|
||||||
double _rate = 0;
|
double _rate = 0;
|
||||||
|
|
||||||
|
@override
|
||||||
Future<Limits> fetchLimits({CryptoCurrency from, CryptoCurrency to}) async {
|
Future<Limits> fetchLimits({CryptoCurrency from, CryptoCurrency to}) async {
|
||||||
final url = await getApiUri() + _orderParameterUriSufix;
|
final url = await getApiUri() + _orderParameterUriSufix;
|
||||||
final response = await get(url);
|
final response = await get(url);
|
||||||
|
@ -55,13 +59,14 @@ class XMRTOExchangeProvider extends ExchangeProvider {
|
||||||
return Limits(min: 0, max: 0);
|
return Limits(min: 0, max: 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
final responseJSON = json.decode(response.body);
|
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||||
final double min = responseJSON['lower_limit'];
|
final min = responseJSON['lower_limit'] as double;
|
||||||
final double max = responseJSON['upper_limit'];
|
final max = responseJSON['upper_limit'] as double;
|
||||||
|
|
||||||
return Limits(min: min, max: max);
|
return Limits(min: min, max: max);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<Trade> createTrade({TradeRequest request}) async {
|
Future<Trade> createTrade({TradeRequest request}) async {
|
||||||
final _request = request as XMRTOTradeRequest;
|
final _request = request as XMRTOTradeRequest;
|
||||||
final url = await getApiUri() + _orderCreateUriSufix;
|
final url = await getApiUri() + _orderCreateUriSufix;
|
||||||
|
@ -74,16 +79,17 @@ class XMRTOExchangeProvider extends ExchangeProvider {
|
||||||
|
|
||||||
if (response.statusCode != 201) {
|
if (response.statusCode != 201) {
|
||||||
if (response.statusCode == 400) {
|
if (response.statusCode == 400) {
|
||||||
final responseJSON = json.decode(response.body);
|
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||||
throw TradeNotCreatedException(description,
|
final error = responseJSON['error_msg'] as String;
|
||||||
description: responseJSON['error_msg']);
|
|
||||||
|
throw TradeNotCreatedException(description, description: error);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw TradeNotCreatedException(description);
|
throw TradeNotCreatedException(description);
|
||||||
}
|
}
|
||||||
|
|
||||||
final responseJSON = json.decode(response.body);
|
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||||
final uuid = responseJSON["uuid"];
|
final uuid = responseJSON["uuid"] as String;
|
||||||
|
|
||||||
return Trade(
|
return Trade(
|
||||||
id: uuid,
|
id: uuid,
|
||||||
|
@ -95,6 +101,7 @@ class XMRTOExchangeProvider extends ExchangeProvider {
|
||||||
createdAt: DateTime.now());
|
createdAt: DateTime.now());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<Trade> findTradeById({@required String id}) async {
|
Future<Trade> findTradeById({@required String id}) async {
|
||||||
const headers = {
|
const headers = {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
|
@ -106,8 +113,9 @@ class XMRTOExchangeProvider extends ExchangeProvider {
|
||||||
|
|
||||||
if (response.statusCode != 200) {
|
if (response.statusCode != 200) {
|
||||||
if (response.statusCode == 400) {
|
if (response.statusCode == 400) {
|
||||||
final responseJSON = json.decode(response.body);
|
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||||
final error = responseJSON['error_msg'];
|
final error = responseJSON['error_msg'] as String;
|
||||||
|
|
||||||
throw TradeNotFoundException(id,
|
throw TradeNotFoundException(id,
|
||||||
provider: description, description: error);
|
provider: description, description: error);
|
||||||
}
|
}
|
||||||
|
@ -115,14 +123,14 @@ class XMRTOExchangeProvider extends ExchangeProvider {
|
||||||
throw TradeNotFoundException(id, provider: description);
|
throw TradeNotFoundException(id, provider: description);
|
||||||
}
|
}
|
||||||
|
|
||||||
final responseJSON = json.decode(response.body);
|
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||||
final address = responseJSON['xmr_receiving_integrated_address'];
|
final address = responseJSON['xmr_receiving_integrated_address'] as String;
|
||||||
final paymentId = responseJSON['xmr_required_payment_id_short'];
|
final paymentId = responseJSON['xmr_required_payment_id_short'] as String;
|
||||||
final amount = responseJSON['xmr_amount_total'].toString();
|
final amount = responseJSON['xmr_amount_total'].toString();
|
||||||
final stateRaw = responseJSON['state'];
|
final stateRaw = responseJSON['state'] as String;
|
||||||
final expiredAtRaw = responseJSON['expires_at'];
|
final expiredAtRaw = responseJSON['expires_at'] as String;
|
||||||
final expiredAt = DateTime.parse(expiredAtRaw).toLocal();
|
final expiredAt = DateTime.parse(expiredAtRaw).toLocal();
|
||||||
final outputTransaction = responseJSON['btc_transaction_id'];
|
final outputTransaction = responseJSON['btc_transaction_id'] as String;
|
||||||
final state = TradeState.deserialize(raw: stateRaw);
|
final state = TradeState.deserialize(raw: stateRaw);
|
||||||
|
|
||||||
return Trade(
|
return Trade(
|
||||||
|
@ -138,6 +146,7 @@ class XMRTOExchangeProvider extends ExchangeProvider {
|
||||||
outputTransaction: outputTransaction);
|
outputTransaction: outputTransaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<double> calculateAmount(
|
Future<double> calculateAmount(
|
||||||
{CryptoCurrency from, CryptoCurrency to, double amount}) async {
|
{CryptoCurrency from, CryptoCurrency to, double amount}) async {
|
||||||
if (from != CryptoCurrency.xmr && to != CryptoCurrency.btc) {
|
if (from != CryptoCurrency.xmr && to != CryptoCurrency.btc) {
|
||||||
|
@ -158,9 +167,10 @@ class XMRTOExchangeProvider extends ExchangeProvider {
|
||||||
final url = await getApiUri() + _orderParameterUriSufix;
|
final url = await getApiUri() + _orderParameterUriSufix;
|
||||||
final response =
|
final response =
|
||||||
await get(url, headers: {'Content-Type': 'application/json'});
|
await get(url, headers: {'Content-Type': 'application/json'});
|
||||||
final responseJSON = json.decode(response.body);
|
final responseJSON = json.decode(response.body) as Map<String, dynamic>;
|
||||||
double btcprice = responseJSON['price'];
|
final btcprice = responseJSON['price'] as double;
|
||||||
double price = 1 / btcprice;
|
final price = 1 / btcprice;
|
||||||
|
|
||||||
return price;
|
return price;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print(e.toString());
|
print(e.toString());
|
||||||
|
|
|
@ -3,16 +3,16 @@ import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
|
||||||
import 'package:cake_wallet/src/domain/exchange/trade_request.dart';
|
import 'package:cake_wallet/src/domain/exchange/trade_request.dart';
|
||||||
|
|
||||||
class XMRTOTradeRequest extends TradeRequest {
|
class XMRTOTradeRequest extends TradeRequest {
|
||||||
final CryptoCurrency from;
|
|
||||||
final CryptoCurrency to;
|
|
||||||
final String amount;
|
|
||||||
final String address;
|
|
||||||
final String refundAddress;
|
|
||||||
|
|
||||||
XMRTOTradeRequest(
|
XMRTOTradeRequest(
|
||||||
{@required this.from,
|
{@required this.from,
|
||||||
@required this.to,
|
@required this.to,
|
||||||
@required this.amount,
|
@required this.amount,
|
||||||
@required this.address,
|
@required this.address,
|
||||||
@required this.refundAddress});
|
@required this.refundAddress});
|
||||||
|
|
||||||
|
final CryptoCurrency from;
|
||||||
|
final CryptoCurrency to;
|
||||||
|
final String amount;
|
||||||
|
final String address;
|
||||||
|
final String refundAddress;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
import 'package:cw_monero/structs/account_row.dart';
|
import 'package:cw_monero/structs/account_row.dart';
|
||||||
|
|
||||||
class Account {
|
class Account {
|
||||||
final int id;
|
|
||||||
final String label;
|
|
||||||
|
|
||||||
Account({this.id, this.label});
|
Account({this.id, this.label});
|
||||||
|
|
||||||
Account.fromMap(Map map)
|
Account.fromMap(Map map)
|
||||||
: this.id = map['id'] == null ? 0 : int.parse(map['id']),
|
: this.id = map['id'] == null ? 0 : int.parse(map['id'] as String),
|
||||||
this.label = map['label'] ?? '';
|
this.label = (map['label'] ?? '') as String;
|
||||||
|
|
||||||
Account.fromRow(AccountRow row)
|
Account.fromRow(AccountRow row)
|
||||||
: this.id = row.getId(),
|
: this.id = row.getId(),
|
||||||
this.label = row.getLabel();
|
this.label = row.getLabel();
|
||||||
|
|
||||||
|
final int id;
|
||||||
|
final String label;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
import 'package:rxdart/rxdart.dart';
|
import 'package:rxdart/rxdart.dart';
|
||||||
import 'package:cw_monero/account_list.dart' as accountListAPI;
|
import 'package:cw_monero/account_list.dart' as account_list;
|
||||||
import 'package:cake_wallet/src/domain/monero/account.dart';
|
import 'package:cake_wallet/src/domain/monero/account.dart';
|
||||||
|
|
||||||
class AccountList {
|
class AccountList {
|
||||||
get accounts => _accounts.stream;
|
|
||||||
BehaviorSubject<List<Account>> _accounts;
|
|
||||||
|
|
||||||
bool _isRefreshing;
|
|
||||||
bool _isUpdating;
|
|
||||||
|
|
||||||
AccountList() {
|
AccountList() {
|
||||||
_isRefreshing = false;
|
_isRefreshing = false;
|
||||||
_isUpdating = false;
|
_isUpdating = false;
|
||||||
_accounts = BehaviorSubject<List<Account>>();
|
_accounts = BehaviorSubject<List<Account>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Observable<List<Account>> get accounts => _accounts.stream;
|
||||||
|
|
||||||
|
BehaviorSubject<List<Account>> _accounts;
|
||||||
|
bool _isRefreshing;
|
||||||
|
bool _isUpdating;
|
||||||
|
|
||||||
Future update() async {
|
Future update() async {
|
||||||
if (_isUpdating) {
|
if (_isUpdating) {
|
||||||
return;
|
return;
|
||||||
|
@ -22,46 +22,47 @@ class AccountList {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_isUpdating = true;
|
_isUpdating = true;
|
||||||
await refresh();
|
refresh();
|
||||||
final accounts = getAll();
|
final accounts = getAll();
|
||||||
_accounts.add(accounts);
|
_accounts.add(accounts);
|
||||||
_isUpdating = false;
|
_isUpdating = false;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_isUpdating = false;
|
_isUpdating = false;
|
||||||
throw e;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Account> getAll() {
|
List<Account> getAll() {
|
||||||
return accountListAPI
|
return account_list
|
||||||
.getAllAccount()
|
.getAllAccount()
|
||||||
.map((accountRow) => Account.fromRow(accountRow))
|
.map((accountRow) => Account.fromRow(accountRow))
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future addAccount({String label}) async {
|
Future addAccount({String label}) async {
|
||||||
await accountListAPI.addAccount(label: label);
|
await account_list.addAccount(label: label);
|
||||||
await update();
|
await update();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future setLabelSubaddress({int accountIndex, String label}) async {
|
Future setLabelSubaddress({int accountIndex, String label}) async {
|
||||||
await accountListAPI.setLabelForAccount(accountIndex: accountIndex, label: label);
|
await account_list.setLabelForAccount(
|
||||||
|
accountIndex: accountIndex, label: label);
|
||||||
await update();
|
await update();
|
||||||
}
|
}
|
||||||
|
|
||||||
refresh() {
|
void refresh() {
|
||||||
if (_isRefreshing) {
|
if (_isRefreshing) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_isRefreshing = true;
|
_isRefreshing = true;
|
||||||
accountListAPI.refreshAccounts();
|
account_list.refreshAccounts();
|
||||||
_isRefreshing = false;
|
_isRefreshing = false;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_isRefreshing = false;
|
_isRefreshing = false;
|
||||||
print(e);
|
print(e);
|
||||||
throw e;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,8 @@ int getHeigthByDate({DateTime date}) {
|
||||||
|
|
||||||
if (endHeight <= 0) {
|
if (endHeight <= 0) {
|
||||||
endHeight = dates.values.toList()[dates.length - 1];
|
endHeight = dates.values.toList()[dates.length - 1];
|
||||||
final preLastDate = dateFormat.parse(dates.keys.elementAt(dates.keys.length - 2));
|
final preLastDate =
|
||||||
|
dateFormat.parse(dates.keys.elementAt(dates.keys.length - 2));
|
||||||
preLastYear = preLastDate.year;
|
preLastYear = preLastDate.year;
|
||||||
preLastMonth = preLastDate.month;
|
preLastMonth = preLastDate.month;
|
||||||
} else {
|
} else {
|
||||||
|
@ -90,12 +91,12 @@ int getHeigthByDate({DateTime date}) {
|
||||||
preLastYear -= 1;
|
preLastYear -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
var startRaw = '$preLastYear' + '-' + '$preLastMonth';
|
final startRaw = '$preLastYear' + '-' + '$preLastMonth';
|
||||||
var startHeight = dates[startRaw];
|
final startHeight = dates[startRaw];
|
||||||
var diff = endHeight - startHeight;
|
final diff = endHeight - startHeight;
|
||||||
var heightPerDay = diff / 30;
|
final heightPerDay = diff / 30;
|
||||||
var daysHeight = date.day * heightPerDay.round();
|
final daysHeight = date.day * heightPerDay.round();
|
||||||
var height = endHeight + daysHeight;
|
final height = endHeight + daysHeight;
|
||||||
|
|
||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,8 @@ import 'package:flutter/foundation.dart';
|
||||||
import 'package:cake_wallet/src/domain/common/balance.dart';
|
import 'package:cake_wallet/src/domain/common/balance.dart';
|
||||||
|
|
||||||
class MoneroBalance extends Balance {
|
class MoneroBalance extends Balance {
|
||||||
|
MoneroBalance({@required this.fullBalance, @required this.unlockedBalance});
|
||||||
|
|
||||||
final String fullBalance;
|
final String fullBalance;
|
||||||
final String unlockedBalance;
|
final String unlockedBalance;
|
||||||
|
|
||||||
MoneroBalance({@required this.fullBalance, @required this.unlockedBalance});
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,11 @@ import 'package:cake_wallet/src/domain/common/transaction_priority.dart';
|
||||||
|
|
||||||
class MoneroTransactionCreationCredentials
|
class MoneroTransactionCreationCredentials
|
||||||
extends TransactionCreationCredentials {
|
extends TransactionCreationCredentials {
|
||||||
|
MoneroTransactionCreationCredentials(
|
||||||
|
{this.address, this.paymentId, this.priority, this.amount});
|
||||||
|
|
||||||
final String address;
|
final String address;
|
||||||
final String paymentId;
|
final String paymentId;
|
||||||
final String amount;
|
final String amount;
|
||||||
final TransactionPriority priority;
|
final TransactionPriority priority;
|
||||||
|
|
||||||
MoneroTransactionCreationCredentials(
|
|
||||||
{this.address, this.paymentId, this.priority, this.amount});
|
|
||||||
}
|
}
|
|
@ -1,26 +1,29 @@
|
||||||
import 'dart:core';
|
import 'dart:core';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:rxdart/rxdart.dart';
|
import 'package:rxdart/rxdart.dart';
|
||||||
import 'package:cw_monero/transaction_history.dart' as moneroTransactionHistory;
|
import 'package:cw_monero/transaction_history.dart'
|
||||||
|
as monero_transaction_history;
|
||||||
import 'package:cake_wallet/src/domain/common/transaction_history.dart';
|
import 'package:cake_wallet/src/domain/common/transaction_history.dart';
|
||||||
import 'package:cake_wallet/src/domain/common/transaction_info.dart';
|
import 'package:cake_wallet/src/domain/common/transaction_info.dart';
|
||||||
|
|
||||||
List<TransactionInfo> _getAllTransactions(_) => moneroTransactionHistory
|
List<TransactionInfo> _getAllTransactions(dynamic _) => monero_transaction_history
|
||||||
.getAllTransations()
|
.getAllTransations()
|
||||||
.map((row) => TransactionInfo.fromRow(row))
|
.map((row) => TransactionInfo.fromRow(row))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
class MoneroTransactionHistory extends TransactionHistory {
|
class MoneroTransactionHistory extends TransactionHistory {
|
||||||
get transactions => _transactions.stream;
|
MoneroTransactionHistory()
|
||||||
BehaviorSubject<List<TransactionInfo>> _transactions;
|
: _transactions = BehaviorSubject<List<TransactionInfo>>.seeded([]);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Observable<List<TransactionInfo>> get transactions => _transactions.stream;
|
||||||
|
|
||||||
|
final BehaviorSubject<List<TransactionInfo>> _transactions;
|
||||||
bool _isUpdating = false;
|
bool _isUpdating = false;
|
||||||
bool _isRefreshing = false;
|
bool _isRefreshing = false;
|
||||||
bool _needToCheckForRefresh = false;
|
bool _needToCheckForRefresh = false;
|
||||||
|
|
||||||
MoneroTransactionHistory()
|
@override
|
||||||
: _transactions = BehaviorSubject<List<TransactionInfo>>.seeded([]);
|
|
||||||
|
|
||||||
Future update() async {
|
Future update() async {
|
||||||
if (_isUpdating) {
|
if (_isUpdating) {
|
||||||
return;
|
return;
|
||||||
|
@ -38,15 +41,18 @@ class MoneroTransactionHistory extends TransactionHistory {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_isUpdating = false;
|
_isUpdating = false;
|
||||||
print(e);
|
print(e);
|
||||||
throw e;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<List<TransactionInfo>> getAll({bool force = false}) async =>
|
Future<List<TransactionInfo>> getAll({bool force = false}) async =>
|
||||||
_getAllTransactions(null);
|
_getAllTransactions(null);
|
||||||
|
|
||||||
Future<int> count() async => moneroTransactionHistory.countOfTransactions();
|
@override
|
||||||
|
Future<int> count() async => monero_transaction_history.countOfTransactions();
|
||||||
|
|
||||||
|
@override
|
||||||
Future refresh() async {
|
Future refresh() async {
|
||||||
if (_isRefreshing) {
|
if (_isRefreshing) {
|
||||||
return;
|
return;
|
||||||
|
@ -54,12 +60,12 @@ class MoneroTransactionHistory extends TransactionHistory {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_isRefreshing = true;
|
_isRefreshing = true;
|
||||||
moneroTransactionHistory.refreshTransactions();
|
monero_transaction_history.refreshTransactions();
|
||||||
_isRefreshing = false;
|
_isRefreshing = false;
|
||||||
} on PlatformException catch (e) {
|
} on PlatformException catch (e) {
|
||||||
_isRefreshing = false;
|
_isRefreshing = false;
|
||||||
print(e);
|
print(e);
|
||||||
throw e;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,8 @@ import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:rxdart/rxdart.dart';
|
import 'package:rxdart/rxdart.dart';
|
||||||
import 'package:cw_monero/wallet.dart' as moneroWallet;
|
import 'package:cw_monero/wallet.dart' as monero_wallet;
|
||||||
import 'package:cw_monero/transaction_history.dart' as transactionHistory;
|
import 'package:cw_monero/transaction_history.dart' as transaction_history;
|
||||||
import 'package:cake_wallet/src/domain/common/wallet_info.dart';
|
import 'package:cake_wallet/src/domain/common/wallet_info.dart';
|
||||||
import 'package:cake_wallet/src/domain/common/wallet.dart';
|
import 'package:cake_wallet/src/domain/common/wallet.dart';
|
||||||
import 'package:cake_wallet/src/domain/common/sync_status.dart';
|
import 'package:cake_wallet/src/domain/common/sync_status.dart';
|
||||||
|
@ -23,9 +23,25 @@ import 'package:cake_wallet/src/domain/monero/subaddress.dart';
|
||||||
import 'package:cake_wallet/src/domain/common/balance.dart';
|
import 'package:cake_wallet/src/domain/common/balance.dart';
|
||||||
import 'package:cake_wallet/src/domain/monero/monero_balance.dart';
|
import 'package:cake_wallet/src/domain/monero/monero_balance.dart';
|
||||||
|
|
||||||
const monero_block_size = 1000;
|
const moneroBlockSize = 1000;
|
||||||
|
|
||||||
class MoneroWallet extends Wallet {
|
class MoneroWallet extends Wallet {
|
||||||
|
MoneroWallet({this.walletInfoSource, this.walletInfo}) {
|
||||||
|
_cachedBlockchainHeight = 0;
|
||||||
|
_isSaving = false;
|
||||||
|
_lastSaveTime = 0;
|
||||||
|
_lastRefreshTime = 0;
|
||||||
|
_refreshHeight = 0;
|
||||||
|
_lastSyncHeight = 0;
|
||||||
|
_name = BehaviorSubject<String>();
|
||||||
|
_address = BehaviorSubject<String>();
|
||||||
|
_syncStatus = BehaviorSubject<SyncStatus>();
|
||||||
|
_onBalanceChange = BehaviorSubject<MoneroBalance>();
|
||||||
|
_account = BehaviorSubject<Account>()..add(Account(id: 0));
|
||||||
|
_subaddress = BehaviorSubject<Subaddress>();
|
||||||
|
setListeners();
|
||||||
|
}
|
||||||
|
|
||||||
static Future<MoneroWallet> createdWallet(
|
static Future<MoneroWallet> createdWallet(
|
||||||
{Box<WalletInfo> walletInfoSource,
|
{Box<WalletInfo> walletInfoSource,
|
||||||
String name,
|
String name,
|
||||||
|
@ -48,8 +64,8 @@ class MoneroWallet extends Wallet {
|
||||||
static Future<MoneroWallet> load(
|
static Future<MoneroWallet> load(
|
||||||
Box<WalletInfo> walletInfoSource, String name, WalletType type) async {
|
Box<WalletInfo> walletInfoSource, String name, WalletType type) async {
|
||||||
final id = walletTypeToString(type).toLowerCase() + '_' + name;
|
final id = walletTypeToString(type).toLowerCase() + '_' + name;
|
||||||
final walletInfo =
|
final walletInfo = walletInfoSource.values
|
||||||
walletInfoSource.values.firstWhere((info) => info.id == id, orElse: () => null);
|
.firstWhere((info) => info.id == id, orElse: () => null);
|
||||||
return await configured(
|
return await configured(
|
||||||
walletInfoSource: walletInfoSource, walletInfo: walletInfo);
|
walletInfoSource: walletInfoSource, walletInfo: walletInfo);
|
||||||
}
|
}
|
||||||
|
@ -61,29 +77,44 @@ class MoneroWallet extends Wallet {
|
||||||
walletInfoSource: walletInfoSource, walletInfo: walletInfo);
|
walletInfoSource: walletInfoSource, walletInfo: walletInfo);
|
||||||
|
|
||||||
if (walletInfo.isRecovery) {
|
if (walletInfo.isRecovery) {
|
||||||
await wallet.setRecoveringFromSeed();
|
wallet.setRecoveringFromSeed();
|
||||||
|
|
||||||
if (walletInfo.restoreHeight != null) {
|
if (walletInfo.restoreHeight != null) {
|
||||||
await wallet.setRefreshFromBlockHeight(
|
wallet.setRefreshFromBlockHeight(height: walletInfo.restoreHeight);
|
||||||
height: walletInfo.restoreHeight);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return wallet;
|
return wallet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get address => _address.value;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get name => _name.value;
|
||||||
|
|
||||||
|
@override
|
||||||
WalletType getType() => WalletType.monero;
|
WalletType getType() => WalletType.monero;
|
||||||
bool get isRecovery => walletInfo.isRecovery;
|
|
||||||
|
@override
|
||||||
Observable<SyncStatus> get syncStatus => _syncStatus.stream;
|
Observable<SyncStatus> get syncStatus => _syncStatus.stream;
|
||||||
|
|
||||||
|
@override
|
||||||
Observable<Balance> get onBalanceChange => _onBalanceChange.stream;
|
Observable<Balance> get onBalanceChange => _onBalanceChange.stream;
|
||||||
Observable<Account> get onAccountChange => _account.stream;
|
|
||||||
|
@override
|
||||||
Observable<String> get onNameChange => _name.stream;
|
Observable<String> get onNameChange => _name.stream;
|
||||||
|
|
||||||
|
@override
|
||||||
Observable<String> get onAddressChange => _address.stream;
|
Observable<String> get onAddressChange => _address.stream;
|
||||||
|
|
||||||
|
Observable<Account> get onAccountChange => _account.stream;
|
||||||
|
|
||||||
Observable<Subaddress> get subaddress => _subaddress.stream;
|
Observable<Subaddress> get subaddress => _subaddress.stream;
|
||||||
|
|
||||||
|
bool get isRecovery => walletInfo.isRecovery;
|
||||||
|
|
||||||
Account get account => _account.value;
|
Account get account => _account.value;
|
||||||
String get address => _address.value;
|
|
||||||
String get name => _name.value;
|
|
||||||
|
|
||||||
Box<WalletInfo> walletInfoSource;
|
Box<WalletInfo> walletInfoSource;
|
||||||
WalletInfo walletInfo;
|
WalletInfo walletInfo;
|
||||||
|
@ -105,27 +136,11 @@ class MoneroWallet extends Wallet {
|
||||||
SubaddressList _cachedSubaddressList;
|
SubaddressList _cachedSubaddressList;
|
||||||
AccountList _cachedAccountList;
|
AccountList _cachedAccountList;
|
||||||
|
|
||||||
MoneroWallet(
|
@override
|
||||||
{this.walletInfoSource, this.walletInfo}) {
|
|
||||||
_cachedBlockchainHeight = 0;
|
|
||||||
_isSaving = false;
|
|
||||||
_lastSaveTime = 0;
|
|
||||||
_lastRefreshTime = 0;
|
|
||||||
_refreshHeight = 0;
|
|
||||||
_lastSyncHeight = 0;
|
|
||||||
_name = BehaviorSubject<String>();
|
|
||||||
_address = BehaviorSubject<String>();
|
|
||||||
_syncStatus = BehaviorSubject<SyncStatus>();
|
|
||||||
_onBalanceChange = BehaviorSubject<MoneroBalance>();
|
|
||||||
_account = BehaviorSubject<Account>()..add(Account(id: 0));
|
|
||||||
_subaddress = BehaviorSubject<Subaddress>();
|
|
||||||
setListeners();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future updateInfo() async {
|
Future updateInfo() async {
|
||||||
_name.value = await getName();
|
_name.value = await getName();
|
||||||
final acccountList = getAccountList();
|
final acccountList = getAccountList();
|
||||||
await acccountList.refresh();
|
acccountList.refresh();
|
||||||
_account.value = acccountList.getAll().first;
|
_account.value = acccountList.getAll().first;
|
||||||
final subaddressList = getSubaddress();
|
final subaddressList = getSubaddress();
|
||||||
await subaddressList.refresh(
|
await subaddressList.refresh(
|
||||||
|
@ -135,67 +150,48 @@ class MoneroWallet extends Wallet {
|
||||||
_address.value = await getAddress();
|
_address.value = await getAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> getFilename() async => moneroWallet.getFilename();
|
@override
|
||||||
|
Future<String> getFilename() async => monero_wallet.getFilename();
|
||||||
|
|
||||||
|
@override
|
||||||
Future<String> getName() async => getFilename()
|
Future<String> getName() async => getFilename()
|
||||||
.then((filename) => filename.split('/'))
|
.then((filename) => filename.split('/'))
|
||||||
.then((splitted) => splitted.last);
|
.then((splitted) => splitted.last);
|
||||||
|
|
||||||
Future<String> getAddress() async => moneroWallet.getAddress(
|
@override
|
||||||
|
Future<String> getAddress() async => monero_wallet.getAddress(
|
||||||
accountIndex: _account.value.id, addressIndex: _subaddress.value.id);
|
accountIndex: _account.value.id, addressIndex: _subaddress.value.id);
|
||||||
|
|
||||||
Future<String> getSeed() async => moneroWallet.getSeed();
|
@override
|
||||||
|
Future<String> getSeed() async => monero_wallet.getSeed();
|
||||||
|
|
||||||
|
@override
|
||||||
Future<String> getFullBalance() async => moneroAmountToString(
|
Future<String> getFullBalance() async => moneroAmountToString(
|
||||||
amount: moneroWallet.getFullBalance(accountIndex: _account.value.id));
|
amount: monero_wallet.getFullBalance(accountIndex: _account.value.id));
|
||||||
|
|
||||||
|
@override
|
||||||
Future<String> getUnlockedBalance() async => moneroAmountToString(
|
Future<String> getUnlockedBalance() async => moneroAmountToString(
|
||||||
amount: moneroWallet.getUnlockedBalance(accountIndex: _account.value.id));
|
amount:
|
||||||
|
monero_wallet.getUnlockedBalance(accountIndex: _account.value.id));
|
||||||
|
|
||||||
Future<int> getCurrentHeight() async => moneroWallet.getCurrentHeight();
|
@override
|
||||||
|
Future<int> getCurrentHeight() async => monero_wallet.getCurrentHeight();
|
||||||
|
|
||||||
Future<int> getNodeHeight() async => moneroWallet.getNodeHeight();
|
@override
|
||||||
|
Future<int> getNodeHeight() async => monero_wallet.getNodeHeight();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<bool> isConnected() async => monero_wallet.isConnected();
|
||||||
|
|
||||||
|
@override
|
||||||
Future<Map<String, String>> getKeys() async => {
|
Future<Map<String, String>> getKeys() async => {
|
||||||
'publicViewKey': moneroWallet.getPublicViewKey(),
|
'publicViewKey': monero_wallet.getPublicViewKey(),
|
||||||
'privateViewKey': moneroWallet.getSecretViewKey(),
|
'privateViewKey': monero_wallet.getSecretViewKey(),
|
||||||
'publicSpendKey': moneroWallet.getPublicSpendKey(),
|
'publicSpendKey': monero_wallet.getPublicSpendKey(),
|
||||||
'privateSpendKey': moneroWallet.getSecretSpendKey()
|
'privateSpendKey': monero_wallet.getSecretSpendKey()
|
||||||
};
|
};
|
||||||
|
|
||||||
Future close() async {
|
@override
|
||||||
moneroWallet.closeListeners();
|
|
||||||
moneroWallet.closeCurrentWallet();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future connectToNode(
|
|
||||||
{Node node, bool useSSL = false, bool isLightWallet = false}) async {
|
|
||||||
try {
|
|
||||||
_syncStatus.value = ConnectingSyncStatus();
|
|
||||||
await moneroWallet.setupNode(
|
|
||||||
address: node.uri,
|
|
||||||
login: node.login,
|
|
||||||
password: node.password,
|
|
||||||
useSSL: useSSL,
|
|
||||||
isLightWallet: isLightWallet);
|
|
||||||
_syncStatus.value = ConnectedSyncStatus();
|
|
||||||
} catch (e) {
|
|
||||||
_syncStatus.value = FailedSyncStatus();
|
|
||||||
print(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future startSync() async {
|
|
||||||
try {
|
|
||||||
_syncStatus.value = StartingSyncStatus();
|
|
||||||
moneroWallet.startRefresh();
|
|
||||||
} on PlatformException catch (e) {
|
|
||||||
_syncStatus.value = FailedSyncStatus();
|
|
||||||
print(e);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TransactionHistory getHistory() {
|
TransactionHistory getHistory() {
|
||||||
if (_cachedTransactionHistory == null) {
|
if (_cachedTransactionHistory == null) {
|
||||||
_cachedTransactionHistory = MoneroTransactionHistory();
|
_cachedTransactionHistory = MoneroTransactionHistory();
|
||||||
|
@ -220,6 +216,45 @@ class MoneroWallet extends Wallet {
|
||||||
return _cachedAccountList;
|
return _cachedAccountList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future close() async {
|
||||||
|
monero_wallet.closeListeners();
|
||||||
|
monero_wallet.closeCurrentWallet();
|
||||||
|
await _name.close();
|
||||||
|
await _address.close();
|
||||||
|
await _subaddress.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future connectToNode(
|
||||||
|
{Node node, bool useSSL = false, bool isLightWallet = false}) async {
|
||||||
|
try {
|
||||||
|
_syncStatus.value = ConnectingSyncStatus();
|
||||||
|
await monero_wallet.setupNode(
|
||||||
|
address: node.uri,
|
||||||
|
login: node.login,
|
||||||
|
password: node.password,
|
||||||
|
useSSL: useSSL,
|
||||||
|
isLightWallet: isLightWallet);
|
||||||
|
_syncStatus.value = ConnectedSyncStatus();
|
||||||
|
} catch (e) {
|
||||||
|
_syncStatus.value = FailedSyncStatus();
|
||||||
|
print(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future startSync() async {
|
||||||
|
try {
|
||||||
|
_syncStatus.value = StartingSyncStatus();
|
||||||
|
monero_wallet.startRefresh();
|
||||||
|
} on PlatformException catch (e) {
|
||||||
|
_syncStatus.value = FailedSyncStatus();
|
||||||
|
print(e);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future askForSave() async {
|
Future askForSave() async {
|
||||||
final diff = DateTime.now().millisecondsSinceEpoch - _lastSaveTime;
|
final diff = DateTime.now().millisecondsSinceEpoch - _lastSaveTime;
|
||||||
|
|
||||||
|
@ -238,12 +273,11 @@ class MoneroWallet extends Wallet {
|
||||||
return _cachedBlockchainHeight;
|
return _cachedBlockchainHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<PendingTransaction> createTransaction(
|
Future<PendingTransaction> createTransaction(
|
||||||
TransactionCreationCredentials credentials) async {
|
TransactionCreationCredentials credentials) async {
|
||||||
MoneroTransactionCreationCredentials _credentials =
|
final _credentials = credentials as MoneroTransactionCreationCredentials;
|
||||||
credentials as MoneroTransactionCreationCredentials;
|
final transactionDescription = await transaction_history.createTransaction(
|
||||||
|
|
||||||
final transactionDescription = await transactionHistory.createTransaction(
|
|
||||||
address: _credentials.address,
|
address: _credentials.address,
|
||||||
paymentId: _credentials.paymentId,
|
paymentId: _credentials.paymentId,
|
||||||
amount: _credentials.amount,
|
amount: _credentials.amount,
|
||||||
|
@ -254,13 +288,19 @@ class MoneroWallet extends Wallet {
|
||||||
transactionDescription);
|
transactionDescription);
|
||||||
}
|
}
|
||||||
|
|
||||||
setRecoveringFromSeed() =>
|
@override
|
||||||
moneroWallet.setRecoveringFromSeed(isRecovery: true);
|
Future rescan({int restoreHeight = 0}) async {
|
||||||
|
_syncStatus.value = StartingSyncStatus();
|
||||||
|
setRefreshFromBlockHeight(height: restoreHeight);
|
||||||
|
monero_wallet.rescanBlockchainAsync();
|
||||||
|
_syncStatus.value = StartingSyncStatus();
|
||||||
|
}
|
||||||
|
|
||||||
setRefreshFromBlockHeight({int height}) =>
|
void setRecoveringFromSeed() =>
|
||||||
moneroWallet.setRefreshFromBlockHeight(height: height);
|
monero_wallet.setRecoveringFromSeed(isRecovery: true);
|
||||||
|
|
||||||
Future<bool> isConnected() async => moneroWallet.isConnected();
|
void setRefreshFromBlockHeight({int height}) =>
|
||||||
|
monero_wallet.setRefreshFromBlockHeight(height: height);
|
||||||
|
|
||||||
Future setAsRecovered() async {
|
Future setAsRecovered() async {
|
||||||
walletInfo.isRecovery = false;
|
walletInfo.isRecovery = false;
|
||||||
|
@ -285,22 +325,15 @@ class MoneroWallet extends Wallet {
|
||||||
|
|
||||||
Future askForUpdateTransactionHistory() async => await getHistory().update();
|
Future askForUpdateTransactionHistory() async => await getHistory().update();
|
||||||
|
|
||||||
Future rescan({int restoreHeight = 0}) async {
|
void changeCurrentSubaddress(Subaddress subaddress) =>
|
||||||
_syncStatus.value = StartingSyncStatus();
|
|
||||||
setRefreshFromBlockHeight(height: restoreHeight);
|
|
||||||
moneroWallet.rescanBlockchainAsync();
|
|
||||||
_syncStatus.value = StartingSyncStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
changeCurrentSubaddress(Subaddress subaddress) =>
|
|
||||||
_subaddress.value = subaddress;
|
_subaddress.value = subaddress;
|
||||||
|
|
||||||
changeAccount(Account account) {
|
void changeAccount(Account account) {
|
||||||
_account.add(account);
|
_account.add(account);
|
||||||
|
|
||||||
getSubaddress()
|
getSubaddress()
|
||||||
.refresh(accountIndex: account.id)
|
.refresh(accountIndex: account.id)
|
||||||
.then((_) => getSubaddress().getAll())
|
.then((dynamic _) => getSubaddress().getAll())
|
||||||
.then((subaddresses) => _subaddress.value = subaddresses[0]);
|
.then((subaddresses) => _subaddress.value = subaddresses[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,16 +344,16 @@ class MoneroWallet extends Wallet {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_isSaving = true;
|
_isSaving = true;
|
||||||
moneroWallet.store();
|
await monero_wallet.store();
|
||||||
_isSaving = false;
|
_isSaving = false;
|
||||||
} on PlatformException catch (e) {
|
} on PlatformException catch (e) {
|
||||||
print(e);
|
print(e);
|
||||||
_isSaving = false;
|
_isSaving = false;
|
||||||
throw e;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setListeners() => moneroWallet.setListeners(
|
void setListeners() => monero_wallet.setListeners(
|
||||||
_onNewBlock, _onNeedToRefresh, _onNewTransaction);
|
_onNewBlock, _onNeedToRefresh, _onNewTransaction);
|
||||||
|
|
||||||
Future _onNewBlock(int height) async {
|
Future _onNewBlock(int height) async {
|
||||||
|
@ -333,13 +366,13 @@ class MoneroWallet extends Wallet {
|
||||||
|
|
||||||
if (isRecovery &&
|
if (isRecovery &&
|
||||||
(_lastSyncHeight == 0 ||
|
(_lastSyncHeight == 0 ||
|
||||||
(height - _lastSyncHeight) > monero_block_size)) {
|
(height - _lastSyncHeight) > moneroBlockSize)) {
|
||||||
_lastSyncHeight = height;
|
_lastSyncHeight = height;
|
||||||
askForUpdateBalance();
|
await askForUpdateBalance();
|
||||||
askForUpdateTransactionHistory();
|
await askForUpdateTransactionHistory();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (height > 0 && ((nodeHeight - height) < monero_block_size)) {
|
if (height > 0 && ((nodeHeight - height) < moneroBlockSize)) {
|
||||||
_syncStatus.add(SyncedSyncStatus());
|
_syncStatus.add(SyncedSyncStatus());
|
||||||
} else {
|
} else {
|
||||||
_syncStatus.add(SyncingSyncStatus(height, nodeHeight, _refreshHeight));
|
_syncStatus.add(SyncingSyncStatus(height, nodeHeight, _refreshHeight));
|
||||||
|
@ -363,15 +396,15 @@ class MoneroWallet extends Wallet {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
askForUpdateBalance();
|
await askForUpdateBalance();
|
||||||
|
|
||||||
_syncStatus.add(SyncedSyncStatus());
|
_syncStatus.add(SyncedSyncStatus());
|
||||||
|
|
||||||
if (isRecovery) {
|
if (isRecovery) {
|
||||||
askForUpdateTransactionHistory();
|
await askForUpdateTransactionHistory();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isRecovery && (nodeHeight - currentHeight < monero_block_size)) {
|
if (isRecovery && (nodeHeight - currentHeight < moneroBlockSize)) {
|
||||||
await setAsRecovered();
|
await setAsRecovered();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import 'dart:io';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:cw_monero/wallet_manager.dart' as moneroWalletManager;
|
import 'package:cw_monero/wallet_manager.dart' as monero_wallet_manager;
|
||||||
import 'package:cake_wallet/src/domain/common/wallet_info.dart';
|
import 'package:cake_wallet/src/domain/common/wallet_info.dart';
|
||||||
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
|
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
|
||||||
import 'package:cake_wallet/src/domain/common/wallets_manager.dart';
|
import 'package:cake_wallet/src/domain/common/wallets_manager.dart';
|
||||||
|
@ -24,54 +24,61 @@ Future<String> pathForWallet({String name}) async {
|
||||||
}
|
}
|
||||||
|
|
||||||
class MoneroWalletsManager extends WalletsManager {
|
class MoneroWalletsManager extends WalletsManager {
|
||||||
|
MoneroWalletsManager({@required this.walletInfoSource});
|
||||||
|
|
||||||
static const type = WalletType.monero;
|
static const type = WalletType.monero;
|
||||||
|
|
||||||
Box<WalletInfo> walletInfoSource;
|
Box<WalletInfo> walletInfoSource;
|
||||||
|
|
||||||
MoneroWalletsManager({@required this.walletInfoSource});
|
@override
|
||||||
|
|
||||||
Future<Wallet> create(String name, String password) async {
|
Future<Wallet> create(String name, String password) async {
|
||||||
try {
|
try {
|
||||||
const isRecovery = false;
|
const isRecovery = false;
|
||||||
final path = await pathForWallet(name: name);
|
final path = await pathForWallet(name: name);
|
||||||
|
|
||||||
await moneroWalletManager.createWallet(path: path, password: password);
|
await monero_wallet_manager.createWallet(path: path, password: password);
|
||||||
|
|
||||||
final wallet = await MoneroWallet.createdWallet(
|
final wallet = await MoneroWallet.createdWallet(
|
||||||
walletInfoSource: walletInfoSource, name: name, isRecovery: isRecovery)
|
walletInfoSource: walletInfoSource,
|
||||||
..updateInfo();
|
name: name,
|
||||||
|
isRecovery: isRecovery);
|
||||||
|
await wallet.updateInfo();
|
||||||
|
|
||||||
return wallet;
|
return wallet;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('MoneroWalletsManager Error: $e');
|
print('MoneroWalletsManager Error: $e');
|
||||||
throw e;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<Wallet> restoreFromSeed(
|
Future<Wallet> restoreFromSeed(
|
||||||
String name, String password, String seed, int restoreHeight) async {
|
String name, String password, String seed, int restoreHeight) async {
|
||||||
try {
|
try {
|
||||||
const isRecovery = true;
|
const isRecovery = true;
|
||||||
final path = await pathForWallet(name: name);
|
final path = await pathForWallet(name: name);
|
||||||
|
|
||||||
await moneroWalletManager.restoreFromSeed(
|
await monero_wallet_manager.restoreFromSeed(
|
||||||
path: path,
|
path: path,
|
||||||
password: password,
|
password: password,
|
||||||
seed: seed,
|
seed: seed,
|
||||||
restoreHeight: restoreHeight);
|
restoreHeight: restoreHeight);
|
||||||
|
|
||||||
return await MoneroWallet.createdWallet(
|
final wallet = await MoneroWallet.createdWallet(
|
||||||
walletInfoSource: walletInfoSource,
|
walletInfoSource: walletInfoSource,
|
||||||
name: name,
|
name: name,
|
||||||
isRecovery: isRecovery,
|
isRecovery: isRecovery,
|
||||||
restoreHeight: restoreHeight)
|
restoreHeight: restoreHeight);
|
||||||
..updateInfo();
|
await wallet.updateInfo();
|
||||||
|
|
||||||
|
return wallet;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('MoneroWalletsManager Error: $e');
|
print('MoneroWalletsManager Error: $e');
|
||||||
throw e;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<Wallet> restoreFromKeys(
|
Future<Wallet> restoreFromKeys(
|
||||||
String name,
|
String name,
|
||||||
String password,
|
String password,
|
||||||
|
@ -83,7 +90,7 @@ class MoneroWalletsManager extends WalletsManager {
|
||||||
const isRecovery = true;
|
const isRecovery = true;
|
||||||
final path = await pathForWallet(name: name);
|
final path = await pathForWallet(name: name);
|
||||||
|
|
||||||
await moneroWalletManager.restoreFromKeys(
|
await monero_wallet_manager.restoreFromKeys(
|
||||||
path: path,
|
path: path,
|
||||||
password: password,
|
password: password,
|
||||||
restoreHeight: restoreHeight,
|
restoreHeight: restoreHeight,
|
||||||
|
@ -95,40 +102,43 @@ class MoneroWalletsManager extends WalletsManager {
|
||||||
walletInfoSource: walletInfoSource,
|
walletInfoSource: walletInfoSource,
|
||||||
name: name,
|
name: name,
|
||||||
isRecovery: isRecovery,
|
isRecovery: isRecovery,
|
||||||
restoreHeight: restoreHeight)
|
restoreHeight: restoreHeight);
|
||||||
..updateInfo();
|
await wallet.updateInfo();
|
||||||
|
|
||||||
return wallet;
|
return wallet;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('MoneroWalletsManager Error: $e');
|
print('MoneroWalletsManager Error: $e');
|
||||||
throw e;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<Wallet> openWallet(String name, String password) async {
|
Future<Wallet> openWallet(String name, String password) async {
|
||||||
try {
|
try {
|
||||||
final path = await pathForWallet(name: name);
|
final path = await pathForWallet(name: name);
|
||||||
await moneroWalletManager.openWallet(path: path, password: password);
|
monero_wallet_manager.openWallet(path: path, password: password);
|
||||||
final wallet = await MoneroWallet.load(walletInfoSource, name, type)
|
final wallet = await MoneroWallet.load(walletInfoSource, name, type);
|
||||||
..updateInfo();
|
await wallet.updateInfo();
|
||||||
|
|
||||||
return wallet;
|
return wallet;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('MoneroWalletsManager Error: $e');
|
print('MoneroWalletsManager Error: $e');
|
||||||
throw e;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future<bool> isWalletExit(String name) async {
|
Future<bool> isWalletExit(String name) async {
|
||||||
try {
|
try {
|
||||||
final path = await pathForWallet(name: name);
|
final path = await pathForWallet(name: name);
|
||||||
return moneroWalletManager.isWalletExist(path: path);
|
return monero_wallet_manager.isWalletExist(path: path);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('MoneroWalletsManager Error: $e');
|
print('MoneroWalletsManager Error: $e');
|
||||||
throw e;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Future remove(WalletDescription wallet) async {
|
Future remove(WalletDescription wallet) async {
|
||||||
final dir = await getApplicationDocumentsDirectory();
|
final dir = await getApplicationDocumentsDirectory();
|
||||||
final root = dir.path.replaceAll('app_flutter', 'files');
|
final root = dir.path.replaceAll('app_flutter', 'files');
|
||||||
|
@ -153,7 +163,8 @@ class MoneroWalletsManager extends WalletsManager {
|
||||||
|
|
||||||
final id =
|
final id =
|
||||||
walletTypeToString(wallet.type).toLowerCase() + '_' + wallet.name;
|
walletTypeToString(wallet.type).toLowerCase() + '_' + wallet.name;
|
||||||
final info = walletInfoSource.values.firstWhere((info) => info.id == id, orElse: () => null);
|
final info = walletInfoSource.values
|
||||||
|
.firstWhere((info) => info.id == id, orElse: () => null);
|
||||||
|
|
||||||
await info?.delete();
|
await info?.delete();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
import 'package:cw_monero/structs/subaddress_row.dart';
|
import 'package:cw_monero/structs/subaddress_row.dart';
|
||||||
|
|
||||||
class Subaddress {
|
class Subaddress {
|
||||||
final int id;
|
|
||||||
final String address;
|
|
||||||
final String label;
|
|
||||||
|
|
||||||
Subaddress({this.id, this.address, this.label});
|
Subaddress({this.id, this.address, this.label});
|
||||||
|
|
||||||
Subaddress.fromMap(Map map)
|
Subaddress.fromMap(Map map)
|
||||||
: this.id = map['id'] == null ? 0 : int.parse(map['id']),
|
: this.id = map['id'] == null ? 0 : int.parse(map['id'] as String),
|
||||||
this.address = map['address'] ?? '',
|
this.address = (map['address'] ?? '') as String,
|
||||||
this.label = map['label'] ?? '';
|
this.label = (map['label'] ?? '') as String;
|
||||||
|
|
||||||
Subaddress.fromRow(SubaddressRow row)
|
Subaddress.fromRow(SubaddressRow row)
|
||||||
: this.id = row.getId(),
|
: this.id = row.getId(),
|
||||||
this.address = row.getAddress(),
|
this.address = row.getAddress(),
|
||||||
this.label = row.getLabel();
|
this.label = row.getLabel();
|
||||||
|
|
||||||
|
final int id;
|
||||||
|
final String address;
|
||||||
|
final String label;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:rxdart/rxdart.dart';
|
import 'package:rxdart/rxdart.dart';
|
||||||
import 'package:cw_monero/subaddress_list.dart' as subaddressListAPI;
|
import 'package:cw_monero/subaddress_list.dart' as subaddress_list;
|
||||||
import 'package:cake_wallet/src/domain/monero/subaddress.dart';
|
import 'package:cake_wallet/src/domain/monero/subaddress.dart';
|
||||||
|
|
||||||
class SubaddressList {
|
class SubaddressList {
|
||||||
get subaddresses => _subaddress.stream;
|
|
||||||
BehaviorSubject<List<Subaddress>> _subaddress;
|
|
||||||
|
|
||||||
bool _isRefreshing;
|
|
||||||
bool _isUpdating;
|
|
||||||
|
|
||||||
SubaddressList() {
|
SubaddressList() {
|
||||||
_isRefreshing = false;
|
_isRefreshing = false;
|
||||||
_isUpdating = false;
|
_isUpdating = false;
|
||||||
_subaddress = BehaviorSubject<List<Subaddress>>();
|
_subaddress = BehaviorSubject<List<Subaddress>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Observable<List<Subaddress>> get subaddresses => _subaddress.stream;
|
||||||
|
|
||||||
|
BehaviorSubject<List<Subaddress>> _subaddress;
|
||||||
|
bool _isRefreshing;
|
||||||
|
bool _isUpdating;
|
||||||
|
|
||||||
Future update({int accountIndex}) async {
|
Future update({int accountIndex}) async {
|
||||||
if (_isUpdating) {
|
if (_isUpdating) {
|
||||||
return;
|
return;
|
||||||
|
@ -29,25 +29,26 @@ class SubaddressList {
|
||||||
_isUpdating = false;
|
_isUpdating = false;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
_isUpdating = false;
|
_isUpdating = false;
|
||||||
throw e;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Subaddress> getAll() {
|
List<Subaddress> getAll() {
|
||||||
return subaddressListAPI
|
return subaddress_list
|
||||||
.getAllSubaddresses()
|
.getAllSubaddresses()
|
||||||
.map((subaddressRow) => Subaddress.fromRow(subaddressRow))
|
.map((subaddressRow) => Subaddress.fromRow(subaddressRow))
|
||||||
.toList();
|
.toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future addSubaddress({int accountIndex, String label}) async {
|
Future addSubaddress({int accountIndex, String label}) async {
|
||||||
await subaddressListAPI.addSubaddress(accountIndex: accountIndex, label: label);
|
await subaddress_list.addSubaddress(
|
||||||
|
accountIndex: accountIndex, label: label);
|
||||||
await update(accountIndex: accountIndex);
|
await update(accountIndex: accountIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future setLabelSubaddress(
|
Future setLabelSubaddress(
|
||||||
{int accountIndex, int addressIndex, String label}) async {
|
{int accountIndex, int addressIndex, String label}) async {
|
||||||
await subaddressListAPI.setLabelForSubaddress(
|
await subaddress_list.setLabelForSubaddress(
|
||||||
accountIndex: accountIndex, addressIndex: addressIndex, label: label);
|
accountIndex: accountIndex, addressIndex: addressIndex, label: label);
|
||||||
await update();
|
await update();
|
||||||
}
|
}
|
||||||
|
@ -59,12 +60,12 @@ class SubaddressList {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_isRefreshing = true;
|
_isRefreshing = true;
|
||||||
subaddressListAPI.refreshSubaddresses(accountIndex: accountIndex);
|
subaddress_list.refreshSubaddresses(accountIndex: accountIndex);
|
||||||
_isRefreshing = false;
|
_isRefreshing = false;
|
||||||
} on PlatformException catch (e) {
|
} on PlatformException catch (e) {
|
||||||
_isRefreshing = false;
|
_isRefreshing = false;
|
||||||
print(e);
|
print(e);
|
||||||
throw e;
|
rethrow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,8 @@ part 'transaction_description.g.dart';
|
||||||
|
|
||||||
@HiveType()
|
@HiveType()
|
||||||
class TransactionDescription extends HiveObject {
|
class TransactionDescription extends HiveObject {
|
||||||
|
TransactionDescription({this.id, this.recipientAddress});
|
||||||
|
|
||||||
static const boxName = 'TransactionDescriptions';
|
static const boxName = 'TransactionDescriptions';
|
||||||
|
|
||||||
@HiveField(0)
|
@HiveField(0)
|
||||||
|
@ -11,6 +13,4 @@ class TransactionDescription extends HiveObject {
|
||||||
|
|
||||||
@HiveField(1)
|
@HiveField(1)
|
||||||
String recipientAddress;
|
String recipientAddress;
|
||||||
|
|
||||||
TransactionDescription({this.id, this.recipientAddress});
|
|
||||||
}
|
}
|
|
@ -4,11 +4,11 @@ import 'package:cake_wallet/src/domain/common/secret_store_key.dart';
|
||||||
import 'package:cake_wallet/src/domain/common/encrypt.dart';
|
import 'package:cake_wallet/src/domain/common/encrypt.dart';
|
||||||
|
|
||||||
class UserService {
|
class UserService {
|
||||||
|
UserService({this.sharedPreferences, this.secureStorage});
|
||||||
|
|
||||||
final FlutterSecureStorage secureStorage;
|
final FlutterSecureStorage secureStorage;
|
||||||
final SharedPreferences sharedPreferences;
|
final SharedPreferences sharedPreferences;
|
||||||
|
|
||||||
UserService({this.sharedPreferences, this.secureStorage});
|
|
||||||
|
|
||||||
Future setPassword(String password) async {
|
Future setPassword(String password) async {
|
||||||
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
|
||||||
|
|
||||||
|
|
|
@ -15,21 +15,15 @@ import 'package:cake_wallet/src/domain/monero/monero_wallets_manager.dart';
|
||||||
import 'package:cake_wallet/src/domain/services/wallet_service.dart';
|
import 'package:cake_wallet/src/domain/services/wallet_service.dart';
|
||||||
|
|
||||||
class WalletIsExistException implements Exception {
|
class WalletIsExistException implements Exception {
|
||||||
String name;
|
|
||||||
|
|
||||||
WalletIsExistException(this.name);
|
WalletIsExistException(this.name);
|
||||||
|
|
||||||
|
String name;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => "Wallet with name $name is already exist!";
|
String toString() => "Wallet with name $name is already exist!";
|
||||||
}
|
}
|
||||||
|
|
||||||
class WalletListService {
|
class WalletListService {
|
||||||
final FlutterSecureStorage secureStorage;
|
|
||||||
final WalletService walletService;
|
|
||||||
final Box<WalletInfo> walletInfoSource;
|
|
||||||
final SharedPreferences sharedPreferences;
|
|
||||||
WalletsManager walletsManager;
|
|
||||||
|
|
||||||
WalletListService(
|
WalletListService(
|
||||||
{this.secureStorage,
|
{this.secureStorage,
|
||||||
this.walletInfoSource,
|
this.walletInfoSource,
|
||||||
|
@ -37,6 +31,12 @@ class WalletListService {
|
||||||
@required this.walletService,
|
@required this.walletService,
|
||||||
@required this.sharedPreferences});
|
@required this.sharedPreferences});
|
||||||
|
|
||||||
|
final FlutterSecureStorage secureStorage;
|
||||||
|
final WalletService walletService;
|
||||||
|
final Box<WalletInfo> walletInfoSource;
|
||||||
|
final SharedPreferences sharedPreferences;
|
||||||
|
WalletsManager walletsManager;
|
||||||
|
|
||||||
Future<List<WalletDescription>> getAll() async => walletInfoSource.values
|
Future<List<WalletDescription>> getAll() async => walletInfoSource.values
|
||||||
.map((info) => WalletDescription(name: info.name, type: info.type))
|
.map((info) => WalletDescription(name: info.name, type: info.type))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
|
@ -10,17 +10,40 @@ import 'package:cake_wallet/src/domain/common/pending_transaction.dart';
|
||||||
import 'package:cake_wallet/src/domain/common/node.dart';
|
import 'package:cake_wallet/src/domain/common/node.dart';
|
||||||
|
|
||||||
class WalletService extends Wallet {
|
class WalletService extends Wallet {
|
||||||
Observable<Wallet> get onWalletChange => _onWalletChanged.stream;
|
WalletService() {
|
||||||
|
_currentWallet = null;
|
||||||
|
walletType = WalletType.none;
|
||||||
|
_syncStatus = BehaviorSubject<SyncStatus>();
|
||||||
|
_onBalanceChange = BehaviorSubject<Balance>();
|
||||||
|
_onWalletChanged = BehaviorSubject<Wallet>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
Observable<Balance> get onBalanceChange => _onBalanceChange.stream;
|
Observable<Balance> get onBalanceChange => _onBalanceChange.stream;
|
||||||
|
|
||||||
|
@override
|
||||||
Observable<SyncStatus> get syncStatus => _syncStatus.stream;
|
Observable<SyncStatus> get syncStatus => _syncStatus.stream;
|
||||||
|
|
||||||
|
@override
|
||||||
Observable<String> get onAddressChange => _currentWallet.onAddressChange;
|
Observable<String> get onAddressChange => _currentWallet.onAddressChange;
|
||||||
|
|
||||||
|
@override
|
||||||
Observable<String> get onNameChange => _currentWallet.onNameChange;
|
Observable<String> get onNameChange => _currentWallet.onNameChange;
|
||||||
|
|
||||||
|
@override
|
||||||
String get address => _currentWallet.address;
|
String get address => _currentWallet.address;
|
||||||
|
|
||||||
|
@override
|
||||||
String get name => _currentWallet.name;
|
String get name => _currentWallet.name;
|
||||||
SyncStatus get syncStatusValue => _syncStatus.value;
|
|
||||||
|
@override
|
||||||
WalletType get walletType => _currentWallet.walletType;
|
WalletType get walletType => _currentWallet.walletType;
|
||||||
|
|
||||||
get currentWallet => _currentWallet;
|
Observable<Wallet> get onWalletChange => _onWalletChanged.stream;
|
||||||
|
|
||||||
|
SyncStatus get syncStatusValue => _syncStatus.value;
|
||||||
|
|
||||||
|
Wallet get currentWallet => _currentWallet;
|
||||||
|
|
||||||
set currentWallet(Wallet wallet) {
|
set currentWallet(Wallet wallet) {
|
||||||
_currentWallet = wallet;
|
_currentWallet = wallet;
|
||||||
|
@ -44,55 +67,65 @@ class WalletService extends Wallet {
|
||||||
BehaviorSubject<SyncStatus> _syncStatus;
|
BehaviorSubject<SyncStatus> _syncStatus;
|
||||||
Wallet _currentWallet;
|
Wallet _currentWallet;
|
||||||
|
|
||||||
WalletService() {
|
|
||||||
_currentWallet = null;
|
|
||||||
walletType = WalletType.none;
|
|
||||||
_syncStatus = BehaviorSubject<SyncStatus>();
|
|
||||||
_onBalanceChange = BehaviorSubject<Balance>();
|
|
||||||
_onWalletChanged = BehaviorSubject<Wallet>();
|
|
||||||
}
|
|
||||||
|
|
||||||
WalletDescription description;
|
WalletDescription description;
|
||||||
|
|
||||||
|
@override
|
||||||
WalletType getType() => WalletType.monero;
|
WalletType getType() => WalletType.monero;
|
||||||
|
|
||||||
|
@override
|
||||||
Future<String> getFilename() => _currentWallet.getFilename();
|
Future<String> getFilename() => _currentWallet.getFilename();
|
||||||
|
|
||||||
|
@override
|
||||||
Future<String> getName() => _currentWallet.getName();
|
Future<String> getName() => _currentWallet.getName();
|
||||||
|
|
||||||
|
@override
|
||||||
Future<String> getAddress() => _currentWallet.getAddress();
|
Future<String> getAddress() => _currentWallet.getAddress();
|
||||||
|
|
||||||
|
@override
|
||||||
Future<String> getSeed() => _currentWallet.getSeed();
|
Future<String> getSeed() => _currentWallet.getSeed();
|
||||||
|
|
||||||
|
@override
|
||||||
Future<Map<String, String>> getKeys() => _currentWallet.getKeys();
|
Future<Map<String, String>> getKeys() => _currentWallet.getKeys();
|
||||||
|
|
||||||
|
@override
|
||||||
Future<String> getFullBalance() => _currentWallet.getFullBalance();
|
Future<String> getFullBalance() => _currentWallet.getFullBalance();
|
||||||
|
|
||||||
|
@override
|
||||||
Future<String> getUnlockedBalance() => _currentWallet.getUnlockedBalance();
|
Future<String> getUnlockedBalance() => _currentWallet.getUnlockedBalance();
|
||||||
|
|
||||||
|
@override
|
||||||
Future<int> getCurrentHeight() => _currentWallet.getCurrentHeight();
|
Future<int> getCurrentHeight() => _currentWallet.getCurrentHeight();
|
||||||
|
|
||||||
|
@override
|
||||||
Future<int> getNodeHeight() => _currentWallet.getNodeHeight();
|
Future<int> getNodeHeight() => _currentWallet.getNodeHeight();
|
||||||
|
|
||||||
|
@override
|
||||||
Future<bool> isConnected() => _currentWallet.isConnected();
|
Future<bool> isConnected() => _currentWallet.isConnected();
|
||||||
|
|
||||||
|
@override
|
||||||
Future close() => _currentWallet.close();
|
Future close() => _currentWallet.close();
|
||||||
|
|
||||||
Future connectToNode({Node node, bool useSSL = false, bool isLightWallet = false}) =>
|
@override
|
||||||
|
Future connectToNode(
|
||||||
|
{Node node, bool useSSL = false, bool isLightWallet = false}) =>
|
||||||
_currentWallet.connectToNode(
|
_currentWallet.connectToNode(
|
||||||
node: node,
|
node: node, useSSL: useSSL, isLightWallet: isLightWallet);
|
||||||
useSSL: useSSL,
|
|
||||||
isLightWallet: isLightWallet);
|
|
||||||
|
|
||||||
|
@override
|
||||||
Future startSync() => _currentWallet.startSync();
|
Future startSync() => _currentWallet.startSync();
|
||||||
|
|
||||||
|
@override
|
||||||
TransactionHistory getHistory() => _currentWallet.getHistory();
|
TransactionHistory getHistory() => _currentWallet.getHistory();
|
||||||
|
|
||||||
|
@override
|
||||||
Future<PendingTransaction> createTransaction(
|
Future<PendingTransaction> createTransaction(
|
||||||
TransactionCreationCredentials credentials) =>
|
TransactionCreationCredentials credentials) =>
|
||||||
_currentWallet.createTransaction(credentials);
|
_currentWallet.createTransaction(credentials);
|
||||||
|
|
||||||
|
@override
|
||||||
Future updateInfo() async => _currentWallet.updateInfo();
|
Future updateInfo() async => _currentWallet.updateInfo();
|
||||||
|
|
||||||
Future rescan({int restoreHeight = 0}) async => _currentWallet.rescan(restoreHeight: restoreHeight);
|
@override
|
||||||
|
Future rescan({int restoreHeight = 0}) async =>
|
||||||
|
_currentWallet.rescan(restoreHeight: restoreHeight);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:mobx/mobx.dart';
|
import 'package:mobx/mobx.dart';
|
||||||
|
import 'package:cake_wallet/src/domain/common/node.dart';
|
||||||
import 'package:cake_wallet/src/domain/common/sync_status.dart';
|
import 'package:cake_wallet/src/domain/common/sync_status.dart';
|
||||||
import 'package:cake_wallet/src/domain/services/wallet_service.dart';
|
import 'package:cake_wallet/src/domain/services/wallet_service.dart';
|
||||||
import 'package:cake_wallet/src/start_updating_price.dart';
|
import 'package:cake_wallet/src/start_updating_price.dart';
|
||||||
|
@ -11,7 +12,12 @@ import 'package:cake_wallet/src/stores/price/price_store.dart';
|
||||||
import 'package:cake_wallet/src/stores/authentication/authentication_store.dart';
|
import 'package:cake_wallet/src/stores/authentication/authentication_store.dart';
|
||||||
import 'package:cake_wallet/src/stores/login/login_store.dart';
|
import 'package:cake_wallet/src/stores/login/login_store.dart';
|
||||||
|
|
||||||
setReactions(
|
Timer _reconnectionTimer;
|
||||||
|
ReactionDisposer _connectToNodeDisposer;
|
||||||
|
ReactionDisposer _onSyncStatusChangeDisposer;
|
||||||
|
ReactionDisposer _onCurrentWalletChangeDisposer;
|
||||||
|
|
||||||
|
void setReactions(
|
||||||
{@required SettingsStore settingsStore,
|
{@required SettingsStore settingsStore,
|
||||||
@required PriceStore priceStore,
|
@required PriceStore priceStore,
|
||||||
@required SyncStore syncStore,
|
@required SyncStore syncStore,
|
||||||
|
@ -36,29 +42,44 @@ setReactions(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
connectToNode({SettingsStore settingsStore, WalletStore walletStore}) =>
|
void connectToNode({SettingsStore settingsStore, WalletStore walletStore}) {
|
||||||
reaction((_) => settingsStore.node,
|
_connectToNodeDisposer?.call();
|
||||||
(node) async => await walletStore.connectToNode(node: node));
|
|
||||||
|
|
||||||
onSyncStatusChange(
|
_connectToNodeDisposer = reaction((_) => settingsStore.node,
|
||||||
|
(Node node) async => await walletStore.connectToNode(node: node));
|
||||||
|
}
|
||||||
|
|
||||||
|
void onCurrentWalletChange(
|
||||||
|
{WalletStore walletStore,
|
||||||
|
SettingsStore settingsStore,
|
||||||
|
PriceStore priceStore}) {
|
||||||
|
_onCurrentWalletChangeDisposer?.call();
|
||||||
|
|
||||||
|
reaction((_) => walletStore.name, (String _) {
|
||||||
|
walletStore.connectToNode(node: settingsStore.node);
|
||||||
|
startUpdatingPrice(settingsStore: settingsStore, priceStore: priceStore);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void onSyncStatusChange(
|
||||||
{SyncStore syncStore,
|
{SyncStore syncStore,
|
||||||
WalletStore walletStore,
|
WalletStore walletStore,
|
||||||
SettingsStore settingsStore}) =>
|
SettingsStore settingsStore}) {
|
||||||
reaction((_) => syncStore.status, (status) async {
|
_onSyncStatusChangeDisposer?.call();
|
||||||
|
|
||||||
|
reaction((_) => syncStore.status, (SyncStatus status) async {
|
||||||
if (status is ConnectedSyncStatus) {
|
if (status is ConnectedSyncStatus) {
|
||||||
await walletStore.startSync();
|
await walletStore.startSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reconnect to the node if the app is not started sync after 30 seconds
|
// Reconnect to the node if the app is not started sync after 30 seconds
|
||||||
if (status is StartingSyncStatus) {
|
if (status is StartingSyncStatus) {
|
||||||
await startReconnectionObserver(
|
startReconnectionObserver(syncStore: syncStore, walletStore: walletStore);
|
||||||
syncStore: syncStore, walletStore: walletStore);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Timer _reconnectionTimer;
|
void startReconnectionObserver({SyncStore syncStore, WalletStore walletStore}) {
|
||||||
|
|
||||||
startReconnectionObserver({SyncStore syncStore, WalletStore walletStore}) {
|
|
||||||
if (_reconnectionTimer != null) {
|
if (_reconnectionTimer != null) {
|
||||||
_reconnectionTimer.cancel();
|
_reconnectionTimer.cancel();
|
||||||
}
|
}
|
||||||
|
@ -75,12 +96,3 @@ startReconnectionObserver({SyncStore syncStore, WalletStore walletStore}) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onCurrentWalletChange(
|
|
||||||
{WalletStore walletStore,
|
|
||||||
SettingsStore settingsStore,
|
|
||||||
PriceStore priceStore}) =>
|
|
||||||
reaction((_) => walletStore.name, (_) {
|
|
||||||
walletStore.connectToNode(node: settingsStore.node);
|
|
||||||
startUpdatingPrice(settingsStore: settingsStore, priceStore: priceStore);
|
|
||||||
});
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
|
||||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
|
|
||||||
class AccountListPage extends BasePage {
|
class AccountListPage extends BasePage {
|
||||||
|
@override
|
||||||
String get title => S.current.accounts;
|
String get title => S.current.accounts;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -21,8 +22,7 @@ class AccountListPage extends BasePage {
|
||||||
width: 28.0,
|
width: 28.0,
|
||||||
height: 28.0,
|
height: 28.0,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle, color: Theme.of(context).selectedRowColor),
|
||||||
color: Theme.of(context).selectedRowColor),
|
|
||||||
child: Stack(
|
child: Stack(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
|
@ -35,7 +35,7 @@ class AccountListPage extends BasePage {
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await Navigator.of(context)
|
await Navigator.of(context)
|
||||||
.pushNamed(Routes.accountCreation);
|
.pushNamed(Routes.accountCreation);
|
||||||
await accountListStore.updateAccountList();
|
accountListStore.updateAccountList();
|
||||||
},
|
},
|
||||||
child: Offstage()),
|
child: Offstage()),
|
||||||
)
|
)
|
||||||
|
@ -53,13 +53,10 @@ class AccountListPage extends BasePage {
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.only(top: 10, bottom: 20),
|
padding: EdgeInsets.only(top: 10, bottom: 20),
|
||||||
child: Observer(
|
child: Observer(builder: (_) {
|
||||||
builder: (_) {
|
|
||||||
final accounts = accountListStore.accounts;
|
final accounts = accountListStore.accounts;
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
itemCount: accounts == null
|
itemCount: accounts == null ? 0 : accounts.length,
|
||||||
? 0
|
|
||||||
: accounts.length,
|
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
final account = accounts[index];
|
final account = accounts[index];
|
||||||
|
|
||||||
|
@ -78,7 +75,10 @@ class AccountListPage extends BasePage {
|
||||||
account.label,
|
account.label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16.0,
|
fontSize: 16.0,
|
||||||
color: Theme.of(context).primaryTextTheme.headline.color),
|
color: Theme.of(context)
|
||||||
|
.primaryTextTheme
|
||||||
|
.headline
|
||||||
|
.color),
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (isCurrent) {
|
if (isCurrent) {
|
||||||
|
@ -102,8 +102,9 @@ class AccountListPage extends BasePage {
|
||||||
color: Colors.blue,
|
color: Colors.blue,
|
||||||
icon: Icons.edit,
|
icon: Icons.edit,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await Navigator.of(context)
|
await Navigator.of(context).pushNamed(
|
||||||
.pushNamed(Routes.accountCreation, arguments: account);
|
Routes.accountCreation,
|
||||||
|
arguments: account);
|
||||||
// await accountListStore.updateAccountList().then((_) {
|
// await accountListStore.updateAccountList().then((_) {
|
||||||
// if (isCurrent) walletStore.setAccount(accountListStore.accounts[index]);
|
// if (isCurrent) walletStore.setAccount(accountListStore.accounts[index]);
|
||||||
// });
|
// });
|
||||||
|
@ -113,8 +114,7 @@ class AccountListPage extends BasePage {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,22 +10,24 @@ import 'package:cake_wallet/src/domain/monero/account.dart';
|
||||||
import 'package:cake_wallet/palette.dart';
|
import 'package:cake_wallet/palette.dart';
|
||||||
|
|
||||||
class AccountPage extends BasePage {
|
class AccountPage extends BasePage {
|
||||||
String get title => 'Account';
|
AccountPage({this.account});
|
||||||
|
|
||||||
final Account account;
|
final Account account;
|
||||||
|
|
||||||
AccountPage({this.account});
|
@override
|
||||||
|
String get title => 'Account';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) => AccountForm(account);
|
Widget body(BuildContext context) => AccountForm(account);
|
||||||
}
|
}
|
||||||
|
|
||||||
class AccountForm extends StatefulWidget {
|
class AccountForm extends StatefulWidget {
|
||||||
final Account account;
|
|
||||||
|
|
||||||
AccountForm(this.account);
|
AccountForm(this.account);
|
||||||
|
|
||||||
|
final Account account;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
createState() => AccountFormState();
|
AccountFormState createState() => AccountFormState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class AccountFormState extends State<AccountForm> {
|
class AccountFormState extends State<AccountForm> {
|
||||||
|
@ -61,8 +63,8 @@ class AccountFormState extends State<AccountForm> {
|
||||||
hintStyle: TextStyle(color: Theme.of(context).hintColor),
|
hintStyle: TextStyle(color: Theme.of(context).hintColor),
|
||||||
hintText: S.of(context).account,
|
hintText: S.of(context).account,
|
||||||
focusedBorder: UnderlineInputBorder(
|
focusedBorder: UnderlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide:
|
||||||
color: Palette.cakeGreen, width: 2.0)),
|
BorderSide(color: Palette.cakeGreen, width: 2.0)),
|
||||||
enabledBorder: UnderlineInputBorder(
|
enabledBorder: UnderlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Theme.of(context).focusColor, width: 1.0))),
|
color: Theme.of(context).focusColor, width: 1.0))),
|
||||||
|
@ -88,7 +90,7 @@ class AccountFormState extends State<AccountForm> {
|
||||||
await accountListStore.addAccount(
|
await accountListStore.addAccount(
|
||||||
label: _textController.text);
|
label: _textController.text);
|
||||||
}
|
}
|
||||||
Navigator.pop(context, _textController.text);
|
Navigator.of(context).pop(_textController.text);
|
||||||
},
|
},
|
||||||
text:
|
text:
|
||||||
widget.account != null ? 'Rename' : S.of(context).add,
|
widget.account != null ? 'Rename' : S.of(context).add,
|
||||||
|
|
|
@ -12,13 +12,18 @@ import 'package:cake_wallet/src/stores/address_book/address_book_store.dart';
|
||||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
|
|
||||||
class AddressBookPage extends BasePage {
|
class AddressBookPage extends BasePage {
|
||||||
bool get isModalBackButton => true;
|
AddressBookPage({this.isEditable = true});
|
||||||
String get title => S.current.address_book;
|
|
||||||
AppBarStyle get appBarStyle => AppBarStyle.withShadow;
|
|
||||||
|
|
||||||
final bool isEditable;
|
final bool isEditable;
|
||||||
|
|
||||||
AddressBookPage({this.isEditable = true});
|
@override
|
||||||
|
bool get isModalBackButton => true;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get title => S.current.address_book;
|
||||||
|
|
||||||
|
@override
|
||||||
|
AppBarStyle get appBarStyle => AppBarStyle.withShadow;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget trailing(BuildContext context) {
|
Widget trailing(BuildContext context) {
|
||||||
|
@ -32,8 +37,7 @@ class AddressBookPage extends BasePage {
|
||||||
width: 28.0,
|
width: 28.0,
|
||||||
height: 28.0,
|
height: 28.0,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle, color: Theme.of(context).selectedRowColor),
|
||||||
color: Theme.of(context).selectedRowColor),
|
|
||||||
child: Stack(
|
child: Stack(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
|
@ -79,16 +83,17 @@ class AddressBookPage extends BasePage {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isCopied = await showNameAndAddressDialog(context, contact.name, contact.address);
|
final isCopied = await showNameAndAddressDialog(
|
||||||
|
context, contact.name, contact.address);
|
||||||
|
|
||||||
if (isCopied) {
|
if (isCopied) {
|
||||||
Clipboard.setData(ClipboardData(text: contact.address));
|
await Clipboard.setData(
|
||||||
|
ClipboardData(text: contact.address));
|
||||||
Scaffold.of(context).showSnackBar(
|
Scaffold.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content:
|
content: Text('Copied to Clipboard'),
|
||||||
Text('Copied to Clipboard'),
|
|
||||||
backgroundColor: Colors.green,
|
backgroundColor: Colors.green,
|
||||||
duration:
|
duration: Duration(milliseconds: 1500),
|
||||||
Duration(milliseconds: 1500),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -117,9 +122,10 @@ class AddressBookPage extends BasePage {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
return !isEditable ? content
|
return !isEditable
|
||||||
|
? content
|
||||||
: Slidable(
|
: Slidable(
|
||||||
key: Key('1'),// Key(contact.id.toString()),
|
key: Key('${contact.key}'),
|
||||||
actionPane: SlidableDrawerActionPane(),
|
actionPane: SlidableDrawerActionPane(),
|
||||||
child: content,
|
child: content,
|
||||||
secondaryActions: <Widget>[
|
secondaryActions: <Widget>[
|
||||||
|
@ -128,8 +134,9 @@ class AddressBookPage extends BasePage {
|
||||||
color: Colors.blue,
|
color: Colors.blue,
|
||||||
icon: Icons.edit,
|
icon: Icons.edit,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await Navigator.of(context)
|
await Navigator.of(context).pushNamed(
|
||||||
.pushNamed(Routes.addressBookAddContact, arguments: contact);
|
Routes.addressBookAddContact,
|
||||||
|
arguments: contact);
|
||||||
await addressBookStore.updateContactList();
|
await addressBookStore.updateContactList();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -138,9 +145,11 @@ class AddressBookPage extends BasePage {
|
||||||
color: Colors.red,
|
color: Colors.red,
|
||||||
icon: CupertinoIcons.delete,
|
icon: CupertinoIcons.delete,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await showAlertDialog(context).then((isDelete) async{
|
await showAlertDialog(context)
|
||||||
|
.then((isDelete) async {
|
||||||
if (isDelete != null && isDelete) {
|
if (isDelete != null && isDelete) {
|
||||||
await addressBookStore.delete(contact: contact);
|
await addressBookStore.delete(
|
||||||
|
contact: contact);
|
||||||
await addressBookStore.updateContactList();
|
await addressBookStore.updateContactList();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -157,7 +166,6 @@ class AddressBookPage extends BasePage {
|
||||||
return await showAlertDialog(context);
|
return await showAlertDialog(context);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
));
|
));
|
||||||
|
@ -220,19 +228,18 @@ class AddressBookPage extends BasePage {
|
||||||
),
|
),
|
||||||
actions: <Widget>[
|
actions: <Widget>[
|
||||||
FlatButton(
|
FlatButton(
|
||||||
onPressed: () =>
|
onPressed: () => Navigator.of(context).pop( false),
|
||||||
Navigator.pop(context, false),
|
|
||||||
child: const Text('Cancel')),
|
child: const Text('Cancel')),
|
||||||
FlatButton(
|
FlatButton(
|
||||||
onPressed: () =>
|
onPressed: () => Navigator.of(context).pop(true),
|
||||||
Navigator.pop(context, true),
|
|
||||||
child: const Text('Remove')),
|
child: const Text('Remove')),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
showNameAndAddressDialog(BuildContext context, String name, String address) async {
|
Future<bool> showNameAndAddressDialog(
|
||||||
|
BuildContext context, String name, String address) async {
|
||||||
return await showDialog(
|
return await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
|
@ -255,7 +262,6 @@ class AddressBookPage extends BasePage {
|
||||||
child: Text('Copy'))
|
child: Text('Copy'))
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,22 +12,24 @@ import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||||
import 'package:cake_wallet/palette.dart';
|
import 'package:cake_wallet/palette.dart';
|
||||||
|
|
||||||
class ContactPage extends BasePage {
|
class ContactPage extends BasePage {
|
||||||
String get title => S.current.contact;
|
ContactPage({this.contact});
|
||||||
|
|
||||||
final Contact contact;
|
final Contact contact;
|
||||||
|
|
||||||
ContactPage({this.contact});
|
@override
|
||||||
|
String get title => S.current.contact;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) => ContactForm(contact);
|
Widget body(BuildContext context) => ContactForm(contact);
|
||||||
}
|
}
|
||||||
|
|
||||||
class ContactForm extends StatefulWidget {
|
class ContactForm extends StatefulWidget {
|
||||||
final Contact contact;
|
|
||||||
|
|
||||||
ContactForm(this.contact);
|
ContactForm(this.contact);
|
||||||
|
|
||||||
|
final Contact contact;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
createState() => ContactFormState();
|
State<ContactForm> createState() => ContactFormState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class ContactFormState extends State<ContactForm> {
|
class ContactFormState extends State<ContactForm> {
|
||||||
|
@ -59,10 +61,11 @@ class ContactFormState extends State<ContactForm> {
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
_setCurrencyType(BuildContext context) async {
|
Future<void> _setCurrencyType(BuildContext context) async {
|
||||||
String currencyType = CryptoCurrency.all[0].toString();
|
var currencyType = CryptoCurrency.all[0].toString();
|
||||||
CryptoCurrency selectedCurrency = CryptoCurrency.all[0];
|
var selectedCurrency = CryptoCurrency.all[0];
|
||||||
await showDialog(
|
|
||||||
|
await showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
|
@ -127,8 +130,8 @@ class ContactFormState extends State<ContactForm> {
|
||||||
hintStyle: TextStyle(color: Theme.of(context).hintColor),
|
hintStyle: TextStyle(color: Theme.of(context).hintColor),
|
||||||
hintText: S.of(context).contact_name,
|
hintText: S.of(context).contact_name,
|
||||||
focusedBorder: UnderlineInputBorder(
|
focusedBorder: UnderlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide:
|
||||||
color: Palette.cakeGreen, width: 2.0)),
|
BorderSide(color: Palette.cakeGreen, width: 2.0)),
|
||||||
enabledBorder: UnderlineInputBorder(
|
enabledBorder: UnderlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Theme.of(context).focusColor, width: 1.0))),
|
color: Theme.of(context).focusColor, width: 1.0))),
|
||||||
|
@ -153,8 +156,7 @@ class ContactFormState extends State<ContactForm> {
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
focusedBorder: UnderlineInputBorder(
|
focusedBorder: UnderlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Palette.cakeGreen,
|
color: Palette.cakeGreen, width: 2.0)),
|
||||||
width: 2.0)),
|
|
||||||
enabledBorder: UnderlineInputBorder(
|
enabledBorder: UnderlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Theme.of(context).focusColor,
|
color: Theme.of(context).focusColor,
|
||||||
|
@ -215,13 +217,15 @@ class ContactFormState extends State<ContactForm> {
|
||||||
} else {
|
} else {
|
||||||
widget.contact.name = _contactNameController.text;
|
widget.contact.name = _contactNameController.text;
|
||||||
widget.contact.address = _addressController.text;
|
widget.contact.address = _addressController.text;
|
||||||
widget.contact.updateCryptoCurrency(currency: _selectectCrypto);
|
widget.contact
|
||||||
|
.updateCryptoCurrency(currency: _selectectCrypto);
|
||||||
|
|
||||||
await addressBookStore.update(contact: widget.contact);
|
await addressBookStore.update(
|
||||||
|
contact: widget.contact);
|
||||||
}
|
}
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await showDialog(
|
await showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
|
|
|
@ -7,13 +7,14 @@ import 'package:cake_wallet/src/stores/auth/auth_state.dart';
|
||||||
import 'package:cake_wallet/src/stores/auth/auth_store.dart';
|
import 'package:cake_wallet/src/stores/auth/auth_store.dart';
|
||||||
import 'package:cake_wallet/src/screens/pin_code/pin_code.dart';
|
import 'package:cake_wallet/src/screens/pin_code/pin_code.dart';
|
||||||
|
|
||||||
|
typedef OnAuthenticationFinished = void Function(bool, AuthPageState);
|
||||||
|
|
||||||
class AuthPage extends StatefulWidget {
|
class AuthPage extends StatefulWidget {
|
||||||
final Function(bool, AuthPageState) onAuthenticationFinished;
|
|
||||||
final bool closable;
|
|
||||||
|
|
||||||
AuthPage({this.onAuthenticationFinished, this.closable = true});
|
AuthPage({this.onAuthenticationFinished, this.closable = true});
|
||||||
|
|
||||||
|
final OnAuthenticationFinished onAuthenticationFinished;
|
||||||
|
final bool closable;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
AuthPageState createState() => AuthPageState();
|
AuthPageState createState() => AuthPageState();
|
||||||
}
|
}
|
||||||
|
@ -33,7 +34,7 @@ class AuthPageState extends State<AuthPage> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final authStore = Provider.of<AuthStore>(context);
|
final authStore = Provider.of<AuthStore>(context);
|
||||||
|
|
||||||
reaction((_) => authStore.state, (state) {
|
reaction((_) => authStore.state, (AuthState state) {
|
||||||
if (state is AuthenticatedSuccessfully) {
|
if (state is AuthenticatedSuccessfully) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
if (widget.onAuthenticationFinished != null) {
|
if (widget.onAuthenticationFinished != null) {
|
||||||
|
@ -60,7 +61,24 @@ class AuthPageState extends State<AuthPage> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state is AuthenticationFailure || state is AuthenticationBanned) {
|
if (state is AuthenticationFailure) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
_pinCodeKey.currentState.clear();
|
||||||
|
_key.currentState.hideCurrentSnackBar();
|
||||||
|
_key.currentState.showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(S.of(context).failed_authentication(state.error)),
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (widget.onAuthenticationFinished != null) {
|
||||||
|
widget.onAuthenticationFinished(false, this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state is AuthenticationBanned) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
_pinCodeKey.currentState.clear();
|
_pinCodeKey.currentState.clear();
|
||||||
_key.currentState.hideCurrentSnackBar();
|
_key.currentState.hideCurrentSnackBar();
|
||||||
|
|
|
@ -28,7 +28,7 @@ abstract class BasePage extends StatelessWidget {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ThemeChanger _themeChanger = Provider.of<ThemeChanger>(context);
|
final _themeChanger = Provider.of<ThemeChanger>(context);
|
||||||
Image _closeButton, _backButton;
|
Image _closeButton, _backButton;
|
||||||
|
|
||||||
if (_themeChanger.getTheme() == Themes.darkTheme) {
|
if (_themeChanger.getTheme() == Themes.darkTheme) {
|
||||||
|
@ -70,7 +70,7 @@ abstract class BasePage extends StatelessWidget {
|
||||||
|
|
||||||
Widget floatingActionButton(BuildContext context) => null;
|
Widget floatingActionButton(BuildContext context) => null;
|
||||||
|
|
||||||
Widget appBar(BuildContext context) {
|
ObstructingPreferredSizeWidget appBar(BuildContext context) {
|
||||||
final _themeChanger = Provider.of<ThemeChanger>(context);
|
final _themeChanger = Provider.of<ThemeChanger>(context);
|
||||||
final _isDarkTheme = _themeChanger.getTheme() == Themes.darkTheme;
|
final _isDarkTheme = _themeChanger.getTheme() == Themes.darkTheme;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:date_range_picker/date_range_picker.dart' as DateRagePicker;
|
import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
|
@ -86,24 +86,19 @@ class DashboardPage extends BasePage {
|
||||||
child: Image.asset('assets/images/exchange_icon.png',
|
child: Image.asset('assets/images/exchange_icon.png',
|
||||||
color: Colors.white, height: 26, width: 22),
|
color: Colors.white, height: 26, width: 22),
|
||||||
backgroundColor: Palette.floatingActionButton,
|
backgroundColor: Palette.floatingActionButton,
|
||||||
onPressed: () async {
|
onPressed: () async => await Navigator.of(context, rootNavigator: true)
|
||||||
final actionListStore = Provider.of<ActionListStore>(context);
|
.pushNamed(Routes.exchange));
|
||||||
|
|
||||||
await Navigator.of(context, rootNavigator: true)
|
|
||||||
.pushNamed(Routes.exchange);
|
|
||||||
actionListStore.updateTradeList();
|
|
||||||
});
|
|
||||||
|
|
||||||
void _presentWalletMenu(BuildContext bodyContext) {
|
void _presentWalletMenu(BuildContext bodyContext) {
|
||||||
final walletMenu = WalletMenu(bodyContext);
|
final walletMenu = WalletMenu(bodyContext);
|
||||||
|
|
||||||
showDialog(
|
showDialog<void>(
|
||||||
builder: (_) => Picker(
|
builder: (_) => Picker(
|
||||||
items: walletMenu.items,
|
items: walletMenu.items,
|
||||||
selectedAtIndex: -1,
|
selectedAtIndex: -1,
|
||||||
title: S.of(bodyContext).wallet_menu,
|
title: S.of(bodyContext).wallet_menu,
|
||||||
pickerHeight: 510,
|
pickerHeight: 510,
|
||||||
onItemSelected: (item) =>
|
onItemSelected: (String item) =>
|
||||||
walletMenu.action(walletMenu.items.indexOf(item))),
|
walletMenu.action(walletMenu.items.indexOf(item))),
|
||||||
context: bodyContext);
|
context: bodyContext);
|
||||||
}
|
}
|
||||||
|
@ -136,8 +131,9 @@ class DashboardPageBodyState extends State<DashboardPageBody> {
|
||||||
return Observer(
|
return Observer(
|
||||||
key: _listObserverKey,
|
key: _listObserverKey,
|
||||||
builder: (_) {
|
builder: (_) {
|
||||||
final items =
|
final items = actionListStore.items == null
|
||||||
actionListStore.items == null ? [] : actionListStore.items;
|
? <String>[]
|
||||||
|
: actionListStore.items;
|
||||||
final itemsCount = items.length + 2;
|
final itemsCount = items.length + 2;
|
||||||
|
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
|
@ -225,19 +221,17 @@ class DashboardPageBodyState extends State<DashboardPageBody> {
|
||||||
builder: (_) {
|
builder: (_) {
|
||||||
final savedDisplayMode =
|
final savedDisplayMode =
|
||||||
settingsStore.balanceDisplayMode;
|
settingsStore.balanceDisplayMode;
|
||||||
final displayMode =
|
final displayMode = balanceStore
|
||||||
balanceStore.isReversing
|
.isReversing
|
||||||
? (savedDisplayMode ==
|
? (savedDisplayMode ==
|
||||||
BalanceDisplayMode
|
BalanceDisplayMode
|
||||||
.availableBalance
|
.availableBalance
|
||||||
? BalanceDisplayMode
|
? BalanceDisplayMode.fullBalance
|
||||||
.fullBalance
|
|
||||||
: BalanceDisplayMode
|
: BalanceDisplayMode
|
||||||
.availableBalance)
|
.availableBalance)
|
||||||
: savedDisplayMode;
|
: savedDisplayMode;
|
||||||
var title = displayMode.toString();
|
|
||||||
|
|
||||||
return Text(title,
|
return Text(displayMode.toString(),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Palette.violet,
|
color: Palette.violet,
|
||||||
fontSize: 16));
|
fontSize: 16));
|
||||||
|
@ -248,13 +242,12 @@ class DashboardPageBodyState extends State<DashboardPageBody> {
|
||||||
final savedDisplayMode =
|
final savedDisplayMode =
|
||||||
settingsStore.balanceDisplayMode;
|
settingsStore.balanceDisplayMode;
|
||||||
var balance = '---';
|
var balance = '---';
|
||||||
final displayMode =
|
final displayMode = balanceStore
|
||||||
balanceStore.isReversing
|
.isReversing
|
||||||
? (savedDisplayMode ==
|
? (savedDisplayMode ==
|
||||||
BalanceDisplayMode
|
BalanceDisplayMode
|
||||||
.availableBalance
|
.availableBalance
|
||||||
? BalanceDisplayMode
|
? BalanceDisplayMode.fullBalance
|
||||||
.fullBalance
|
|
||||||
: BalanceDisplayMode
|
: BalanceDisplayMode
|
||||||
.availableBalance)
|
.availableBalance)
|
||||||
: savedDisplayMode;
|
: savedDisplayMode;
|
||||||
|
@ -499,7 +492,7 @@ class DashboardPageBodyState extends State<DashboardPageBody> {
|
||||||
onSelected: (item) async {
|
onSelected: (item) async {
|
||||||
if (item == 2) {
|
if (item == 2) {
|
||||||
final List<DateTime> picked =
|
final List<DateTime> picked =
|
||||||
await DateRagePicker.showDatePicker(
|
await date_rage_picker.showDatePicker(
|
||||||
context: context,
|
context: context,
|
||||||
initialFirstDate: DateTime.now()
|
initialFirstDate: DateTime.now()
|
||||||
.subtract(Duration(days: 1)),
|
.subtract(Duration(days: 1)),
|
||||||
|
|
|
@ -4,17 +4,19 @@ import 'package:intl/intl.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
|
||||||
class DateSectionRaw extends StatelessWidget {
|
class DateSectionRaw extends StatelessWidget {
|
||||||
|
DateSectionRaw({this.date});
|
||||||
|
|
||||||
static final dateSectionDateFormat = DateFormat("d MMM");
|
static final dateSectionDateFormat = DateFormat("d MMM");
|
||||||
static final nowDate = DateTime.now();
|
static final nowDate = DateTime.now();
|
||||||
|
|
||||||
final DateTime date;
|
final DateTime date;
|
||||||
|
|
||||||
DateSectionRaw({this.date});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final diffDays = date.difference(nowDate).inDays;
|
final diffDays = date.difference(nowDate).inDays;
|
||||||
final isToday = nowDate.day == date.day && nowDate.month == date.month && nowDate.year == date.year;
|
final isToday = nowDate.day == date.day &&
|
||||||
|
nowDate.month == date.month &&
|
||||||
|
nowDate.year == date.year;
|
||||||
var title = "";
|
var title = "";
|
||||||
|
|
||||||
if (isToday) {
|
if (isToday) {
|
||||||
|
|
|
@ -4,13 +4,6 @@ import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
|
||||||
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
|
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
|
||||||
|
|
||||||
class TradeRow extends StatelessWidget {
|
class TradeRow extends StatelessWidget {
|
||||||
final VoidCallback onTap;
|
|
||||||
final ExchangeProviderDescription provider;
|
|
||||||
final CryptoCurrency from;
|
|
||||||
final CryptoCurrency to;
|
|
||||||
final String createdAtFormattedDate;
|
|
||||||
final String formattedAmount;
|
|
||||||
|
|
||||||
TradeRow(
|
TradeRow(
|
||||||
{this.provider,
|
{this.provider,
|
||||||
this.from,
|
this.from,
|
||||||
|
@ -19,6 +12,13 @@ class TradeRow extends StatelessWidget {
|
||||||
this.formattedAmount,
|
this.formattedAmount,
|
||||||
@required this.onTap});
|
@required this.onTap});
|
||||||
|
|
||||||
|
final VoidCallback onTap;
|
||||||
|
final ExchangeProviderDescription provider;
|
||||||
|
final CryptoCurrency from;
|
||||||
|
final CryptoCurrency to;
|
||||||
|
final String createdAtFormattedDate;
|
||||||
|
final String formattedAmount;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final amountCrypto = provider == ExchangeProviderDescription.xmrto
|
final amountCrypto = provider == ExchangeProviderDescription.xmrto
|
||||||
|
@ -48,7 +48,10 @@ class TradeRow extends StatelessWidget {
|
||||||
Text('${from.toString()} → ${to.toString()}',
|
Text('${from.toString()} → ${to.toString()}',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: Theme.of(context).primaryTextTheme.subhead.color)),
|
color: Theme.of(context)
|
||||||
|
.primaryTextTheme
|
||||||
|
.subhead
|
||||||
|
.color)),
|
||||||
formattedAmount != null
|
formattedAmount != null
|
||||||
? Text(formattedAmount + ' ' + amountCrypto,
|
? Text(formattedAmount + ' ' + amountCrypto,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
|
|
|
@ -4,13 +4,6 @@ import 'package:cake_wallet/src/domain/common/transaction_direction.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
|
||||||
class TransactionRow extends StatelessWidget {
|
class TransactionRow extends StatelessWidget {
|
||||||
final VoidCallback onTap;
|
|
||||||
final TransactionDirection direction;
|
|
||||||
final String formattedDate;
|
|
||||||
final String formattedAmount;
|
|
||||||
final String formattedFiatAmount;
|
|
||||||
final bool isPending;
|
|
||||||
|
|
||||||
TransactionRow(
|
TransactionRow(
|
||||||
{this.direction,
|
{this.direction,
|
||||||
this.formattedDate,
|
this.formattedDate,
|
||||||
|
@ -19,6 +12,13 @@ class TransactionRow extends StatelessWidget {
|
||||||
this.isPending,
|
this.isPending,
|
||||||
@required this.onTap});
|
@required this.onTap});
|
||||||
|
|
||||||
|
final VoidCallback onTap;
|
||||||
|
final TransactionDirection direction;
|
||||||
|
final String formattedDate;
|
||||||
|
final String formattedAmount;
|
||||||
|
final String formattedFiatAmount;
|
||||||
|
final bool isPending;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return InkWell(
|
return InkWell(
|
||||||
|
@ -53,7 +53,10 @@ class TransactionRow extends StatelessWidget {
|
||||||
(isPending ? S.of(context).pending : ''),
|
(isPending ? S.of(context).pending : ''),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: Theme.of(context).primaryTextTheme.subhead.color)),
|
color: Theme.of(context)
|
||||||
|
.primaryTextTheme
|
||||||
|
.subhead
|
||||||
|
.color)),
|
||||||
Text(formattedAmount,
|
Text(formattedAmount,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 16, color: Palette.purpleBlue))
|
fontSize: 16, color: Palette.purpleBlue))
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
|
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
||||||
|
|
||||||
class WalletMenu {
|
class WalletMenu {
|
||||||
|
WalletMenu(this.context);
|
||||||
|
|
||||||
final List<String> items = [
|
final List<String> items = [
|
||||||
S.current.reconnect,
|
S.current.reconnect,
|
||||||
S.current.rescan,
|
S.current.rescan,
|
||||||
|
@ -14,9 +17,8 @@ class WalletMenu {
|
||||||
S.current.accounts,
|
S.current.accounts,
|
||||||
S.current.address_book_menu
|
S.current.address_book_menu
|
||||||
];
|
];
|
||||||
final BuildContext context;
|
|
||||||
|
|
||||||
WalletMenu(this.context);
|
final BuildContext context;
|
||||||
|
|
||||||
void action(int index) {
|
void action(int index) {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
|
@ -32,7 +34,7 @@ class WalletMenu {
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
Navigator.of(context).pushNamed(Routes.auth,
|
Navigator.of(context).pushNamed(Routes.auth,
|
||||||
arguments: (isAuthenticatedSuccessfully, auth) =>
|
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) =>
|
||||||
isAuthenticatedSuccessfully
|
isAuthenticatedSuccessfully
|
||||||
? Navigator.of(auth.context).popAndPushNamed(Routes.seed)
|
? Navigator.of(auth.context).popAndPushNamed(Routes.seed)
|
||||||
: null);
|
: null);
|
||||||
|
@ -40,7 +42,7 @@ class WalletMenu {
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
Navigator.of(context).pushNamed(Routes.auth,
|
Navigator.of(context).pushNamed(Routes.auth,
|
||||||
arguments: (isAuthenticatedSuccessfully, auth) =>
|
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) =>
|
||||||
isAuthenticatedSuccessfully
|
isAuthenticatedSuccessfully
|
||||||
? Navigator.of(auth.context)
|
? Navigator.of(auth.context)
|
||||||
.popAndPushNamed(Routes.showKeys)
|
.popAndPushNamed(Routes.showKeys)
|
||||||
|
@ -57,10 +59,10 @@ class WalletMenu {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _presentReconnectAlert(BuildContext context) async {
|
Future<void> _presentReconnectAlert(BuildContext context) async {
|
||||||
final walletStore = Provider.of<WalletStore>(context);
|
final walletStore = Provider.of<WalletStore>(context);
|
||||||
|
|
||||||
await showDialog(
|
await showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
|
|
|
@ -8,10 +8,10 @@ import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||||
|
|
||||||
class DisclaimerPage extends BasePage {
|
class DisclaimerPage extends BasePage {
|
||||||
final bool isReadOnly;
|
|
||||||
|
|
||||||
DisclaimerPage({this.isReadOnly = false});
|
DisclaimerPage({this.isReadOnly = false});
|
||||||
|
|
||||||
|
final bool isReadOnly;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get isModalBackButton => false;
|
bool get isModalBackButton => false;
|
||||||
|
|
||||||
|
@ -23,25 +23,25 @@ class DisclaimerPage extends BasePage {
|
||||||
}
|
}
|
||||||
|
|
||||||
class DisclaimerPageBody extends StatefulWidget {
|
class DisclaimerPageBody extends StatefulWidget {
|
||||||
final bool isReadOnly;
|
|
||||||
|
|
||||||
DisclaimerPageBody({this.isReadOnly = true});
|
DisclaimerPageBody({this.isReadOnly = true});
|
||||||
|
|
||||||
|
final bool isReadOnly;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
createState() => DisclaimerBodyState(false);
|
DisclaimerBodyState createState() => DisclaimerBodyState(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
||||||
static const xmrto_url = 'https://xmr.to/app_static/html/tos.html';
|
DisclaimerBodyState(this._isAccepted);
|
||||||
static const changenow_url = 'https://changenow.io/terms-of-use';
|
|
||||||
|
|
||||||
bool _isAccepted;
|
static const xmrtoUrl = 'https://xmr.to/app_static/html/tos.html';
|
||||||
|
static const changenowUrl = 'https://changenow.io/terms-of-use';
|
||||||
|
|
||||||
|
final bool _isAccepted;
|
||||||
bool _checked = false;
|
bool _checked = false;
|
||||||
String _fileText = '';
|
String _fileText = '';
|
||||||
|
|
||||||
DisclaimerBodyState(this._isAccepted);
|
Future<void> launchUrl(String url) async {
|
||||||
|
|
||||||
launchUrl(String url) async {
|
|
||||||
if (await canLaunch(url)) await launch(url);
|
if (await canLaunch(url)) await launch(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,8 +50,8 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
_showAlertDialog(BuildContext context) async {
|
Future<void> _showAlertDialog(BuildContext context) async {
|
||||||
await showDialog(
|
await showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
|
@ -66,7 +66,7 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
||||||
actions: <Widget>[
|
actions: <Widget>[
|
||||||
FlatButton(
|
FlatButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pop(context);
|
Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
child: Text('OK')),
|
child: Text('OK')),
|
||||||
],
|
],
|
||||||
|
@ -74,9 +74,7 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_afterLayout(_) {
|
void _afterLayout(Duration _) => _showAlertDialog(context);
|
||||||
_showAlertDialog(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
@ -87,7 +85,6 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
SizedBox(height: 10.0),
|
SizedBox(height: 10.0),
|
||||||
|
@ -166,9 +163,9 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Expanded(
|
Expanded(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () => launchUrl(xmrto_url),
|
onTap: () => launchUrl(xmrtoUrl),
|
||||||
child: Text(
|
child: Text(
|
||||||
xmrto_url,
|
xmrtoUrl,
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.blue,
|
color: Colors.blue,
|
||||||
|
@ -187,9 +184,9 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Expanded(
|
Expanded(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () => launchUrl(changenow_url),
|
onTap: () => launchUrl(changenowUrl),
|
||||||
child: Text(
|
child: Text(
|
||||||
changenow_url,
|
changenowUrl,
|
||||||
textAlign: TextAlign.left,
|
textAlign: TextAlign.left,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.blue,
|
color: Colors.blue,
|
||||||
|
@ -288,8 +285,14 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
||||||
child: PrimaryButton(
|
child: PrimaryButton(
|
||||||
onPressed: _checked ? () {} : null,
|
onPressed: _checked ? () {} : null,
|
||||||
text: 'Accept',
|
text: 'Accept',
|
||||||
color: Theme.of(context).primaryTextTheme.button.backgroundColor,
|
color: Theme.of(context)
|
||||||
borderColor: Theme.of(context).primaryTextTheme.button.decorationColor,
|
.primaryTextTheme
|
||||||
|
.button
|
||||||
|
.backgroundColor,
|
||||||
|
borderColor: Theme.of(context)
|
||||||
|
.primaryTextTheme
|
||||||
|
.button
|
||||||
|
.decorationColor,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: Offstage(),
|
: Offstage(),
|
||||||
|
|
|
@ -6,8 +6,9 @@ import 'package:provider/provider.dart';
|
||||||
import 'package:cake_wallet/palette.dart';
|
import 'package:cake_wallet/palette.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
|
|
||||||
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
|
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
|
||||||
|
import 'package:cake_wallet/src/domain/exchange/exchange_provider.dart';
|
||||||
|
import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
|
||||||
import 'package:cake_wallet/src/domain/exchange/xmrto/xmrto_exchange_provider.dart';
|
import 'package:cake_wallet/src/domain/exchange/xmrto/xmrto_exchange_provider.dart';
|
||||||
import 'package:cake_wallet/src/stores/exchange/exchange_trade_state.dart';
|
import 'package:cake_wallet/src/stores/exchange/exchange_trade_state.dart';
|
||||||
import 'package:cake_wallet/src/stores/exchange/limits_state.dart';
|
import 'package:cake_wallet/src/stores/exchange/limits_state.dart';
|
||||||
|
@ -20,15 +21,14 @@ import 'package:cake_wallet/src/widgets/picker.dart';
|
||||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||||
|
|
||||||
class ExchangePage extends BasePage {
|
class ExchangePage extends BasePage {
|
||||||
|
@override
|
||||||
String get title => S.current.exchange;
|
String get title => S.current.exchange;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool get isModalBackButton => true;
|
bool get isModalBackButton => true;
|
||||||
|
|
||||||
final Image arrowBottomPurple = Image.asset(
|
final Image arrowBottomPurple =
|
||||||
'assets/images/arrow_bottom_purple_icon.png',
|
Image.asset('assets/images/arrow_bottom_purple_icon.png', height: 8);
|
||||||
height: 8,
|
|
||||||
);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget middle(BuildContext context) {
|
Widget middle(BuildContext context) {
|
||||||
|
@ -93,12 +93,12 @@ class ExchangePage extends BasePage {
|
||||||
final items = exchangeStore.providersForCurrentPair();
|
final items = exchangeStore.providersForCurrentPair();
|
||||||
final selectedItem = items.indexOf(exchangeStore.provider);
|
final selectedItem = items.indexOf(exchangeStore.provider);
|
||||||
|
|
||||||
showDialog(
|
showDialog<void>(
|
||||||
builder: (_) => Picker(
|
builder: (_) => Picker(
|
||||||
items: items,
|
items: items,
|
||||||
selectedAtIndex: selectedItem,
|
selectedAtIndex: selectedItem,
|
||||||
title: S.of(context).change_exchange_provider,
|
title: S.of(context).change_exchange_provider,
|
||||||
onItemSelected: (provider) =>
|
onItemSelected: (ExchangeProvider provider) =>
|
||||||
exchangeStore.changeProvider(provider: provider)),
|
exchangeStore.changeProvider(provider: provider)),
|
||||||
context: context);
|
context: context);
|
||||||
}
|
}
|
||||||
|
@ -253,8 +253,9 @@ class ExchangeFormState extends State<ExchangeForm> {
|
||||||
builder: (_) => LoadingPrimaryButton(
|
builder: (_) => LoadingPrimaryButton(
|
||||||
text: S.of(context).exchange,
|
text: S.of(context).exchange,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (_formKey.currentState.validate())
|
if (_formKey.currentState.validate()) {
|
||||||
exchangeStore.createTrade();
|
exchangeStore.createTrade();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
color: Theme.of(context)
|
color: Theme.of(context)
|
||||||
.primaryTextTheme
|
.primaryTextTheme
|
||||||
|
@ -327,34 +328,38 @@ class ExchangeFormState extends State<ExchangeForm> {
|
||||||
|
|
||||||
reaction(
|
reaction(
|
||||||
(_) => walletStore.name,
|
(_) => walletStore.name,
|
||||||
(_) => _onWalletNameChange(
|
(String _) => _onWalletNameChange(
|
||||||
walletStore, store.receiveCurrency, receiveKey));
|
walletStore, store.receiveCurrency, receiveKey));
|
||||||
|
|
||||||
reaction(
|
reaction(
|
||||||
(_) => walletStore.name,
|
(_) => walletStore.name,
|
||||||
(_) => _onWalletNameChange(
|
(String _) => _onWalletNameChange(
|
||||||
walletStore, store.depositCurrency, depositKey));
|
walletStore, store.depositCurrency, depositKey));
|
||||||
|
|
||||||
reaction((_) => store.receiveCurrency,
|
reaction(
|
||||||
(currency) => _onCurrencyChange(currency, walletStore, receiveKey));
|
(_) => store.receiveCurrency,
|
||||||
|
(CryptoCurrency currency) =>
|
||||||
|
_onCurrencyChange(currency, walletStore, receiveKey));
|
||||||
|
|
||||||
reaction((_) => store.depositCurrency,
|
reaction(
|
||||||
(currency) => _onCurrencyChange(currency, walletStore, depositKey));
|
(_) => store.depositCurrency,
|
||||||
|
(CryptoCurrency currency) =>
|
||||||
|
_onCurrencyChange(currency, walletStore, depositKey));
|
||||||
|
|
||||||
reaction((_) => store.depositAmount, (amount) {
|
reaction((_) => store.depositAmount, (String amount) {
|
||||||
if (depositKey.currentState.amountController.text != amount) {
|
if (depositKey.currentState.amountController.text != amount) {
|
||||||
depositKey.currentState.amountController.text = amount;
|
depositKey.currentState.amountController.text = amount;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
reaction((_) => store.receiveAmount, (amount) {
|
reaction((_) => store.receiveAmount, (String amount) {
|
||||||
if (receiveKey.currentState.amountController.text !=
|
if (receiveKey.currentState.amountController.text !=
|
||||||
store.receiveAmount) {
|
store.receiveAmount) {
|
||||||
receiveKey.currentState.amountController.text = amount;
|
receiveKey.currentState.amountController.text = amount;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
reaction((_) => store.provider, (provider) {
|
reaction((_) => store.provider, (ExchangeProvider provider) {
|
||||||
final isReversed = provider is XMRTOExchangeProvider;
|
final isReversed = provider is XMRTOExchangeProvider;
|
||||||
|
|
||||||
if (isReversed) {
|
if (isReversed) {
|
||||||
|
@ -373,10 +378,10 @@ class ExchangeFormState extends State<ExchangeForm> {
|
||||||
receiveKey.currentState.changeIsAmountEstimated(!isReversed);
|
receiveKey.currentState.changeIsAmountEstimated(!isReversed);
|
||||||
});
|
});
|
||||||
|
|
||||||
reaction((_) => store.tradeState, (state) {
|
reaction((_) => store.tradeState, (ExchangeTradeState state) {
|
||||||
if (state is TradeIsCreatedFailure) {
|
if (state is TradeIsCreatedFailure) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
showDialog(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
|
@ -397,7 +402,7 @@ class ExchangeFormState extends State<ExchangeForm> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
reaction((_) => store.limitsState, (state) {
|
reaction((_) => store.limitsState, (LimitsState state) {
|
||||||
final isXMRTO = store.provider is XMRTOExchangeProvider;
|
final isXMRTO = store.provider is XMRTOExchangeProvider;
|
||||||
String min;
|
String min;
|
||||||
String max;
|
String max;
|
||||||
|
@ -444,7 +449,7 @@ class ExchangeFormState extends State<ExchangeForm> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
reaction((_) => walletStore.address, (address) {
|
reaction((_) => walletStore.address, (String address) {
|
||||||
if (store.depositCurrency == CryptoCurrency.xmr) {
|
if (store.depositCurrency == CryptoCurrency.xmr) {
|
||||||
depositKey.currentState.changeAddress(address: address);
|
depositKey.currentState.changeAddress(address: address);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,18 +7,6 @@ import 'package:cake_wallet/src/widgets/picker.dart';
|
||||||
import 'package:cake_wallet/src/widgets/address_text_field.dart';
|
import 'package:cake_wallet/src/widgets/address_text_field.dart';
|
||||||
|
|
||||||
class ExchangeCard extends StatefulWidget {
|
class ExchangeCard extends StatefulWidget {
|
||||||
final List<CryptoCurrency> currencies;
|
|
||||||
final Function(CryptoCurrency) onCurrencySelected;
|
|
||||||
final CryptoCurrency initialCurrency;
|
|
||||||
final String initialWalletName;
|
|
||||||
final String initialAddress;
|
|
||||||
final bool initialIsAmountEditable;
|
|
||||||
final bool initialIsAddressEditable;
|
|
||||||
final bool isAmountEstimated;
|
|
||||||
final Image imageArrow;
|
|
||||||
final FormFieldValidator<String> currencyValueValidator;
|
|
||||||
final FormFieldValidator<String> addressTextFieldValidator;
|
|
||||||
|
|
||||||
ExchangeCard(
|
ExchangeCard(
|
||||||
{Key key,
|
{Key key,
|
||||||
this.initialCurrency,
|
this.initialCurrency,
|
||||||
|
@ -34,8 +22,20 @@ class ExchangeCard extends StatefulWidget {
|
||||||
this.addressTextFieldValidator})
|
this.addressTextFieldValidator})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
|
final List<CryptoCurrency> currencies;
|
||||||
|
final Function(CryptoCurrency) onCurrencySelected;
|
||||||
|
final CryptoCurrency initialCurrency;
|
||||||
|
final String initialWalletName;
|
||||||
|
final String initialAddress;
|
||||||
|
final bool initialIsAmountEditable;
|
||||||
|
final bool initialIsAddressEditable;
|
||||||
|
final bool isAmountEstimated;
|
||||||
|
final Image imageArrow;
|
||||||
|
final FormFieldValidator<String> currencyValueValidator;
|
||||||
|
final FormFieldValidator<String> addressTextFieldValidator;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
createState() => ExchangeCardState();
|
ExchangeCardState createState() => ExchangeCardState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExchangeCardState extends State<ExchangeCard> {
|
class ExchangeCardState extends State<ExchangeCard> {
|
||||||
|
@ -102,7 +102,6 @@ class ExchangeCardState extends State<ExchangeCard> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
padding: EdgeInsets.fromLTRB(22, 15, 22, 30),
|
padding: EdgeInsets.fromLTRB(22, 15, 22, 30),
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
|
@ -150,7 +149,10 @@ class ExchangeCardState extends State<ExchangeCard> {
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
color: Theme.of(context).primaryTextTheme.title.color)),
|
color: Theme.of(context)
|
||||||
|
.primaryTextTheme
|
||||||
|
.title
|
||||||
|
.color)),
|
||||||
widget.imageArrow
|
widget.imageArrow
|
||||||
]),
|
]),
|
||||||
_walletName != null
|
_walletName != null
|
||||||
|
@ -173,7 +175,10 @@ class ExchangeCardState extends State<ExchangeCard> {
|
||||||
textAlign: TextAlign.right,
|
textAlign: TextAlign.right,
|
||||||
keyboardType: TextInputType.numberWithOptions(
|
keyboardType: TextInputType.numberWithOptions(
|
||||||
signed: false, decimal: false),
|
signed: false, decimal: false),
|
||||||
inputFormatters: [BlacklistingTextInputFormatter(new RegExp('[\\-|\\ |\\,]'))],
|
inputFormatters: [
|
||||||
|
BlacklistingTextInputFormatter(
|
||||||
|
RegExp('[\\-|\\ |\\,]'))
|
||||||
|
],
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintStyle: TextStyle(
|
hintStyle: TextStyle(
|
||||||
color: Theme.of(context).cardTheme.color,
|
color: Theme.of(context).cardTheme.color,
|
||||||
|
@ -182,8 +187,7 @@ class ExchangeCardState extends State<ExchangeCard> {
|
||||||
hintText: '0.00000000',
|
hintText: '0.00000000',
|
||||||
focusedBorder: UnderlineInputBorder(
|
focusedBorder: UnderlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Palette.cakeGreen,
|
color: Palette.cakeGreen, width: 2.0)),
|
||||||
width: 2.0)),
|
|
||||||
enabledBorder: UnderlineInputBorder(
|
enabledBorder: UnderlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: _isAmountEditable
|
color: _isAmountEditable
|
||||||
|
@ -201,21 +205,29 @@ class ExchangeCardState extends State<ExchangeCard> {
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
_min != null
|
_min != null
|
||||||
? Text(
|
? Text(
|
||||||
S.of(context).min_value(_min, _selectedCurrency.toString()),
|
S.of(context).min_value(
|
||||||
|
_min, _selectedCurrency.toString()),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
height: 1.2,
|
height: 1.2,
|
||||||
color: Theme.of(context).primaryTextTheme.subtitle.color),
|
color: Theme.of(context)
|
||||||
|
.primaryTextTheme
|
||||||
|
.subtitle
|
||||||
|
.color),
|
||||||
)
|
)
|
||||||
: SizedBox(),
|
: SizedBox(),
|
||||||
_min != null ? SizedBox(width: 10) : SizedBox(),
|
_min != null ? SizedBox(width: 10) : SizedBox(),
|
||||||
_max != null
|
_max != null
|
||||||
? Text(
|
? Text(
|
||||||
S.of(context).max_value(_max, _selectedCurrency.toString()),
|
S.of(context).max_value(
|
||||||
|
_max, _selectedCurrency.toString()),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
height: 1.2,
|
height: 1.2,
|
||||||
color: Theme.of(context).primaryTextTheme.subtitle.color))
|
color: Theme.of(context)
|
||||||
|
.primaryTextTheme
|
||||||
|
.subtitle
|
||||||
|
.color))
|
||||||
: SizedBox(),
|
: SizedBox(),
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
|
@ -248,12 +260,13 @@ class ExchangeCardState extends State<ExchangeCard> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _presentPicker(BuildContext context) {
|
void _presentPicker(BuildContext context) {
|
||||||
showDialog(
|
showDialog<void>(
|
||||||
builder: (_) => Picker(
|
builder: (_) => Picker(
|
||||||
items: widget.currencies,
|
items: widget.currencies,
|
||||||
selectedAtIndex: widget.currencies.indexOf(_selectedCurrency),
|
selectedAtIndex: widget.currencies.indexOf(_selectedCurrency),
|
||||||
title: S.of(context).change_currency,
|
title: S.of(context).change_currency,
|
||||||
onItemSelected: (item) => widget.onCurrencySelected != null
|
onItemSelected: (CryptoCurrency item) =>
|
||||||
|
widget.onCurrencySelected != null
|
||||||
? widget.onCurrencySelected(item)
|
? widget.onCurrencySelected(item)
|
||||||
: null),
|
: null),
|
||||||
context: context);
|
context: context);
|
||||||
|
|
|
@ -8,11 +8,12 @@ import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
import 'package:cake_wallet/src/domain/exchange/trade.dart';
|
import 'package:cake_wallet/src/domain/exchange/trade.dart';
|
||||||
|
|
||||||
class ExchangeConfirmPage extends BasePage {
|
class ExchangeConfirmPage extends BasePage {
|
||||||
String get title => S.current.copy_id;
|
ExchangeConfirmPage({@required this.trade});
|
||||||
|
|
||||||
final Trade trade;
|
final Trade trade;
|
||||||
|
|
||||||
ExchangeConfirmPage({@required this.trade});
|
@override
|
||||||
|
String get title => S.current.copy_id;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
|
|
|
@ -20,6 +20,7 @@ import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||||
|
|
||||||
class ExchangeTradePage extends BasePage {
|
class ExchangeTradePage extends BasePage {
|
||||||
|
@override
|
||||||
String get title => S.current.exchange;
|
String get title => S.current.exchange;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -28,7 +29,7 @@ class ExchangeTradePage extends BasePage {
|
||||||
|
|
||||||
class ExchangeTradeForm extends StatefulWidget {
|
class ExchangeTradeForm extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
createState() => ExchangeTradeState();
|
ExchangeTradeState createState() => ExchangeTradeState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class ExchangeTradeState extends State<ExchangeTradeForm> {
|
class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||||
|
@ -330,10 +331,10 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||||
|
|
||||||
final sendStore = Provider.of<SendStore>(context);
|
final sendStore = Provider.of<SendStore>(context);
|
||||||
|
|
||||||
reaction((_) => sendStore.state, (state) {
|
reaction((_) => sendStore.state, (SendingState state) {
|
||||||
if (state is SendingFailed) {
|
if (state is SendingFailed) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
showDialog(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
|
@ -351,7 +352,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
|
||||||
|
|
||||||
if (state is TransactionCreatedSuccessfully) {
|
if (state is TransactionCreatedSuccessfully) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
showDialog(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
|
|
|
@ -2,18 +2,17 @@ import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class CopyButton extends StatelessWidget {
|
class CopyButton extends StatelessWidget {
|
||||||
|
const CopyButton(
|
||||||
|
{@required this.onPressed,
|
||||||
|
@required this.text,
|
||||||
|
@required this.color,
|
||||||
|
@required this.borderColor});
|
||||||
|
|
||||||
final VoidCallback onPressed;
|
final VoidCallback onPressed;
|
||||||
final Color color;
|
final Color color;
|
||||||
final Color borderColor;
|
final Color borderColor;
|
||||||
final String text;
|
final String text;
|
||||||
|
|
||||||
const CopyButton({
|
|
||||||
@required this.onPressed,
|
|
||||||
@required this.text,
|
|
||||||
@required this.color,
|
|
||||||
@required this.borderColor});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ButtonTheme(
|
return ButtonTheme(
|
||||||
|
@ -22,9 +21,10 @@ class CopyButton extends StatelessWidget {
|
||||||
child: FlatButton(
|
child: FlatButton(
|
||||||
onPressed: onPressed,
|
onPressed: onPressed,
|
||||||
color: color,
|
color: color,
|
||||||
shape: RoundedRectangleBorder(side: BorderSide(color: borderColor), borderRadius: BorderRadius.circular(10.0)),
|
shape: RoundedRectangleBorder(
|
||||||
|
side: BorderSide(color: borderColor),
|
||||||
|
borderRadius: BorderRadius.circular(10.0)),
|
||||||
child: Text(text, style: TextStyle(fontSize: 14.0)),
|
child: Text(text, style: TextStyle(fontSize: 14.0)),
|
||||||
)
|
));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -3,24 +3,24 @@ import 'dart:async';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
|
||||||
class TimerWidget extends StatefulWidget {
|
class TimerWidget extends StatefulWidget {
|
||||||
|
TimerWidget(this.expiratedAt, {this.color = Colors.black});
|
||||||
|
|
||||||
final DateTime expiratedAt;
|
final DateTime expiratedAt;
|
||||||
final Color color;
|
final Color color;
|
||||||
|
|
||||||
TimerWidget(this.expiratedAt, {this.color = Colors.black});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
createState() => TimerWidgetState();
|
TimerWidgetState createState() => TimerWidgetState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class TimerWidgetState extends State<TimerWidget> {
|
class TimerWidgetState extends State<TimerWidget> {
|
||||||
|
TimerWidgetState();
|
||||||
|
|
||||||
int _leftSeconds;
|
int _leftSeconds;
|
||||||
int _minutes;
|
int _minutes;
|
||||||
int _seconds;
|
int _seconds;
|
||||||
bool _isExpired;
|
bool _isExpired;
|
||||||
Timer _timer;
|
Timer _timer;
|
||||||
|
|
||||||
TimerWidgetState();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
@ -52,7 +52,8 @@ class TimerWidgetState extends State<TimerWidget> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return _isExpired
|
return _isExpired
|
||||||
? Text(S.of(context).expired, style: TextStyle(fontSize: 14.0, color: Colors.red))
|
? Text(S.of(context).expired,
|
||||||
|
style: TextStyle(fontSize: 14.0, color: Colors.red))
|
||||||
: Text(
|
: Text(
|
||||||
S.of(context).time(_minutes.toString(), _seconds.toString()),
|
S.of(context).time(_minutes.toString(), _seconds.toString()),
|
||||||
style: TextStyle(fontSize: 14.0, color: widget.color),
|
style: TextStyle(fontSize: 14.0, color: widget.color),
|
||||||
|
|
|
@ -7,14 +7,16 @@ import 'package:cake_wallet/src/stores/settings/settings_store.dart';
|
||||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
|
|
||||||
class FaqPage extends BasePage {
|
class FaqPage extends BasePage {
|
||||||
|
@override
|
||||||
String get title => S.current.faq;
|
String get title => S.current.faq;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
|
|
||||||
return FutureBuilder(
|
return FutureBuilder(
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
var faqItems = json.decode(snapshot.data.toString());
|
final faqItems = (json.decode(snapshot.data.toString())
|
||||||
|
as List<Map<String, String>>) ??
|
||||||
|
<Map<String, String>>[];
|
||||||
|
|
||||||
return ListView.separated(
|
return ListView.separated(
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
|
@ -22,34 +24,24 @@ class FaqPage extends BasePage {
|
||||||
final itemChild = faqItems[index]["answer"];
|
final itemChild = faqItems[index]["answer"];
|
||||||
|
|
||||||
return ExpansionTile(
|
return ExpansionTile(
|
||||||
title: Text(
|
title: Text(itemTitle),
|
||||||
itemTitle
|
|
||||||
),
|
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(left: 15.0, right: 15.0),
|
||||||
left: 15.0,
|
child: Text(itemChild),
|
||||||
right: 15.0
|
))
|
||||||
),
|
|
||||||
child: Text(
|
|
||||||
itemChild,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
separatorBuilder: (_, __) => Divider(
|
separatorBuilder: (_, __) =>
|
||||||
color: Theme.of(context).dividerTheme.color,
|
Divider(color: Theme.of(context).dividerTheme.color, height: 1.0),
|
||||||
height: 1.0,
|
itemCount: faqItems.length,
|
||||||
),
|
|
||||||
itemCount: faqItems == null ? 0 : faqItems.length,
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
future: rootBundle.loadString(getFaqPath(context)),
|
future: rootBundle.loadString(getFaqPath(context)),
|
||||||
|
@ -86,5 +78,4 @@ class FaqPage extends BasePage {
|
||||||
return 'assets/faq/faq_en.json';
|
return 'assets/faq/faq_en.json';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -15,24 +15,25 @@ import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||||
import 'package:cake_wallet/palette.dart';
|
import 'package:cake_wallet/palette.dart';
|
||||||
|
|
||||||
class NewWalletPage extends BasePage {
|
class NewWalletPage extends BasePage {
|
||||||
final WalletListService walletsService;
|
|
||||||
final WalletService walletService;
|
|
||||||
final SharedPreferences sharedPreferences;
|
|
||||||
|
|
||||||
String get title => S.current.new_wallet;
|
|
||||||
|
|
||||||
NewWalletPage(
|
NewWalletPage(
|
||||||
{@required this.walletsService,
|
{@required this.walletsService,
|
||||||
@required this.walletService,
|
@required this.walletService,
|
||||||
@required this.sharedPreferences});
|
@required this.sharedPreferences});
|
||||||
|
|
||||||
|
final WalletListService walletsService;
|
||||||
|
final WalletService walletService;
|
||||||
|
final SharedPreferences sharedPreferences;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get title => S.current.new_wallet;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) => WalletNameForm();
|
Widget body(BuildContext context) => WalletNameForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
class WalletNameForm extends StatefulWidget {
|
class WalletNameForm extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
createState() => _WalletNameFormState();
|
_WalletNameFormState createState() => _WalletNameFormState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _WalletNameFormState extends State<WalletNameForm> {
|
class _WalletNameFormState extends State<WalletNameForm> {
|
||||||
|
@ -43,14 +44,14 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final walletCreationStore = Provider.of<WalletCreationStore>(context);
|
final walletCreationStore = Provider.of<WalletCreationStore>(context);
|
||||||
|
|
||||||
reaction((_) => walletCreationStore.state, (state) {
|
reaction((_) => walletCreationStore.state, (WalletCreationState state) {
|
||||||
if (state is WalletCreatedSuccessfully) {
|
if (state is WalletCreatedSuccessfully) {
|
||||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state is WalletCreationFailure) {
|
if (state is WalletCreationFailure) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
showDialog(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
|
@ -88,8 +89,8 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
||||||
fontSize: 24.0, color: Theme.of(context).hintColor),
|
fontSize: 24.0, color: Theme.of(context).hintColor),
|
||||||
hintText: S.of(context).wallet_name,
|
hintText: S.of(context).wallet_name,
|
||||||
focusedBorder: UnderlineInputBorder(
|
focusedBorder: UnderlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide:
|
||||||
color: Palette.cakeGreen, width: 2.0)),
|
BorderSide(color: Palette.cakeGreen, width: 2.0)),
|
||||||
enabledBorder: UnderlineInputBorder(
|
enabledBorder: UnderlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Theme.of(context).focusColor,
|
color: Theme.of(context).focusColor,
|
||||||
|
|
|
@ -17,7 +17,7 @@ class NewNodePage extends BasePage {
|
||||||
|
|
||||||
class NewNodePageForm extends StatefulWidget {
|
class NewNodePageForm extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
createState() => NewNodeFormState();
|
NewNodeFormState createState() => NewNodeFormState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class NewNodeFormState extends State<NewNodePageForm> {
|
class NewNodeFormState extends State<NewNodePageForm> {
|
||||||
|
|
|
@ -2,18 +2,16 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:cake_wallet/palette.dart';
|
import 'package:cake_wallet/palette.dart';
|
||||||
|
|
||||||
class NodeIndicator extends StatelessWidget {
|
class NodeIndicator extends StatelessWidget {
|
||||||
final color;
|
|
||||||
|
|
||||||
NodeIndicator({this.color = Palette.red});
|
NodeIndicator({this.color = Palette.red});
|
||||||
|
|
||||||
|
final Color color;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
width: 10.0,
|
width: 10.0,
|
||||||
height: 10.0,
|
height: 10.0,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(shape: BoxShape.circle, color: color),
|
||||||
shape: BoxShape.circle,
|
|
||||||
color: color),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -13,6 +13,7 @@ import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
class NodeListPage extends BasePage {
|
class NodeListPage extends BasePage {
|
||||||
NodeListPage();
|
NodeListPage();
|
||||||
|
|
||||||
|
@override
|
||||||
String get title => S.current.nodes;
|
String get title => S.current.nodes;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -26,7 +27,7 @@ class NodeListPage extends BasePage {
|
||||||
minWidth: double.minPositive,
|
minWidth: double.minPositive,
|
||||||
child: FlatButton(
|
child: FlatButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await showDialog(
|
await showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
|
@ -76,10 +77,8 @@ class NodeListPage extends BasePage {
|
||||||
height: 28.0,
|
height: 28.0,
|
||||||
child: FlatButton(
|
child: FlatButton(
|
||||||
shape: CircleBorder(),
|
shape: CircleBorder(),
|
||||||
onPressed: () async {
|
onPressed: () async =>
|
||||||
await Navigator.of(context).pushNamed(Routes.newNode);
|
await Navigator.of(context).pushNamed(Routes.newNode),
|
||||||
nodeList.update();
|
|
||||||
},
|
|
||||||
child: Offstage()),
|
child: Offstage()),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
@ -94,7 +93,7 @@ class NodeListPage extends BasePage {
|
||||||
|
|
||||||
class NodeListPageBody extends StatefulWidget {
|
class NodeListPageBody extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
createState() => NodeListPageBodyState();
|
NodeListPageBodyState createState() => NodeListPageBodyState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class NodeListPageBodyState extends State<NodeListPageBody> {
|
class NodeListPageBodyState extends State<NodeListPageBody> {
|
||||||
|
@ -141,7 +140,7 @@ class NodeListPageBodyState extends State<NodeListPageBody> {
|
||||||
switch (snapshot.connectionState) {
|
switch (snapshot.connectionState) {
|
||||||
case ConnectionState.done:
|
case ConnectionState.done:
|
||||||
return NodeIndicator(
|
return NodeIndicator(
|
||||||
color: snapshot.data
|
color: snapshot.data as bool
|
||||||
? Palette.green
|
? Palette.green
|
||||||
: Palette.red);
|
: Palette.red);
|
||||||
default:
|
default:
|
||||||
|
@ -150,7 +149,7 @@ class NodeListPageBodyState extends State<NodeListPageBody> {
|
||||||
}),
|
}),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
if (!isCurrent) {
|
if (!isCurrent) {
|
||||||
await showDialog(
|
await showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
|
|
|
@ -6,19 +6,20 @@ import 'package:cake_wallet/src/stores/settings/settings_store.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
|
||||||
abstract class PinCodeWidget extends StatefulWidget {
|
abstract class PinCodeWidget extends StatefulWidget {
|
||||||
final Function(List<int> pin, PinCodeState state) onPinCodeEntered;
|
|
||||||
final bool hasLengthSwitcher;
|
|
||||||
|
|
||||||
PinCodeWidget({Key key, this.onPinCodeEntered, this.hasLengthSwitcher})
|
PinCodeWidget({Key key, this.onPinCodeEntered, this.hasLengthSwitcher})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
|
final Function(List<int> pin, PinCodeState state) onPinCodeEntered;
|
||||||
|
final bool hasLengthSwitcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
class PinCode extends PinCodeWidget {
|
class PinCode extends PinCodeWidget {
|
||||||
final Function(List<int> pin, PinCodeState state) onPinCodeEntered;
|
PinCode(Function(List<int> pin, PinCodeState state) onPinCodeEntered,
|
||||||
final bool hasLengthSwitcher;
|
bool hasLengthSwitcher, Key key)
|
||||||
|
: super(
|
||||||
PinCode(this.onPinCodeEntered, this.hasLengthSwitcher, Key key)
|
key: key,
|
||||||
: super(key: key);
|
onPinCodeEntered: onPinCodeEntered,
|
||||||
|
hasLengthSwitcher: hasLengthSwitcher);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
PinCodeState createState() => PinCodeState();
|
PinCodeState createState() => PinCodeState();
|
||||||
|
@ -30,27 +31,22 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
||||||
static const fourPinLength = 4;
|
static const fourPinLength = 4;
|
||||||
static final deleteIconImage = Image.asset('assets/images/delete_icon.png');
|
static final deleteIconImage = Image.asset('assets/images/delete_icon.png');
|
||||||
static final backArrowImage = Image.asset('assets/images/back_arrow.png');
|
static final backArrowImage = Image.asset('assets/images/back_arrow.png');
|
||||||
GlobalKey _gridViewKey = GlobalKey();
|
final _gridViewKey = GlobalKey();
|
||||||
|
|
||||||
int pinLength = defaultPinLength;
|
int pinLength = defaultPinLength;
|
||||||
List<int> pin = List<int>.filled(defaultPinLength, null);
|
List<int> pin = List<int>.filled(defaultPinLength, null);
|
||||||
String title = S.current.enter_your_pin;
|
String title = S.current.enter_your_pin;
|
||||||
double _aspectRatio = 0;
|
double _aspectRatio = 0;
|
||||||
|
|
||||||
void setTitle(String title) {
|
void setTitle(String title) => setState(() => this.title = title);
|
||||||
setState(() => this.title = title);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear() {
|
void clear() => setState(() => pin = List<int>.filled(pinLength, null));
|
||||||
setState(() => pin = List<int>.filled(pinLength, null));
|
|
||||||
}
|
|
||||||
|
|
||||||
void onPinCodeEntered(PinCodeState state) {
|
void onPinCodeEntered(PinCodeState state) =>
|
||||||
widget.onPinCodeEntered(state.pin, this);
|
widget.onPinCodeEntered(state.pin, this);
|
||||||
}
|
|
||||||
|
|
||||||
void changePinLength(int length) {
|
void changePinLength(int length) {
|
||||||
List<int> newPin = List<int>.filled(length, null);
|
final newPin = List<int>.filled(length, null);
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
pinLength = length;
|
pinLength = length;
|
||||||
|
@ -58,19 +54,23 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setDefaultPinLength() {
|
void setDefaultPinLength() {
|
||||||
final settingsStore = Provider.of<SettingsStore>(context);
|
final settingsStore = Provider.of<SettingsStore>(context);
|
||||||
|
|
||||||
pinLength = settingsStore.defaultPinLength;
|
pinLength = settingsStore.defaultPinLength;
|
||||||
changePinLength(pinLength);
|
changePinLength(pinLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentAspectRatio() {
|
void calculateAspectRatio() {
|
||||||
final RenderBox renderBox = _gridViewKey.currentContext.findRenderObject();
|
final renderBox =
|
||||||
|
_gridViewKey.currentContext.findRenderObject() as RenderBox;
|
||||||
|
final cellWidth = renderBox.size.width / 3;
|
||||||
|
final cellHeight = renderBox.size.height / 4;
|
||||||
|
|
||||||
|
if (cellWidth > 0 && cellHeight > 0) {
|
||||||
|
_aspectRatio = cellWidth / cellHeight;
|
||||||
|
}
|
||||||
|
|
||||||
double cellWidth = renderBox.size.width / 3;
|
|
||||||
double cellHeight = renderBox.size.height / 4;
|
|
||||||
if (cellWidth > 0 && cellHeight > 0) _aspectRatio = cellWidth / cellHeight;
|
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,15 +80,13 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
||||||
WidgetsBinding.instance.addPostFrameCallback(afterLayout);
|
WidgetsBinding.instance.addPostFrameCallback(afterLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
afterLayout(_) {
|
void afterLayout(dynamic _) {
|
||||||
setDefaultPinLength();
|
setDefaultPinLength();
|
||||||
getCurrentAspectRatio();
|
calculateAspectRatio();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) => Scaffold(body: body(context));
|
||||||
return Scaffold(body: body(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
return SafeArea(
|
return SafeArea(
|
||||||
|
@ -196,7 +194,7 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _push(int num) {
|
void _push(int num) {
|
||||||
if (_pinLength() >= pinLength) {
|
if (currentPinLength() >= pinLength) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,13 +205,15 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_pinLength() == pinLength) {
|
final _currentPinLength = currentPinLength();
|
||||||
|
|
||||||
|
if (_currentPinLength == pinLength) {
|
||||||
onPinCodeEntered(this);
|
onPinCodeEntered(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _pop() {
|
void _pop() {
|
||||||
if (_pinLength() == 0) {
|
if (currentPinLength() == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +225,7 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int _pinLength() {
|
int currentPinLength() {
|
||||||
return pin.fold(0, (v, e) {
|
return pin.fold(0, (v, e) {
|
||||||
if (e != null) {
|
if (e != null) {
|
||||||
return v + 1;
|
return v + 1;
|
||||||
|
|
|
@ -10,7 +10,7 @@ class QrImage extends StatelessWidget {
|
||||||
Color foregroundColor = Colors.black,
|
Color foregroundColor = Colors.black,
|
||||||
int version = 7,
|
int version = 7,
|
||||||
int errorCorrectionLevel = QrErrorCorrectLevel.L,
|
int errorCorrectionLevel = QrErrorCorrectLevel.L,
|
||||||
}) : _painter = new QrPainter(data, foregroundColor, version, errorCorrectionLevel);
|
}) : _painter = QrPainter(data, foregroundColor, version, errorCorrectionLevel);
|
||||||
|
|
||||||
final QrPainter _painter;
|
final QrPainter _painter;
|
||||||
final Color backgroundColor;
|
final Color backgroundColor;
|
||||||
|
@ -18,7 +18,7 @@ class QrImage extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return new Container(
|
return Container(
|
||||||
width: size,
|
width: size,
|
||||||
height: size,
|
height: size,
|
||||||
color: backgroundColor,
|
color: backgroundColor,
|
||||||
|
|
|
@ -7,27 +7,28 @@ class QrPainter extends CustomPainter {
|
||||||
this.color,
|
this.color,
|
||||||
this.version,
|
this.version,
|
||||||
this.errorCorrectionLevel,
|
this.errorCorrectionLevel,
|
||||||
) : this._qr = new QrCode(version, errorCorrectionLevel) {
|
) : this._qr = QrCode(version, errorCorrectionLevel) {
|
||||||
_p.color = this.color;
|
_p.color = this.color;
|
||||||
|
|
||||||
_qr.addData(data);
|
_qr.addData(data);
|
||||||
_qr.make();
|
_qr.make();
|
||||||
}
|
}
|
||||||
|
|
||||||
final QrCode _qr;
|
|
||||||
final _p = new Paint()..style = PaintingStyle.fill;
|
|
||||||
|
|
||||||
final int version;
|
final int version;
|
||||||
final int errorCorrectionLevel;
|
final int errorCorrectionLevel;
|
||||||
final Color color;
|
final Color color;
|
||||||
|
|
||||||
|
final QrCode _qr;
|
||||||
|
final _p = Paint()..style = PaintingStyle.fill;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void paint(Canvas canvas, Size size) {
|
void paint(Canvas canvas, Size size) {
|
||||||
final squareSize = size.shortestSide / _qr.moduleCount;
|
final squareSize = size.shortestSide / _qr.moduleCount;
|
||||||
for (int x = 0; x < _qr.moduleCount; x++) {
|
for (int x = 0; x < _qr.moduleCount; x++) {
|
||||||
for (int y = 0; y < _qr.moduleCount; y++) {
|
for (int y = 0; y < _qr.moduleCount; y++) {
|
||||||
if (_qr.isDark(y, x)) {
|
if (_qr.isDark(y, x)) {
|
||||||
final squareRect = new Rect.fromLTWH(x * squareSize, y * squareSize, squareSize, squareSize);
|
final squareRect = Rect.fromLTWH(
|
||||||
|
x * squareSize, y * squareSize, squareSize, squareSize);
|
||||||
canvas.drawRect(squareRect, _p);
|
canvas.drawRect(squareRect, _p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,9 +38,11 @@ class QrPainter extends CustomPainter {
|
||||||
@override
|
@override
|
||||||
bool shouldRepaint(CustomPainter oldDelegate) {
|
bool shouldRepaint(CustomPainter oldDelegate) {
|
||||||
if (oldDelegate is QrPainter) {
|
if (oldDelegate is QrPainter) {
|
||||||
return this.color != oldDelegate.color || this.errorCorrectionLevel != oldDelegate.errorCorrectionLevel ||
|
return this.color != oldDelegate.color ||
|
||||||
|
this.errorCorrectionLevel != oldDelegate.errorCorrectionLevel ||
|
||||||
this.version != oldDelegate.version;
|
this.version != oldDelegate.version;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -13,7 +13,10 @@ import 'package:cake_wallet/src/screens/receive/qr_image.dart';
|
||||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
|
|
||||||
class ReceivePage extends BasePage {
|
class ReceivePage extends BasePage {
|
||||||
|
@override
|
||||||
bool get isModalBackButton => true;
|
bool get isModalBackButton => true;
|
||||||
|
|
||||||
|
@override
|
||||||
String get title => S.current.receive;
|
String get title => S.current.receive;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -31,7 +34,10 @@ class ReceivePage extends BasePage {
|
||||||
padding: EdgeInsets.all(0),
|
padding: EdgeInsets.all(0),
|
||||||
onPressed: () => Share.text(
|
onPressed: () => Share.text(
|
||||||
'Share address', walletStore.subaddress.address, 'text/plain'),
|
'Share address', walletStore.subaddress.address, 'text/plain'),
|
||||||
child: Icon(Icons.share, size: 30.0,)),
|
child: Icon(
|
||||||
|
Icons.share,
|
||||||
|
size: 30.0,
|
||||||
|
)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -43,7 +49,7 @@ class ReceivePage extends BasePage {
|
||||||
|
|
||||||
class ReceiveBody extends StatefulWidget {
|
class ReceiveBody extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
createState() => ReceiveBodyState();
|
ReceiveBodyState createState() => ReceiveBodyState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReceiveBodyState extends State<ReceiveBody> {
|
class ReceiveBodyState extends State<ReceiveBody> {
|
||||||
|
@ -67,8 +73,9 @@ class ReceiveBodyState extends State<ReceiveBody> {
|
||||||
amountController.addListener(() {
|
amountController.addListener(() {
|
||||||
if (_formKey.currentState.validate()) {
|
if (_formKey.currentState.validate()) {
|
||||||
walletStore.onChangedAmountValue(amountController.text);
|
walletStore.onChangedAmountValue(amountController.text);
|
||||||
} else
|
} else {
|
||||||
walletStore.onChangedAmountValue('');
|
walletStore.onChangedAmountValue('');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return SafeArea(
|
return SafeArea(
|
||||||
|
@ -152,7 +159,7 @@ class ReceiveBodyState extends State<ReceiveBody> {
|
||||||
TextInputType.numberWithOptions(decimal: true),
|
TextInputType.numberWithOptions(decimal: true),
|
||||||
inputFormatters: [
|
inputFormatters: [
|
||||||
BlacklistingTextInputFormatter(
|
BlacklistingTextInputFormatter(
|
||||||
new RegExp('[\\-|\\ |\\,]'))
|
RegExp('[\\-|\\ |\\,]'))
|
||||||
],
|
],
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14.0,
|
fontSize: 14.0,
|
||||||
|
@ -163,8 +170,7 @@ class ReceiveBodyState extends State<ReceiveBody> {
|
||||||
hintText: S.of(context).amount,
|
hintText: S.of(context).amount,
|
||||||
focusedBorder: UnderlineInputBorder(
|
focusedBorder: UnderlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Palette.cakeGreen,
|
color: Palette.cakeGreen, width: 2.0)),
|
||||||
width: 2.0)),
|
|
||||||
enabledBorder: UnderlineInputBorder(
|
enabledBorder: UnderlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Theme.of(context).focusColor,
|
color: Theme.of(context).focusColor,
|
||||||
|
|
|
@ -9,7 +9,10 @@ import 'package:cake_wallet/generated/i18n.dart';
|
||||||
class RestoreOptionsPage extends BasePage {
|
class RestoreOptionsPage extends BasePage {
|
||||||
static const _aspectRatioImage = 2.086;
|
static const _aspectRatioImage = 2.086;
|
||||||
|
|
||||||
|
@override
|
||||||
String get title => S.current.restore_restore_wallet;
|
String get title => S.current.restore_restore_wallet;
|
||||||
|
|
||||||
|
@override
|
||||||
Color get backgroundColor => Palette.creamyGrey;
|
Color get backgroundColor => Palette.creamyGrey;
|
||||||
|
|
||||||
final _imageSeedKeys = Image.asset('assets/images/seedKeys.png');
|
final _imageSeedKeys = Image.asset('assets/images/seedKeys.png');
|
||||||
|
@ -26,7 +29,8 @@ class RestoreOptionsPage extends BasePage {
|
||||||
Flexible(
|
Flexible(
|
||||||
child: RestoreButton(
|
child: RestoreButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pushNamed(context, Routes.restoreWalletOptionsFromWelcome);
|
Navigator.pushNamed(
|
||||||
|
context, Routes.restoreWalletOptionsFromWelcome);
|
||||||
},
|
},
|
||||||
image: _imageSeedKeys,
|
image: _imageSeedKeys,
|
||||||
aspectRatioImage: _aspectRatioImage,
|
aspectRatioImage: _aspectRatioImage,
|
||||||
|
|
|
@ -17,24 +17,25 @@ import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||||
import 'package:cake_wallet/palette.dart';
|
import 'package:cake_wallet/palette.dart';
|
||||||
|
|
||||||
class RestoreWalletFromKeysPage extends BasePage {
|
class RestoreWalletFromKeysPage extends BasePage {
|
||||||
final WalletListService walletsService;
|
|
||||||
final WalletService walletService;
|
|
||||||
final SharedPreferences sharedPreferences;
|
|
||||||
|
|
||||||
String get title => S.current.restore_title_from_keys;
|
|
||||||
|
|
||||||
RestoreWalletFromKeysPage(
|
RestoreWalletFromKeysPage(
|
||||||
{@required this.walletsService,
|
{@required this.walletsService,
|
||||||
@required this.sharedPreferences,
|
@required this.sharedPreferences,
|
||||||
@required this.walletService});
|
@required this.walletService});
|
||||||
|
|
||||||
|
final WalletListService walletsService;
|
||||||
|
final WalletService walletService;
|
||||||
|
final SharedPreferences sharedPreferences;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get title => S.current.restore_title_from_keys;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) => RestoreFromKeysFrom();
|
Widget body(BuildContext context) => RestoreFromKeysFrom();
|
||||||
}
|
}
|
||||||
|
|
||||||
class RestoreFromKeysFrom extends StatefulWidget {
|
class RestoreFromKeysFrom extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
createState() => _RestoreFromKeysFromState();
|
_RestoreFromKeysFromState createState() => _RestoreFromKeysFromState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
|
class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
|
||||||
|
@ -49,14 +50,14 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final walletRestorationStore = Provider.of<WalletRestorationStore>(context);
|
final walletRestorationStore = Provider.of<WalletRestorationStore>(context);
|
||||||
|
|
||||||
reaction((_) => walletRestorationStore.state, (state) {
|
reaction((_) => walletRestorationStore.state, (WalletRestorationState state) {
|
||||||
if (state is WalletRestoredSuccessfully) {
|
if (state is WalletRestoredSuccessfully) {
|
||||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state is WalletRestorationFailure) {
|
if (state is WalletRestorationFailure) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
showDialog(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
|
@ -97,8 +98,7 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
|
||||||
hintText: S.of(context).restore_wallet_name,
|
hintText: S.of(context).restore_wallet_name,
|
||||||
focusedBorder: UnderlineInputBorder(
|
focusedBorder: UnderlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Palette.cakeGreen,
|
color: Palette.cakeGreen, width: 2.0)),
|
||||||
width: 2.0)),
|
|
||||||
enabledBorder: UnderlineInputBorder(
|
enabledBorder: UnderlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Theme.of(context).focusColor,
|
color: Theme.of(context).focusColor,
|
||||||
|
@ -127,8 +127,7 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
|
||||||
hintText: S.of(context).restore_address,
|
hintText: S.of(context).restore_address,
|
||||||
focusedBorder: UnderlineInputBorder(
|
focusedBorder: UnderlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Palette.cakeGreen,
|
color: Palette.cakeGreen, width: 2.0)),
|
||||||
width: 2.0)),
|
|
||||||
enabledBorder: UnderlineInputBorder(
|
enabledBorder: UnderlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Theme.of(context).focusColor,
|
color: Theme.of(context).focusColor,
|
||||||
|
@ -155,8 +154,7 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
|
||||||
hintText: S.of(context).restore_view_key_private,
|
hintText: S.of(context).restore_view_key_private,
|
||||||
focusedBorder: UnderlineInputBorder(
|
focusedBorder: UnderlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Palette.cakeGreen,
|
color: Palette.cakeGreen, width: 2.0)),
|
||||||
width: 2.0)),
|
|
||||||
enabledBorder: UnderlineInputBorder(
|
enabledBorder: UnderlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Theme.of(context).focusColor,
|
color: Theme.of(context).focusColor,
|
||||||
|
@ -183,8 +181,7 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
|
||||||
hintText: S.of(context).restore_spend_key_private,
|
hintText: S.of(context).restore_spend_key_private,
|
||||||
focusedBorder: UnderlineInputBorder(
|
focusedBorder: UnderlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Palette.cakeGreen,
|
color: Palette.cakeGreen, width: 2.0)),
|
||||||
width: 2.0)),
|
|
||||||
enabledBorder: UnderlineInputBorder(
|
enabledBorder: UnderlineInputBorder(
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Theme.of(context).focusColor,
|
color: Theme.of(context).focusColor,
|
||||||
|
|
|
@ -13,6 +13,7 @@ import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||||
import 'package:cake_wallet/palette.dart';
|
import 'package:cake_wallet/palette.dart';
|
||||||
|
|
||||||
class RestoreWalletFromSeedDetailsPage extends BasePage {
|
class RestoreWalletFromSeedDetailsPage extends BasePage {
|
||||||
|
@override
|
||||||
String get title => S.current.restore_wallet_restore_description;
|
String get title => S.current.restore_wallet_restore_description;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -21,7 +22,8 @@ class RestoreWalletFromSeedDetailsPage extends BasePage {
|
||||||
|
|
||||||
class RestoreFromSeedDetailsForm extends StatefulWidget {
|
class RestoreFromSeedDetailsForm extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
createState() => _RestoreFromSeedDetailsFormState();
|
_RestoreFromSeedDetailsFormState createState() =>
|
||||||
|
_RestoreFromSeedDetailsFormState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _RestoreFromSeedDetailsFormState
|
class _RestoreFromSeedDetailsFormState
|
||||||
|
@ -34,14 +36,14 @@ class _RestoreFromSeedDetailsFormState
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final walletRestorationStore = Provider.of<WalletRestorationStore>(context);
|
final walletRestorationStore = Provider.of<WalletRestorationStore>(context);
|
||||||
|
|
||||||
reaction((_) => walletRestorationStore.state, (state) {
|
reaction((_) => walletRestorationStore.state, (WalletRestorationState state) {
|
||||||
if (state is WalletRestoredSuccessfully) {
|
if (state is WalletRestoredSuccessfully) {
|
||||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state is WalletRestorationFailure) {
|
if (state is WalletRestorationFailure) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
showDialog(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
|
|
|
@ -14,24 +14,25 @@ import 'package:cake_wallet/src/stores/wallet_restoration/wallet_restoration_sto
|
||||||
import 'package:cake_wallet/src/widgets/seed_widget.dart';
|
import 'package:cake_wallet/src/widgets/seed_widget.dart';
|
||||||
|
|
||||||
class RestoreWalletFromSeedPage extends BasePage {
|
class RestoreWalletFromSeedPage extends BasePage {
|
||||||
final WalletListService walletsService;
|
|
||||||
final WalletService walletService;
|
|
||||||
final SharedPreferences sharedPreferences;
|
|
||||||
|
|
||||||
String get title => S.current.restore_title_from_seed;
|
|
||||||
|
|
||||||
RestoreWalletFromSeedPage(
|
RestoreWalletFromSeedPage(
|
||||||
{@required this.walletsService,
|
{@required this.walletsService,
|
||||||
@required this.walletService,
|
@required this.walletService,
|
||||||
@required this.sharedPreferences});
|
@required this.sharedPreferences});
|
||||||
|
|
||||||
|
final WalletListService walletsService;
|
||||||
|
final WalletService walletService;
|
||||||
|
final SharedPreferences sharedPreferences;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get title => S.current.restore_title_from_seed;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) => RestoreFromSeedForm();
|
Widget body(BuildContext context) => RestoreFromSeedForm();
|
||||||
}
|
}
|
||||||
|
|
||||||
class RestoreFromSeedForm extends StatefulWidget {
|
class RestoreFromSeedForm extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
createState() => _RestoreFromSeedFormState();
|
_RestoreFromSeedFormState createState() => _RestoreFromSeedFormState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _RestoreFromSeedFormState extends State<RestoreFromSeedForm> {
|
class _RestoreFromSeedFormState extends State<RestoreFromSeedForm> {
|
||||||
|
@ -46,9 +47,8 @@ class _RestoreFromSeedFormState extends State<RestoreFromSeedForm> {
|
||||||
(_) => _setReactions(context, walletRestorationStore));
|
(_) => _setReactions(context, walletRestorationStore));
|
||||||
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () =>
|
||||||
SystemChannels.textInput.invokeMethod('TextInput.hide');
|
SystemChannels.textInput.invokeMethod<void>('TextInput.hide'),
|
||||||
},
|
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.only(left: 20.0, right: 20.0, bottom: 20.0),
|
padding: EdgeInsets.only(left: 20.0, right: 20.0, bottom: 20.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
@ -90,7 +90,7 @@ class _RestoreFromSeedFormState extends State<RestoreFromSeedForm> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
reaction((_) => store.errorMessage, (errorMessage) {
|
reaction((_) => store.errorMessage, (String errorMessage) {
|
||||||
if (errorMessage == null || errorMessage.isEmpty) {
|
if (errorMessage == null || errorMessage.isEmpty) {
|
||||||
_seedKey.currentState.validated();
|
_seedKey.currentState.validated();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -9,7 +9,10 @@ import 'package:cake_wallet/generated/i18n.dart';
|
||||||
class RestoreWalletOptionsPage extends BasePage {
|
class RestoreWalletOptionsPage extends BasePage {
|
||||||
static const _aspectRatioImage = 2.086;
|
static const _aspectRatioImage = 2.086;
|
||||||
|
|
||||||
|
@override
|
||||||
String get title => S.current.restore_seed_keys_restore;
|
String get title => S.current.restore_seed_keys_restore;
|
||||||
|
|
||||||
|
@override
|
||||||
Color get backgroundColor => Palette.creamyGrey;
|
Color get backgroundColor => Palette.creamyGrey;
|
||||||
|
|
||||||
final _imageSeed = Image.asset('assets/images/seedIco.png');
|
final _imageSeed = Image.asset('assets/images/seedIco.png');
|
||||||
|
|
|
@ -2,15 +2,6 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:cake_wallet/palette.dart';
|
import 'package:cake_wallet/palette.dart';
|
||||||
|
|
||||||
class RestoreButton extends StatelessWidget {
|
class RestoreButton extends StatelessWidget {
|
||||||
final VoidCallback onPressed;
|
|
||||||
final Image image;
|
|
||||||
final double aspectRatioImage;
|
|
||||||
final Color color;
|
|
||||||
final Color titleColor;
|
|
||||||
final String title;
|
|
||||||
final String description;
|
|
||||||
final String textButton;
|
|
||||||
|
|
||||||
const RestoreButton(
|
const RestoreButton(
|
||||||
{@required this.onPressed,
|
{@required this.onPressed,
|
||||||
@required this.image,
|
@required this.image,
|
||||||
|
@ -21,9 +12,17 @@ class RestoreButton extends StatelessWidget {
|
||||||
this.description = '',
|
this.description = '',
|
||||||
this.textButton = ''});
|
this.textButton = ''});
|
||||||
|
|
||||||
|
final VoidCallback onPressed;
|
||||||
|
final Image image;
|
||||||
|
final double aspectRatioImage;
|
||||||
|
final Color color;
|
||||||
|
final Color titleColor;
|
||||||
|
final String title;
|
||||||
|
final String description;
|
||||||
|
final String textButton;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
margin: EdgeInsets.only(top: 20.0, bottom: 20.0),
|
margin: EdgeInsets.only(top: 20.0, bottom: 20.0),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
|
@ -71,9 +70,9 @@ class RestoreButton extends StatelessWidget {
|
||||||
child: Text(
|
child: Text(
|
||||||
description,
|
description,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style:
|
style: TextStyle(
|
||||||
TextStyle(
|
color:
|
||||||
color: Theme.of(context).accentTextTheme.subhead.color,
|
Theme.of(context).accentTextTheme.subhead.color,
|
||||||
fontSize: 14.0,
|
fontSize: 14.0,
|
||||||
height: 1.4),
|
height: 1.4),
|
||||||
),
|
),
|
||||||
|
@ -88,7 +87,10 @@ class RestoreButton extends StatelessWidget {
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border(
|
border: Border(
|
||||||
top: BorderSide(
|
top: BorderSide(
|
||||||
color: Theme.of(context).accentTextTheme.headline.decorationColor,
|
color: Theme.of(context)
|
||||||
|
.accentTextTheme
|
||||||
|
.headline
|
||||||
|
.decorationColor,
|
||||||
width: 1.15)),
|
width: 1.15)),
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import 'package:cake_wallet/src/screens/welcome/create_welcome_page.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:cake_wallet/routes.dart';
|
import 'package:cake_wallet/routes.dart';
|
||||||
import 'package:cake_wallet/router.dart';
|
|
||||||
import 'package:cake_wallet/src/stores/authentication/authentication_store.dart';
|
import 'package:cake_wallet/src/stores/authentication/authentication_store.dart';
|
||||||
import 'package:cake_wallet/src/stores/price/price_store.dart';
|
import 'package:cake_wallet/src/stores/price/price_store.dart';
|
||||||
import 'package:cake_wallet/src/stores/settings/settings_store.dart';
|
import 'package:cake_wallet/src/stores/settings/settings_store.dart';
|
||||||
|
@ -19,6 +17,8 @@ import 'package:cake_wallet/src/domain/monero/transaction_description.dart';
|
||||||
import 'package:cake_wallet/src/screens/auth/create_login_page.dart';
|
import 'package:cake_wallet/src/screens/auth/create_login_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/seed/create_seed_page.dart';
|
import 'package:cake_wallet/src/screens/seed/create_seed_page.dart';
|
||||||
import 'package:cake_wallet/src/screens/dashboard/create_dashboard_page.dart';
|
import 'package:cake_wallet/src/screens/dashboard/create_dashboard_page.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
||||||
|
import 'package:cake_wallet/src/screens/welcome/create_welcome_page.dart';
|
||||||
|
|
||||||
class Root extends StatefulWidget {
|
class Root extends StatefulWidget {
|
||||||
Root({Key key}) : super(key: key);
|
Root({Key key}) : super(key: key);
|
||||||
|
@ -81,7 +81,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
Navigator.of(context).pushNamed(Routes.unlock,
|
Navigator.of(context).pushNamed(Routes.unlock,
|
||||||
arguments: (isAuthenticatedSuccessfully, auth) {
|
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
||||||
if (!isAuthenticatedSuccessfully) {
|
if (!isAuthenticatedSuccessfully) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,14 +11,19 @@ import 'package:cake_wallet/src/stores/wallet_seed/wallet_seed_store.dart';
|
||||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||||
|
|
||||||
class SeedPage extends BasePage {
|
class SeedPage extends BasePage {
|
||||||
|
SeedPage({this.onCloseCallback});
|
||||||
|
|
||||||
static final image = Image.asset('assets/images/seed_image.png');
|
static final image = Image.asset('assets/images/seed_image.png');
|
||||||
|
|
||||||
|
@override
|
||||||
bool get isModalBackButton => true;
|
bool get isModalBackButton => true;
|
||||||
|
|
||||||
|
@override
|
||||||
String get title => S.current.seed_title;
|
String get title => S.current.seed_title;
|
||||||
|
|
||||||
final VoidCallback onCloseCallback;
|
final VoidCallback onCloseCallback;
|
||||||
|
|
||||||
SeedPage({this.onCloseCallback});
|
@override
|
||||||
|
|
||||||
void onClose(BuildContext context) =>
|
void onClose(BuildContext context) =>
|
||||||
onCloseCallback != null ? onCloseCallback() : Navigator.of(context).pop();
|
onCloseCallback != null ? onCloseCallback() : Navigator.of(context).pop();
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'package:cake_wallet/src/screens/auth/auth_page.dart';
|
||||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
@ -23,8 +24,13 @@ import 'package:cake_wallet/src/domain/common/sync_status.dart';
|
||||||
import 'package:cake_wallet/src/stores/sync/sync_store.dart';
|
import 'package:cake_wallet/src/stores/sync/sync_store.dart';
|
||||||
|
|
||||||
class SendPage extends BasePage {
|
class SendPage extends BasePage {
|
||||||
|
@override
|
||||||
String get title => S.current.send_title;
|
String get title => S.current.send_title;
|
||||||
|
|
||||||
|
@override
|
||||||
bool get isModalBackButton => true;
|
bool get isModalBackButton => true;
|
||||||
|
|
||||||
|
@override
|
||||||
bool get resizeToAvoidBottomPadding => false;
|
bool get resizeToAvoidBottomPadding => false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -212,7 +218,7 @@ class SendFormState extends State<SendForm> {
|
||||||
signed: false, decimal: false),
|
signed: false, decimal: false),
|
||||||
inputFormatters: [
|
inputFormatters: [
|
||||||
BlacklistingTextInputFormatter(
|
BlacklistingTextInputFormatter(
|
||||||
new RegExp('[\\-|\\ |\\,]'))
|
RegExp('[\\-|\\ |\\,]'))
|
||||||
],
|
],
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
prefixIcon: Padding(
|
prefixIcon: Padding(
|
||||||
|
@ -272,7 +278,7 @@ class SendFormState extends State<SendForm> {
|
||||||
signed: false, decimal: false),
|
signed: false, decimal: false),
|
||||||
inputFormatters: [
|
inputFormatters: [
|
||||||
BlacklistingTextInputFormatter(
|
BlacklistingTextInputFormatter(
|
||||||
new RegExp('[\\-|\\ |\\,]'))
|
RegExp('[\\-|\\ |\\,]'))
|
||||||
],
|
],
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
prefixIcon: Padding(
|
prefixIcon: Padding(
|
||||||
|
@ -353,7 +359,7 @@ class SendFormState extends State<SendForm> {
|
||||||
FocusScope.of(context).requestFocus(FocusNode());
|
FocusScope.of(context).requestFocus(FocusNode());
|
||||||
|
|
||||||
if (_formKey.currentState.validate()) {
|
if (_formKey.currentState.validate()) {
|
||||||
await showDialog(
|
await showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (dialogContext) {
|
builder: (dialogContext) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
|
@ -364,12 +370,11 @@ class SendFormState extends State<SendForm> {
|
||||||
FlatButton(
|
FlatButton(
|
||||||
child: Text(S.of(context).send),
|
child: Text(S.of(context).send),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
Navigator.of(dialogContext)
|
await Navigator.of(dialogContext)
|
||||||
.popAndPushNamed(
|
.popAndPushNamed(Routes.auth,
|
||||||
Routes.auth,
|
arguments: (bool
|
||||||
arguments:
|
isAuthenticatedSuccessfully,
|
||||||
(isAuthenticatedSuccessfully,
|
AuthPageState auth) {
|
||||||
auth) {
|
|
||||||
if (!isAuthenticatedSuccessfully) {
|
if (!isAuthenticatedSuccessfully) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -408,13 +413,13 @@ class SendFormState extends State<SendForm> {
|
||||||
|
|
||||||
final sendStore = Provider.of<SendStore>(context);
|
final sendStore = Provider.of<SendStore>(context);
|
||||||
|
|
||||||
reaction((_) => sendStore.fiatAmount, (amount) {
|
reaction((_) => sendStore.fiatAmount, (String amount) {
|
||||||
if (amount != _fiatAmountController.text) {
|
if (amount != _fiatAmountController.text) {
|
||||||
_fiatAmountController.text = amount;
|
_fiatAmountController.text = amount;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
reaction((_) => sendStore.cryptoAmount, (amount) {
|
reaction((_) => sendStore.cryptoAmount, (String amount) {
|
||||||
if (amount != _cryptoAmountController.text) {
|
if (amount != _cryptoAmountController.text) {
|
||||||
_cryptoAmountController.text = amount;
|
_cryptoAmountController.text = amount;
|
||||||
}
|
}
|
||||||
|
@ -436,10 +441,10 @@ class SendFormState extends State<SendForm> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
reaction((_) => sendStore.state, (state) {
|
reaction((_) => sendStore.state, (SendingState state) {
|
||||||
if (state is SendingFailed) {
|
if (state is SendingFailed) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
showDialog(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
|
@ -457,7 +462,7 @@ class SendFormState extends State<SendForm> {
|
||||||
|
|
||||||
if (state is TransactionCreatedSuccessfully) {
|
if (state is TransactionCreatedSuccessfully) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
showDialog(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
|
|
|
@ -21,7 +21,8 @@ const Map<String, String> _languages = {
|
||||||
};
|
};
|
||||||
|
|
||||||
class ChangeLanguage extends BasePage {
|
class ChangeLanguage extends BasePage {
|
||||||
get title => S.current.settings_change_language;
|
@override
|
||||||
|
String get title => S.current.settings_change_language;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget body(BuildContext context) {
|
Widget body(BuildContext context) {
|
||||||
|
@ -50,7 +51,7 @@ class ChangeLanguage extends BasePage {
|
||||||
),
|
),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
if (!isCurrent) {
|
if (!isCurrent) {
|
||||||
await showDialog(
|
await showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
|
|
|
@ -7,39 +7,41 @@ import 'package:cake_wallet/theme_changer.dart';
|
||||||
import 'package:cake_wallet/themes.dart';
|
import 'package:cake_wallet/themes.dart';
|
||||||
import 'package:cake_wallet/generated/i18n.dart';
|
import 'package:cake_wallet/generated/i18n.dart';
|
||||||
|
|
||||||
class EnterPinCode extends StatefulWidget{
|
class EnterPinCode extends StatefulWidget {
|
||||||
|
const EnterPinCode(this.currentPinLength, this.currentPin);
|
||||||
|
|
||||||
final int currentPinLength;
|
final int currentPinLength;
|
||||||
final List<int> currentPin;
|
final List<int> currentPin;
|
||||||
|
|
||||||
const EnterPinCode(this.currentPinLength, this.currentPin);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
createState() => EnterPinCodeState(currentPinLength, currentPin);
|
EnterPinCodeState createState() =>
|
||||||
|
EnterPinCodeState(currentPinLength, currentPin);
|
||||||
}
|
}
|
||||||
|
|
||||||
class EnterPinCodeState extends State<EnterPinCode>{
|
class EnterPinCodeState extends State<EnterPinCode> {
|
||||||
GlobalKey _gridViewKey = GlobalKey();
|
EnterPinCodeState(this.pinLength, this.currentPin);
|
||||||
|
|
||||||
|
final _gridViewKey = GlobalKey();
|
||||||
final _closeButtonImage = Image.asset('assets/images/close_button.png');
|
final _closeButtonImage = Image.asset('assets/images/close_button.png');
|
||||||
final _closeButtonImageDarkTheme = Image.asset('assets/images/close_button_dark_theme.png');
|
final _closeButtonImageDarkTheme =
|
||||||
|
Image.asset('assets/images/close_button_dark_theme.png');
|
||||||
static final deleteIconImage = Image.asset('assets/images/delete_icon.png');
|
static final deleteIconImage = Image.asset('assets/images/delete_icon.png');
|
||||||
final int pinLength;
|
final int pinLength;
|
||||||
final List<int> currentPin;
|
final List<int> currentPin;
|
||||||
List<int> pin;
|
List<int> pin;
|
||||||
double _aspectRatio = 0;
|
double _aspectRatio = 0;
|
||||||
|
|
||||||
EnterPinCodeState(this.pinLength, this.currentPin);
|
void _calcualteCurrentAspectRatio() {
|
||||||
|
final renderBox =
|
||||||
|
_gridViewKey.currentContext.findRenderObject() as RenderBox;
|
||||||
|
final cellWidth = renderBox.size.width / 3;
|
||||||
|
final cellHeight = renderBox.size.height / 4;
|
||||||
|
|
||||||
_getCurrentAspectRatio(){
|
if (cellWidth > 0 && cellHeight > 0) {
|
||||||
final RenderBox renderBox = _gridViewKey.currentContext.findRenderObject();
|
_aspectRatio = cellWidth / cellHeight;
|
||||||
|
}
|
||||||
|
|
||||||
double cellWidth = renderBox.size.width/3;
|
setState(() {});
|
||||||
double cellHeight = renderBox.size.height/4;
|
|
||||||
if (cellWidth > 0 && cellHeight > 0) _aspectRatio = cellWidth/cellHeight;
|
|
||||||
setState(() {
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -49,18 +51,12 @@ class EnterPinCodeState extends State<EnterPinCode>{
|
||||||
WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
|
WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
_afterLayout(_) {
|
void _afterLayout(dynamic _) => _calcualteCurrentAspectRatio();
|
||||||
_getCurrentAspectRatio();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final _themeChanger = Provider.of<ThemeChanger>(context);
|
||||||
ThemeChanger _themeChanger = Provider.of<ThemeChanger>(context);
|
final _isDarkTheme = _themeChanger.getTheme() == Themes.darkTheme;
|
||||||
bool _isDarkTheme;
|
|
||||||
|
|
||||||
if (_themeChanger.getTheme() == Themes.darkTheme) _isDarkTheme = true;
|
|
||||||
else _isDarkTheme = false;
|
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Theme.of(context).backgroundColor,
|
backgroundColor: Theme.of(context).backgroundColor,
|
||||||
|
@ -68,13 +64,15 @@ class EnterPinCodeState extends State<EnterPinCode>{
|
||||||
leading: ButtonTheme(
|
leading: ButtonTheme(
|
||||||
minWidth: double.minPositive,
|
minWidth: double.minPositive,
|
||||||
child: FlatButton(
|
child: FlatButton(
|
||||||
onPressed: (){ Navigator.pop(context, false); },
|
onPressed: () {
|
||||||
child: _isDarkTheme ? _closeButtonImageDarkTheme : _closeButtonImage
|
Navigator.pop(context, false);
|
||||||
),
|
},
|
||||||
|
child: _isDarkTheme
|
||||||
|
? _closeButtonImageDarkTheme
|
||||||
|
: _closeButtonImage),
|
||||||
),
|
),
|
||||||
backgroundColor: Theme.of(context).backgroundColor,
|
backgroundColor: Theme.of(context).backgroundColor,
|
||||||
border: null,
|
border: null),
|
||||||
),
|
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.only(left: 40.0, right: 40.0, bottom: 40.0),
|
padding: EdgeInsets.only(left: 40.0, right: 40.0, bottom: 40.0),
|
||||||
|
@ -82,11 +80,7 @@ class EnterPinCodeState extends State<EnterPinCode>{
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Spacer(flex: 2),
|
Spacer(flex: 2),
|
||||||
Text(S.of(context).enter_your_pin,
|
Text(S.of(context).enter_your_pin,
|
||||||
style: TextStyle(
|
style: TextStyle(fontSize: 24, color: Palette.wildDarkBlue)),
|
||||||
fontSize: 24,
|
|
||||||
color: Palette.wildDarkBlue
|
|
||||||
)
|
|
||||||
),
|
|
||||||
Spacer(flex: 3),
|
Spacer(flex: 3),
|
||||||
Container(
|
Container(
|
||||||
width: 180,
|
width: 180,
|
||||||
|
@ -101,7 +95,8 @@ class EnterPinCodeState extends State<EnterPinCode>{
|
||||||
height: size,
|
height: size,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
color: isFilled ? Palette.deepPurple : Colors.transparent,
|
color:
|
||||||
|
isFilled ? Palette.deepPurple : Colors.transparent,
|
||||||
border: Border.all(color: Palette.wildDarkBlue),
|
border: Border.all(color: Palette.wildDarkBlue),
|
||||||
));
|
));
|
||||||
}),
|
}),
|
||||||
|
@ -112,18 +107,19 @@ class EnterPinCodeState extends State<EnterPinCode>{
|
||||||
flex: 24,
|
flex: 24,
|
||||||
child: Container(
|
child: Container(
|
||||||
key: _gridViewKey,
|
key: _gridViewKey,
|
||||||
child: _aspectRatio > 0 ? GridView.count(
|
child: _aspectRatio > 0
|
||||||
|
? GridView.count(
|
||||||
crossAxisCount: 3,
|
crossAxisCount: 3,
|
||||||
childAspectRatio: _aspectRatio,
|
childAspectRatio: _aspectRatio,
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
children: List.generate(12, (index) {
|
children: List.generate(12, (index) {
|
||||||
|
|
||||||
if (index == 9) {
|
if (index == 9) {
|
||||||
return Container(
|
return Container(
|
||||||
margin: EdgeInsets.all(5.0),
|
margin: EdgeInsets.all(5.0),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
color: _isDarkTheme ? PaletteDark.darkThemePinButton
|
color: _isDarkTheme
|
||||||
|
? PaletteDark.darkThemePinButton
|
||||||
: Palette.darkGrey,
|
: Palette.darkGrey,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -133,8 +129,11 @@ class EnterPinCodeState extends State<EnterPinCode>{
|
||||||
return Container(
|
return Container(
|
||||||
margin: EdgeInsets.all(5.0),
|
margin: EdgeInsets.all(5.0),
|
||||||
child: FlatButton(
|
child: FlatButton(
|
||||||
onPressed: () { _pop(); },
|
onPressed: () {
|
||||||
color: _isDarkTheme ? PaletteDark.darkThemePinButton
|
_pop();
|
||||||
|
},
|
||||||
|
color: _isDarkTheme
|
||||||
|
? PaletteDark.darkThemePinButton
|
||||||
: Palette.darkGrey,
|
: Palette.darkGrey,
|
||||||
shape: CircleBorder(),
|
shape: CircleBorder(),
|
||||||
child: deleteIconImage,
|
child: deleteIconImage,
|
||||||
|
@ -147,32 +146,30 @@ class EnterPinCodeState extends State<EnterPinCode>{
|
||||||
return Container(
|
return Container(
|
||||||
margin: EdgeInsets.all(5.0),
|
margin: EdgeInsets.all(5.0),
|
||||||
child: FlatButton(
|
child: FlatButton(
|
||||||
onPressed: () { _push(index); },
|
onPressed: () {
|
||||||
color: _isDarkTheme ? PaletteDark.darkThemePinDigitButton
|
_push(index);
|
||||||
|
},
|
||||||
|
color: _isDarkTheme
|
||||||
|
? PaletteDark.darkThemePinDigitButton
|
||||||
: Palette.creamyGrey,
|
: Palette.creamyGrey,
|
||||||
shape: CircleBorder(),
|
shape: CircleBorder(),
|
||||||
child: Text(
|
child: Text('$index',
|
||||||
'$index',
|
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 23.0,
|
fontSize: 23.0,
|
||||||
color: Palette.blueGrey
|
color: Palette.blueGrey)),
|
||||||
)
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
) : null
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
: null))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
)
|
)),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_showIncorrectPinDialog(BuildContext context) async {
|
void _showIncorrectPinDialog(BuildContext context) async {
|
||||||
await showDialog(
|
await showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
|
@ -186,8 +183,7 @@ class EnterPinCodeState extends State<EnterPinCode>{
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _push(int num) {
|
void _push(int num) {
|
||||||
|
@ -202,20 +198,16 @@ class EnterPinCodeState extends State<EnterPinCode>{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_pinLength() == pinLength) {
|
final currentPinLength = _pinLength();
|
||||||
|
|
||||||
if (listEquals<int>(pin, currentPin)){
|
|
||||||
|
|
||||||
|
if (currentPinLength == pinLength) {
|
||||||
|
if (listEquals<int>(pin, currentPin)) {
|
||||||
Navigator.pop(context, true);
|
Navigator.pop(context, true);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
Navigator.pop(context, false);
|
Navigator.pop(context, false);
|
||||||
|
|
||||||
_showIncorrectPinDialog(context);
|
_showIncorrectPinDialog(context);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,5 +233,4 @@ class EnterPinCodeState extends State<EnterPinCode>{
|
||||||
return v;
|
return v;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -2,6 +2,15 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:cake_wallet/src/screens/settings/attributes.dart';
|
import 'package:cake_wallet/src/screens/settings/attributes.dart';
|
||||||
|
|
||||||
class SettingsItem {
|
class SettingsItem {
|
||||||
|
SettingsItem(
|
||||||
|
{this.onTaped,
|
||||||
|
this.title,
|
||||||
|
this.link,
|
||||||
|
this.image,
|
||||||
|
this.widget,
|
||||||
|
this.attribute,
|
||||||
|
this.widgetBuilder});
|
||||||
|
|
||||||
final VoidCallback onTaped;
|
final VoidCallback onTaped;
|
||||||
final String title;
|
final String title;
|
||||||
final String link;
|
final String link;
|
||||||
|
@ -9,12 +18,4 @@ class SettingsItem {
|
||||||
final Widget widget;
|
final Widget widget;
|
||||||
final Attributes attribute;
|
final Attributes attribute;
|
||||||
final WidgetBuilder widgetBuilder;
|
final WidgetBuilder widgetBuilder;
|
||||||
|
|
||||||
SettingsItem({this.onTaped,
|
|
||||||
this.title,
|
|
||||||
this.link,
|
|
||||||
this.image,
|
|
||||||
this.widget,
|
|
||||||
this.attribute,
|
|
||||||
this.widgetBuilder});
|
|
||||||
}
|
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue