Fixed issues for linter and analyzer

M committed Jan 8, 2020 at 14:26 UTC 78ec11de47808b62fd15e15507cbc611a2d201c9
168 files changed +2262 -1959
analysis_options.yaml
+3 -10
@@ -5,17 +5,14 @@ analyzer:
5 implicit-casts: false
6 implicit-dynamic: false
7 exclude:
8 - - **/*.yaml
9 - - build/**
10 - - **/*.g.dart
11 - - lib/generated/*.dart
8 + - "build/**"
9 + - "**/*.g.dart"
10 + - "lib/generated/*.dart"
11
12 linter:
13 rules:
14 - always_declare_return_types
16 - - always_specify_types
15 - annotate_overrides
18 - - avoid_as
16 - avoid_empty_else
17 - avoid_init_to_null
18 - avoid_return_types_on_setters
@@ -48,17 +45,13 @@ linter:
45 - prefer_final_fields
46 - prefer_final_locals
47 - prefer_is_not_empty
51 - - public_member_api_docs
48 - slash_for_doc_comments
49 - sort_constructors_first
50 - sort_unnamed_constructors_first
55 - - super_goes_last
51 - test_types_in_equals
52 - throw_in_finally
58 - - type_annotate_public_apis
53 - type_init_formals
54 - unawaited_futures
61 - - unnecessary_brace_in_string_interp
55 - unnecessary_getters_setters
56 - unrelated_type_equality_checks
57 - valid_regexps
\ No newline at end of file
cw_monero/lib/account_list.dart
+14 -9
@@ -26,7 +26,7 @@ final accountSetLabelNative = moneroApi
26 .lookup<NativeFunction<account_set_label>>('account_set_label_row')
27 .asFunction<AccountSetLabel>();
28
29 -refreshAccounts() => accountRefreshNative();
29 +void refreshAccounts() => accountRefreshNative();
30
31 List<AccountRow> getAllAccount() {
32 final size = accountSizeNative();
@@ -38,24 +38,29 @@ List<AccountRow> getAllAccount() {
38 .toList();
39 }
40
41 -addAccountSync({String label}) {
41 +void addAccountSync({String label}) {
42 final labelPointer = Utf8.toUtf8(label);
43 accountAddNewNative(labelPointer);
44 free(labelPointer);
45 }
46
47 -setLabelForAccountSync({int accountIndex, String label}) {
47 +void setLabelForAccountSync({int accountIndex, String label}) {
48 final labelPointer = Utf8.toUtf8(label);
49 accountSetLabelNative(accountIndex, labelPointer);
50 free(labelPointer);
51 }
52
53 -_addAccount(String label) => addAccountSync(label: label);
53 +void _addAccount(String label) => addAccountSync(label: label);
54
55 -_setLabelForAccount(Map args) => setLabelForAccountSync(
56 - label: args['label'], accountIndex: args['accountIndex']);
55 +void _setLabelForAccount(Map<String, dynamic> args) {
56 + final label = args['label'] as String;
57 + final accountIndex = args['accountIndex'] as int;
58
58 -Future addAccount({String label}) async => compute(_addAccount, label);
59 + setLabelForAccountSync(label: label, accountIndex: accountIndex);
60 +}
61 +
62 +Future<void> addAccount({String label}) async => compute(_addAccount, label);
63
60 -Future setLabelForAccount({int accountIndex, String label}) async => compute(
61 - _setLabelForAccount, {'accountIndex': accountIndex, 'label': label});
64 +Future<void> setLabelForAccount({int accountIndex, String label}) async =>
65 + compute(
66 + _setLabelForAccount, {'accountIndex': accountIndex, 'label': label});
cw_monero/lib/exceptions/connection_to_node_exception.dart
+2 -2
@@ -1,5 +1,5 @@
1 class ConnectionToNodeException implements Exception {
2 - final String message;
3 -
2 ConnectionToNodeException({this.message});
3 +
4 + final String message;
5 }
\ No newline at end of file
cw_monero/lib/exceptions/creation_transaction_exception.dart
+2 -2
@@ -1,7 +1,7 @@
1 class CreationTransactionException implements Exception {
2 - final String message;
3 -
2 CreationTransactionException({this.message});
3 +
4 + final String message;
5
6 @override
7 String toString() => message;
cw_monero/lib/exceptions/setup_wallet_exception.dart
+2 -2
@@ -1,5 +1,5 @@
1 class SetupWalletException implements Exception {
2 - final String message;
3 -
2 SetupWalletException({this.message});
3 +
4 + final String message;
5 }
\ No newline at end of file
cw_monero/lib/exceptions/wallet_creation_exception.dart
+2 -2
@@ -1,5 +1,5 @@
1 class WalletCreationException implements Exception {
2 - final String message;
3 -
2 WalletCreationException({this.message});
3 +
4 + final String message;
5 }
\ No newline at end of file
cw_monero/lib/exceptions/wallet_restore_from_keys_exception.dart
+2 -2
@@ -1,5 +1,5 @@
1 class WalletRestoreFromKeysException implements Exception {
2 - final String message;
3 -
2 WalletRestoreFromKeysException({this.message});
3 +
4 + final String message;
5 }
\ No newline at end of file
cw_monero/lib/exceptions/wallet_restore_from_seed_exception.dart
+2 -2
@@ -1,5 +1,5 @@
1 class WalletRestoreFromSeedException implements Exception {
2 - final String message;
3 -
2 WalletRestoreFromSeedException({this.message});
3 +
4 + final String message;
5 }
\ No newline at end of file
cw_monero/lib/structs/pending_transaction.dart
+2 -2
@@ -14,10 +14,10 @@ class PendingTransactionRaw extends Struct {
14 }
15
16 class PendingTransactionDescription {
17 + PendingTransactionDescription({this.amount, this.fee, this.hash, this.pointerAddress});
18 +
19 final int amount;
20 final int fee;
21 final String hash;
22 final int pointerAddress;
21 -
22 - PendingTransactionDescription({this.amount, this.fee, this.hash, this.pointerAddress});
23 }
\ No newline at end of file
cw_monero/lib/subaddress_list.dart
+20 -10
@@ -26,7 +26,7 @@ final subaddrressSetLabelNative = moneroApi
26 .lookup<NativeFunction<subaddress_set_label>>('subaddress_set_label')
27 .asFunction<SubaddressSetLabel>();
28
29 -refreshSubaddresses({int accountIndex}) =>
29 +void refreshSubaddresses({int accountIndex}) =>
30 subaddressRefreshNative(accountIndex);
31
32 List<SubaddressRow> getAllSubaddresses() {
@@ -40,25 +40,35 @@ List<SubaddressRow> getAllSubaddresses() {
40 .toList();
41 }
42
43 -addSubaddressSync({int accountIndex, String label}) {
43 +void addSubaddressSync({int accountIndex, String label}) {
44 final labelPointer = Utf8.toUtf8(label);
45 subaddrressAddNewNative(accountIndex, labelPointer);
46 free(labelPointer);
47 }
48
49 -setLabelForSubaddressSync({int accountIndex, int addressIndex, String label}) {
49 +void setLabelForSubaddressSync(
50 + {int accountIndex, int addressIndex, String label}) {
51 final labelPointer = Utf8.toUtf8(label);
52 +
53 subaddrressSetLabelNative(accountIndex, addressIndex, labelPointer);
54 free(labelPointer);
55 }
56
55 -_addSubaddress(Map args) =>
56 - addSubaddressSync(accountIndex: args['accountIndex'], label: args['label']);
57 +void _addSubaddress(Map<String, dynamic> args) {
58 + final label = args['label'] as String;
59 + final accountIndex = args['accountIndex'] as int;
60
58 -_setLabelForSubaddress(Map args) => setLabelForSubaddressSync(
59 - accountIndex: args['accountIndex'],
60 - addressIndex: args['addressIndex'],
61 - label: args['label']);
61 + addSubaddressSync(accountIndex: accountIndex, label: label);
62 +}
63 +
64 +void _setLabelForSubaddress(Map<String, dynamic> args) {
65 + final label = args['label'] as String;
66 + final accountIndex = args['accountIndex'] as int;
67 + final addressIndex = args['addressIndex'] as int;
68 +
69 + setLabelForSubaddressSync(
70 + accountIndex: accountIndex, addressIndex: addressIndex, label: label);
71 +}
72
73 Future addSubaddress({int accountIndex, String label}) async =>
74 compute(_addSubaddress, {'accountIndex': accountIndex, 'label': label});
@@ -69,4 +79,4 @@ Future setLabelForSubaddress(
79 'accountIndex': accountIndex,
80 'addressIndex': addressIndex,
81 'label': label
72 - });
\ No newline at end of file
82 + });
cw_monero/lib/transaction_history.dart
+17 -10
@@ -29,7 +29,7 @@ final transactionCommitNative = moneroApi
29 .lookup<NativeFunction<transaction_commit>>('transaction_commit')
30 .asFunction<TransactionCommit>();
31
32 -refreshTransactions() => transactionsRefreshNative();
32 +void refreshTransactions() => transactionsRefreshNative();
33
34 int countOfTransactions() => transactionsCountNative();
35
@@ -84,10 +84,10 @@ PendingTransactionDescription createTransactionSync(
84 pointerAddress: pendingTransactionRawPointer.address);
85 }
86
87 -commitTransactionFromPointerAddress({int address}) => commitTransaction(
87 +void commitTransactionFromPointerAddress({int address}) => commitTransaction(
88 transactionPointer: Pointer<PendingTransactionRaw>.fromAddress(address));
89
90 -commitTransaction({Pointer<PendingTransactionRaw> transactionPointer}) {
90 +void commitTransaction({Pointer<PendingTransactionRaw> transactionPointer}) {
91 final errorMessagePointer = allocate<Utf8Box>();
92 final isCommited =
93 transactionCommitNative(transactionPointer, errorMessagePointer) != 0;
@@ -99,13 +99,20 @@ commitTransaction({Pointer<PendingTransactionRaw> transactionPointer}) {
99 }
100 }
101
102 -PendingTransactionDescription _createTransactionSync(Map args) =>
103 - createTransactionSync(
104 - address: args['address'],
105 - paymentId: args['paymentId'],
106 - amount: args['amount'],
107 - priorityRaw: args['priorityRaw'],
108 - accountIndex: args['accountIndex']);
102 +PendingTransactionDescription _createTransactionSync(Map args) {
103 + final address = args['address'] as String;
104 + final paymentId = args['paymentId'] as String;
105 + final amount = args['amount'] as String;
106 + final priorityRaw = args['priorityRaw'] as int;
107 + final accountIndex = args['accountIndex'] as int;
108 +
109 + return createTransactionSync(
110 + address: address,
111 + paymentId: paymentId,
112 + amount: amount,
113 + priorityRaw: priorityRaw,
114 + accountIndex: accountIndex);
115 +}
116
117 Future<PendingTransactionDescription> createTransaction(
118 {String address,
cw_monero/lib/wallet.dart
+31 -20
@@ -179,23 +179,23 @@ bool setupNodeSync(
179 return isSetupNode;
180 }
181
182 -startRefreshSync() => startRefreshNative();
182 +void startRefreshSync() => startRefreshNative();
183
184 Future<bool> connectToNode() async => connecToNodeNative() != 0;
185
186 -setRefreshFromBlockHeight({int height}) =>
186 +void setRefreshFromBlockHeight({int height}) =>
187 setRefreshFromBlockHeightNative(height);
188
189 -setRecoveringFromSeed({bool isRecovery}) =>
189 +void setRecoveringFromSeed({bool isRecovery}) =>
190 setRecoveringFromSeedNative(_boolToInt(isRecovery));
191
192 -storeSync() {
192 +void storeSync() {
193 final pathPointer = Utf8.toUtf8('');
194 storeNative(pathPointer);
195 free(pathPointer);
196 }
197
198 -closeCurrentWallet() => closeCurrentWalletNative();
198 +void closeCurrentWallet() => closeCurrentWalletNative();
199
200 String getSecretViewKey() =>
201 convertUTF8ToString(pointer: getSecretViewKeyNative());
@@ -213,8 +213,8 @@ Timer _updateSyncInfoTimer;
213
214 int _lastKnownBlockHeight = 0;
215
216 -setListeners(Future Function(int) onNewBlock, Future Function() onNeedToRefresh,
217 - Future Function() onNewTransaction) {
216 +void setListeners(Future Function(int) onNewBlock,
217 + Future Function() onNeedToRefresh, Future Function() onNewTransaction) {
218 if (_updateSyncInfoTimer != null) {
219 _updateSyncInfoTimer.cancel();
220 }
@@ -240,25 +240,36 @@ setListeners(Future Function(int) onNewBlock, Future Function() onNeedToRefresh,
240 setListenerNative();
241 }
242
243 -closeListeners() {
243 +void closeListeners() {
244 if (_updateSyncInfoTimer != null) {
245 _updateSyncInfoTimer.cancel();
246 }
247 }
248
249 -onStartup() => onStartupNative();
249 +void onStartup() => onStartupNative();
250
251 -_storeSync(_) => storeSync();
252 -bool _setupNodeSync(Map args) => setupNodeSync(
253 - address: args['address'],
254 - login: args['login'] ?? '',
255 - password: args['password'] ?? '',
256 - useSSL: args['useSSL'],
257 - isLightWallet: args['isLightWallet']);
258 -bool _isConnected(_) => isConnectedSync();
259 -int _getNodeHeight(_) => getNodeHeightSync();
251 +void _storeSync(Object _) => storeSync();
252
261 -startRefresh() => startRefreshSync();
253 +bool _setupNodeSync(Map args) {
254 + final address = args['address'] as String;
255 + final login = (args['login'] ?? '') as String;
256 + final password = (args['password'] ?? '') as String;
257 + final useSSL = args['useSSL'] as bool;
258 + final isLightWallet = args['isLightWallet'] as bool;
259 +
260 + return setupNodeSync(
261 + address: address,
262 + login: login,
263 + password: password,
264 + useSSL: useSSL,
265 + isLightWallet: isLightWallet);
266 +}
267 +
268 +bool _isConnected(Object _) => isConnectedSync();
269 +
270 +int _getNodeHeight(Object _) => getNodeHeightSync();
271 +
272 +void startRefresh() => startRefreshSync();
273
274 Future setupNode(
275 {String address,
@@ -280,4 +291,4 @@ Future<bool> isConnected() => compute(_isConnected, 0);
291
292 Future<int> getNodeHeight() => compute(_getNodeHeight, 0);
293
283 -rescanBlockchainAsync() => rescanBlockchainAsyncNative();
\ No newline at end of file
294 +void rescanBlockchainAsync() => rescanBlockchainAsyncNative();
cw_monero/lib/wallet_manager.dart
+41 -23
@@ -31,7 +31,7 @@ final loadWalletNative = moneroApi
31 .lookup<NativeFunction<load_wallet>>('load_wallet')
32 .asFunction<LoadWallet>();
33
34 -createWalletSync(
34 +void createWalletSync(
35 {String path,
36 String password,
37 String language = 'English',
@@ -63,7 +63,7 @@ bool isWalletExistSync({String path}) {
63 return isExist;
64 }
65
66 -restoreWalletFromSeedSync(
66 +void restoreWalletFromSeedSync(
67 {String path,
68 String password,
69 String seed,
@@ -92,7 +92,7 @@ restoreWalletFromSeedSync(
92 }
93 }
94
95 -restoreWalletFromKeysSync(
95 +void restoreWalletFromKeysSync(
96 {String path,
97 String password,
98 String language = 'English',
@@ -133,7 +133,7 @@ restoreWalletFromKeysSync(
133 }
134 }
135
136 -loadWallet({String path, String password, int nettype = 0}) {
136 +void loadWallet({String path, String password, int nettype = 0}) {
137 final pathPointer = Utf8.toUtf8(path);
138 final passwordPointer = Utf8.toUtf8(password);
139
@@ -142,34 +142,52 @@ loadWallet({String path, String password, int nettype = 0}) {
142 free(passwordPointer);
143 }
144
145 -_createWallet(args) =>
146 - createWalletSync(path: args['path'], password: args['password']);
145 +void _createWallet(Map<String, dynamic> args) {
146 + final path = args['path'] as String;
147 + final password = args['password'] as String;
148
148 -_restoreFromSeed(args) => restoreWalletFromSeedSync(
149 - path: args['path'],
150 - password: args['password'],
151 - seed: args['seed'],
152 - restoreHeight: args['restoreHeight']);
149 + createWalletSync(path: path, password: password);
150 +}
151 +
152 +void _restoreFromSeed(Map<String, dynamic> args) {
153 + final path = args['path'] as String;
154 + final password = args['password'] as String;
155 + final seed = args['seed'] as String;
156 + final restoreHeight = args['restoreHeight'] as int;
157
154 -_restoreFromKeys(args) => restoreWalletFromKeysSync(
155 - path: args['path'],
156 - password: args['password'],
157 - restoreHeight: args['restoreHeight'],
158 - address: args['address'],
159 - viewKey: args['viewKey'],
160 - spendKey: args['spendKey']);
158 + restoreWalletFromSeedSync(
159 + path: path, password: password, seed: seed, restoreHeight: restoreHeight);
160 +}
161 +
162 +void _restoreFromKeys(Map<String, dynamic> args) {
163 + final path = args['path'] as String;
164 + final password = args['password'] as String;
165 + final restoreHeight = args['restoreHeight'] as int;
166 + final address = args['address'] as String;
167 + final viewKey = args['viewKey'] as String;
168 + final spendKey = args['spendKey'] as String;
169 +
170 + restoreWalletFromKeysSync(
171 + path: path,
172 + password: password,
173 + restoreHeight: restoreHeight,
174 + address: address,
175 + viewKey: viewKey,
176 + spendKey: spendKey);
177 +}
178
162 -_openWallet(Map args) async =>
179 +Future<void> _openWallet(Map<String, String> args) async =>
180 loadWallet(path: args['path'], password: args['password']);
181
182 bool _isWalletExist(String path) => isWalletExistSync(path: path);
183
167 -openWallet({String path, String password, int nettype = 0}) async =>
184 +void openWallet({String path, String password, int nettype = 0}) async =>
185 loadWallet(path: path, password: password);
186
170 -Future openWalletAsync(Map args) async => compute(_openWallet, args);
187 +Future<void> openWalletAsync(Map<String, String> args) async =>
188 + compute(_openWallet, args);
189
172 -Future createWallet(
190 +Future<void> createWallet(
191 {String path,
192 String password,
193 String language = 'English',
@@ -215,4 +233,4 @@ Future restoreFromKeys(
233 'restoreHeight': restoreHeight
234 });
235
218 -Future<bool> isWalletExist({String path}) => compute(_isWalletExist, path);
\ No newline at end of file
236 +Future<bool> isWalletExist({String path}) => compute(_isWalletExist, path);
lib/main.dart
+13 -11
@@ -6,7 +6,7 @@ import 'package:provider/provider.dart';
6 import 'package:flutter/material.dart';
7 import 'package:flutter/services.dart';
8 import 'package:hive/hive.dart';
9 -import 'package:cw_monero/wallet.dart' as moneroWallet;
9 +import 'package:cw_monero/wallet.dart' as monero_wallet;
10 import 'package:cake_wallet/router.dart';
11 import 'theme_changer.dart';
12 import 'themes.dart';
@@ -39,7 +39,7 @@ import 'package:cake_wallet/src/domain/common/language.dart';
39 void main() async {
40 WidgetsFlutterBinding.ensureInitialized();
41
42 - var appDir = await getApplicationDocumentsDirectory();
42 + final appDir = await getApplicationDocumentsDirectory();
43 Hive.init(appDir.path);
44 Hive.registerAdapter(ContactAdapter(), 0);
45 Hive.registerAdapter(NodeAdapter(), 1);
@@ -50,18 +50,20 @@ void main() async {
50
51 final secureStorage = FlutterSecureStorage();
52 final transactionDescriptionsBoxKey = await getEncryptionKey(
53 - secureStorage: secureStorage, forKey: 'transactionDescriptionsBoxKey'); // FIXME: Unnamed constant
53 + secureStorage: secureStorage,
54 + forKey: 'transactionDescriptionsBoxKey'); // FIXME: Unnamed constant
55 final tradesBoxKey = await getEncryptionKey(
55 - secureStorage: secureStorage, forKey: 'tradesBoxKey'); // FIXME: Unnamed constant
56 + secureStorage: secureStorage,
57 + forKey: 'tradesBoxKey'); // FIXME: Unnamed constant
58
57 - var contacts = await Hive.openBox<Contact>(Contact.boxName);
58 - var nodes = await Hive.openBox<Node>(Node.boxName);
59 - var transactionDescriptions = await Hive.openBox<TransactionDescription>(
59 + final contacts = await Hive.openBox<Contact>(Contact.boxName);
60 + final nodes = await Hive.openBox<Node>(Node.boxName);
61 + final transactionDescriptions = await Hive.openBox<TransactionDescription>(
62 TransactionDescription.boxName,
63 encryptionKey: transactionDescriptionsBoxKey);
62 - var trades =
64 + final trades =
65 await Hive.openBox<Trade>(Trade.boxName, encryptionKey: tradesBoxKey);
64 - var walletInfoSource = await Hive.openBox<WalletInfo>(WalletInfo.boxName);
66 + final walletInfoSource = await Hive.openBox<WalletInfo>(WalletInfo.boxName);
67
68 final sharedPreferences = await SharedPreferences.getInstance();
69 final walletService = WalletService();
@@ -124,7 +126,7 @@ void main() async {
126 ], child: CakeWalletApp()));
127 }
128
127 -initialSetup(
129 +Future<void> initialSetup(
130 {WalletListService walletListService,
131 SharedPreferences sharedPreferences,
132 Box<Node> nodes,
@@ -137,7 +139,7 @@ initialSetup(
139 sharedPreferences: sharedPreferences,
140 nodes: nodes);
141 await authStore.started();
140 - moneroWallet.onStartup();
142 + monero_wallet.onStartup();
143 }
144
145 class CakeWalletApp extends StatelessWidget {
lib/router.dart
+64 -53
@@ -19,6 +19,10 @@ import 'package:cake_wallet/src/domain/exchange/xmrto/xmrto_exchange_provider.da
19 import 'package:cake_wallet/src/domain/common/node.dart';
20 import 'package:cake_wallet/src/domain/monero/transaction_description.dart';
21 import 'package:cake_wallet/src/domain/exchange/trade.dart';
22 +import 'package:cake_wallet/src/domain/monero/account.dart';
23 +import 'package:cake_wallet/src/domain/common/mnemotic_item.dart';
24 +import 'package:cake_wallet/src/domain/common/transaction_info.dart';
25 +import 'package:cake_wallet/src/domain/monero/subaddress.dart';
26
27 // MARK: Import stores
28
@@ -101,10 +105,10 @@ class Router {
105 Box<Trade> trades}) {
106 switch (settings.name) {
107 case Routes.welcome:
104 - return MaterialPageRoute(builder: (_) => createWelcomePage());
108 + return MaterialPageRoute<void>(builder: (_) => createWelcomePage());
109
110 case Routes.newWalletFromWelcome:
107 - return CupertinoPageRoute(
111 + return CupertinoPageRoute<void>(
112 builder: (_) => Provider(
113 create: (_) => UserStore(
114 accountService: UserService(
@@ -115,7 +119,7 @@ class Router {
119 Navigator.pushNamed(context, Routes.newWallet))));
120
121 case Routes.newWallet:
118 - return CupertinoPageRoute(
122 + return CupertinoPageRoute<void>(
123 builder:
124 (_) =>
125 ProxyProvider<AuthenticationStore, WalletCreationStore>(
@@ -132,10 +136,10 @@ class Router {
136 Function(BuildContext, String) callback;
137
138 if (settings.arguments is Function(BuildContext, String)) {
135 - callback = settings.arguments;
139 + callback = settings.arguments as Function(BuildContext, String);
140 }
141
138 - return CupertinoPageRoute(
142 + return CupertinoPageRoute<void>(
143 builder: (_) => Provider(
144 create: (_) => UserStore(
145 accountService: UserService(
@@ -147,13 +151,14 @@ class Router {
151 fullscreenDialog: true);
152
153 case Routes.restoreOptions:
150 - return CupertinoPageRoute(builder: (_) => RestoreOptionsPage());
154 + return CupertinoPageRoute<void>(builder: (_) => RestoreOptionsPage());
155
156 case Routes.restoreWalletOptions:
153 - return CupertinoPageRoute(builder: (_) => RestoreWalletOptionsPage());
157 + return CupertinoPageRoute<void>(
158 + builder: (_) => RestoreWalletOptionsPage());
159
160 case Routes.restoreWalletOptionsFromWelcome:
156 - return CupertinoPageRoute(
161 + return CupertinoPageRoute<void>(
162 builder: (_) => Provider(
163 create: (_) => UserStore(
164 accountService: UserService(
@@ -164,14 +169,14 @@ class Router {
169 context, Routes.restoreWalletOptions))));
170
171 case Routes.seed:
167 - return MaterialPageRoute(
172 + return MaterialPageRoute<void>(
173 builder: (_) => createSeedPage(
174 settingsStore: settingsStore,
175 walletService: walletService,
171 - callback: settings.arguments));
176 + callback: settings.arguments as void Function()));
177
178 case Routes.restoreWalletFromSeed:
174 - return CupertinoPageRoute(
179 + return CupertinoPageRoute<void>(
180 builder: (_) =>
181 ProxyProvider<AuthenticationStore, WalletRestorationStore>(
182 update: (_, authStore, __) => WalletRestorationStore(
@@ -184,7 +189,7 @@ class Router {
189 sharedPreferences: sharedPreferences)));
190
191 case Routes.restoreWalletFromKeys:
187 - return CupertinoPageRoute(
192 + return CupertinoPageRoute<void>(
193 builder: (_) =>
194 ProxyProvider<AuthenticationStore, WalletRestorationStore>(
195 update: (_, authStore, __) => WalletRestorationStore(
@@ -197,7 +202,7 @@ class Router {
202 sharedPreferences: sharedPreferences)));
203
204 case Routes.dashboard:
200 - return CupertinoPageRoute(
205 + return CupertinoPageRoute<void>(
206 builder: (_) => createDashboardPage(
207 walletService: walletService,
208 priceStore: priceStore,
@@ -207,7 +212,7 @@ class Router {
212 walletStore: walletStore));
213
214 case Routes.send:
210 - return CupertinoPageRoute(
215 + return CupertinoPageRoute<void>(
216 fullscreenDialog: true,
217 builder: (_) => MultiProvider(providers: [
218 ProxyProvider<SettingsStore, BalanceStore>(
@@ -227,7 +232,7 @@ class Router {
232 ], child: SendPage()));
233
234 case Routes.receive:
230 - return CupertinoPageRoute(
235 + return CupertinoPageRoute<void>(
236 fullscreenDialog: true,
237 builder: (_) => MultiProvider(providers: [
238 Provider(
@@ -236,30 +241,30 @@ class Router {
241 ], child: ReceivePage()));
242
243 case Routes.transactionDetails:
239 - return CupertinoPageRoute(
244 + return CupertinoPageRoute<void>(
245 fullscreenDialog: true,
241 - builder: (_) =>
242 - TransactionDetailsPage(transactionInfo: settings.arguments));
246 + builder: (_) => TransactionDetailsPage(
247 + transactionInfo: settings.arguments as TransactionInfo));
248
249 case Routes.newSubaddress:
245 - return CupertinoPageRoute(
250 + return CupertinoPageRoute<void>(
251 builder: (_) => Provider(
252 create: (_) =>
253 SubadrressCreationStore(walletService: walletService),
254 child: NewSubaddressPage()));
255
256 case Routes.disclaimer:
252 - return CupertinoPageRoute(builder: (_) => DisclaimerPage());
257 + return CupertinoPageRoute<void>(builder: (_) => DisclaimerPage());
258
259 case Routes.readDisclaimer:
255 - return CupertinoPageRoute(
260 + return CupertinoPageRoute<void>(
261 builder: (_) => DisclaimerPage(isReadOnly: true));
262
263 case Routes.seedAlert:
259 - return CupertinoPageRoute(builder: (_) => SeedAlert());
264 + return CupertinoPageRoute<void>(builder: (_) => SeedAlert());
265
266 case Routes.walletList:
262 - return MaterialPageRoute(
267 + return MaterialPageRoute<void>(
268 fullscreenDialog: true,
269 builder: (_) => Provider(
270 create: (_) => WalletListStore(
@@ -268,40 +273,43 @@ class Router {
273 child: WalletListPage()));
274
275 case Routes.auth:
271 - return MaterialPageRoute(
276 + return MaterialPageRoute<void>(
277 fullscreenDialog: true,
278 builder: (_) => Provider(
279 create: (_) => AuthStore(
280 sharedPreferences: sharedPreferences,
281 userService: userService,
282 walletService: walletService),
278 - child: AuthPage(onAuthenticationFinished: settings.arguments),
283 + child: AuthPage(
284 + onAuthenticationFinished:
285 + settings.arguments as OnAuthenticationFinished),
286 ));
287
288 case Routes.unlock:
282 - return MaterialPageRoute(
289 + return MaterialPageRoute<void>(
290 fullscreenDialog: true,
291 builder: (_) => createUnlockPage(
292 sharedPreferences: sharedPreferences,
293 userService: userService,
294 walletService: walletService,
288 - onAuthenticationFinished: settings.arguments));
295 + onAuthenticationFinished:
296 + settings.arguments as OnAuthenticationFinished));
297
298 case Routes.nodeList:
291 - return CupertinoPageRoute(builder: (context) {
299 + return CupertinoPageRoute<void>(builder: (context) {
300 return Provider(
301 create: (_) => NodeListStore(nodesSource: nodes),
302 child: NodeListPage());
303 });
304
305 case Routes.newNode:
298 - return CupertinoPageRoute(
306 + return CupertinoPageRoute<void>(
307 builder: (_) => Provider<NodeListStore>(
308 create: (_) => NodeListStore(nodesSource: nodes),
309 child: NewNodePage()));
310
311 case Routes.login:
304 - return CupertinoPageRoute(builder: (context) {
312 + return CupertinoPageRoute<void>(builder: (context) {
313 final authenticationStore = Provider.of<AuthenticationStore>(context);
314
315 return createLoginPage(
@@ -313,7 +321,7 @@ class Router {
321 });
322
323 case Routes.accountList:
316 - return MaterialPageRoute(
324 + return MaterialPageRoute<void>(
325 builder: (context) {
326 return MultiProvider(providers: [
327 Provider(
@@ -324,14 +332,14 @@ class Router {
332 fullscreenDialog: true);
333
334 case Routes.accountCreation:
327 - return CupertinoPageRoute(builder: (context) {
335 + return CupertinoPageRoute<String>(builder: (context) {
336 return Provider(
337 create: (_) => AccountListStore(walletService: walletService),
330 - child: AccountPage(account: settings.arguments));
338 + child: AccountPage(account: settings.arguments as Account));
339 });
340
341 case Routes.addressBook:
334 - return MaterialPageRoute(builder: (context) {
342 + return MaterialPageRoute<void>(builder: (context) {
343 return MultiProvider(
344 providers: [
345 Provider(
@@ -344,7 +352,7 @@ class Router {
352 });
353
354 case Routes.pickerAddressBook:
347 - return MaterialPageRoute(builder: (context) {
355 + return MaterialPageRoute<void>(builder: (context) {
356 return MultiProvider(
357 providers: [
358 Provider(
@@ -357,7 +365,7 @@ class Router {
365 });
366
367 case Routes.addressBookAddContact:
360 - return CupertinoPageRoute(builder: (context) {
368 + return CupertinoPageRoute<void>(builder: (context) {
369 return MultiProvider(
370 providers: [
371 Provider(
@@ -365,12 +373,12 @@ class Router {
373 AccountListStore(walletService: walletService)),
374 Provider(create: (_) => AddressBookStore(contacts: contacts))
375 ],
368 - child: ContactPage(contact: settings.arguments),
376 + child: ContactPage(contact: settings.arguments as Contact),
377 );
378 });
379
380 case Routes.showKeys:
373 - return MaterialPageRoute(
381 + return MaterialPageRoute<void>(
382 builder: (context) {
383 return Provider(
384 create: (_) => WalletKeysStore(walletService: walletService),
@@ -380,12 +388,13 @@ class Router {
388 fullscreenDialog: true);
389
390 case Routes.exchangeTrade:
383 - return CupertinoPageRoute(
391 + return CupertinoPageRoute<void>(
392 builder: (_) => MultiProvider(
393 providers: [
394 ProxyProvider<SettingsStore, ExchangeTradeStore>(
395 update: (_, settingsStore, __) => ExchangeTradeStore(
388 - trade: settings.arguments, walletStore: walletStore),
396 + trade: settings.arguments as Trade,
397 + walletStore: walletStore),
398 ),
399 ProxyProvider<SettingsStore, SendStore>(
400 update: (_, settingsStore, __) => SendStore(
@@ -398,21 +407,22 @@ class Router {
407 ));
408
409 case Routes.exchangeConfirm:
401 - return MaterialPageRoute(
402 - builder: (_) => ExchangeConfirmPage(trade: settings.arguments));
410 + return MaterialPageRoute<void>(
411 + builder: (_) =>
412 + ExchangeConfirmPage(trade: settings.arguments as Trade));
413
414 case Routes.tradeDetails:
405 - return MaterialPageRoute(builder: (context) {
415 + return MaterialPageRoute<void>(builder: (context) {
416 return MultiProvider(providers: [
417 ProxyProvider<SettingsStore, ExchangeTradeStore>(
418 update: (_, settingsStore, __) => ExchangeTradeStore(
409 - trade: settings.arguments, walletStore: walletStore),
419 + trade: settings.arguments as Trade, walletStore: walletStore),
420 )
421 ], child: TradeDetailsPage());
422 });
423
424 case Routes.subaddressList:
415 - return MaterialPageRoute(
425 + return MaterialPageRoute<Subaddress>(
426 builder: (_) => MultiProvider(providers: [
427 Provider(
428 create: (_) =>
@@ -420,17 +430,18 @@ class Router {
430 ], child: SubaddressListPage()));
431
432 case Routes.restoreWalletFromSeedDetails:
423 - return CupertinoPageRoute(
433 + return CupertinoPageRoute<void>(
434 builder: (_) =>
435 ProxyProvider<AuthenticationStore, WalletRestorationStore>(
436 update: (_, authStore, __) => WalletRestorationStore(
437 authStore: authStore,
438 sharedPreferences: sharedPreferences,
439 walletListService: walletListService,
430 - seed: settings.arguments),
440 + seed: settings.arguments as List<MnemoticItem>),
441 child: RestoreWalletFromSeedDetailsPage()));
442 +
443 case Routes.exchange:
433 - return MaterialPageRoute(
444 + return MaterialPageRoute<void>(
445 builder: (_) => MultiProvider(providers: [
446 Provider(create: (_) {
447 final xmrtoprovider = XMRTOExchangeProvider();
@@ -449,25 +460,25 @@ class Router {
460 ], child: ExchangePage()));
461
462 case Routes.settings:
452 - return MaterialPageRoute(
463 + return MaterialPageRoute<void>(
464 builder: (_) => Provider(
465 create: (_) => NodeListStore(nodesSource: nodes),
466 child: SettingsPage()));
467
468 case Routes.rescan:
458 - return MaterialPageRoute(
469 + return MaterialPageRoute<void>(
470 builder: (_) => Provider(
471 create: (_) => RescanWalletStore(walletService: walletService),
472 child: RescanPage()));
473
474 case Routes.faq:
464 - return MaterialPageRoute(builder: (_) => FaqPage());
475 + return MaterialPageRoute<void>(builder: (_) => FaqPage());
476
477 case Routes.changeLanguage:
467 - return MaterialPageRoute(builder: (_) => ChangeLanguage());
478 + return MaterialPageRoute<void>(builder: (_) => ChangeLanguage());
479
480 default:
470 - return MaterialPageRoute(
481 + return MaterialPageRoute<void>(
482 builder: (_) => Scaffold(
483 body: Center(
484 child: Text(S.current.router_no_route(settings.name))),
lib/src/domain/common/balance_display_mode.dart
+3 -3
@@ -3,6 +3,9 @@ import 'package:cake_wallet/generated/i18n.dart';
3 import 'package:cake_wallet/src/domain/common/enumerable_item.dart';
4
5 class BalanceDisplayMode extends EnumerableItem<int> with Serializable<int> {
6 + const BalanceDisplayMode({@required String title, @required int raw})
7 + : super(title: title, raw: raw);
8 +
9 static const all = [
10 BalanceDisplayMode.fullBalance,
11 BalanceDisplayMode.availableBalance,
@@ -27,9 +30,6 @@ class BalanceDisplayMode extends EnumerableItem<int> with Serializable<int> {
30 }
31 }
32
30 - const BalanceDisplayMode({@required String title, @required int raw})
31 - : super(title: title, raw: raw);
32 -
33 @override
34 String toString() {
35 switch (this) {
lib/src/domain/common/contact.dart
+4 -7
@@ -6,6 +6,9 @@ part 'contact.g.dart';
6
7 @HiveType()
8 class Contact extends HiveObject {
9 + Contact({@required this.name, @required this.address, CryptoCurrency type})
10 + : raw = type?.raw;
11 +
12 static const boxName = 'Contacts';
13
14 @HiveField(0)
@@ -19,12 +22,6 @@ class Contact extends HiveObject {
22
23 CryptoCurrency get type => CryptoCurrency.deserialize(raw: raw);
24
22 - Contact(
23 - {@required this.name,
24 - @required this.address,
25 - CryptoCurrency type})
26 - : raw = type?.raw;
27 -
28 - updateCryptoCurrency({@required CryptoCurrency currency}) =>
25 + void updateCryptoCurrency({@required CryptoCurrency currency}) =>
26 raw = currency.raw;
27 }
lib/src/domain/common/crypto_currency.dart
+3 -3
@@ -5,6 +5,9 @@ part 'crypto_currency.g.dart';
5
6 @HiveType()
7 class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
8 + const CryptoCurrency({final String title, final int raw})
9 + : super(title: title, raw: raw);
10 +
11 static const all = [
12 CryptoCurrency.xmr,
13 CryptoCurrency.btc,
@@ -58,9 +61,6 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> {
61 }
62 }
63
61 - const CryptoCurrency({final String title, final int raw})
62 - : super(title: title, raw: raw);
63 -
64 @override
65 String toString() => title;
66 }
lib/src/domain/common/default_settings_migration.dart
+8 -8
@@ -11,7 +11,7 @@ Future defaultSettingsMigration(
11 {@required int version,
12 @required SharedPreferences sharedPreferences,
13 @required Box<Node> nodes}) async {
14 - int currentVersion =
14 + final currentVersion =
15 sharedPreferences.getInt('current_default_settings_migration_version') ??
16 0;
17
@@ -22,17 +22,17 @@ Future defaultSettingsMigration(
22 try {
23 switch (version) {
24 case 1:
25 - sharedPreferences.setString(
25 + await sharedPreferences.setString(
26 'current_fiat_currency', FiatCurrency.usd.toString());
27 - sharedPreferences.setInt(
27 + await sharedPreferences.setInt(
28 'current_fee_priority', TransactionPriority.standart.raw);
29 - sharedPreferences.setInt('current_balance_display_mode',
29 + await sharedPreferences.setInt('current_balance_display_mode',
30 BalanceDisplayMode.availableBalance.raw);
31 - sharedPreferences.setInt(
31 + await sharedPreferences.setInt(
32 'current_default_settings_migration_version', 1);
33 - sharedPreferences.setBool('save_recipient_address', false);
33 + await sharedPreferences.setBool('save_recipient_address', false);
34 await resetToDefault(nodes);
35 - sharedPreferences.setInt('current_node_id', 0);
35 + await sharedPreferences.setInt('current_node_id', 0);
36 break;
37 default:
38 break;
@@ -41,6 +41,6 @@ Future defaultSettingsMigration(
41 print('Migration error: ${e.toString()}');
42 }
43
44 - sharedPreferences.setInt(
44 + await sharedPreferences.setInt(
45 'current_default_settings_migration_version', version);
46 }
lib/src/domain/common/digest_request.dart
+27 -33
@@ -1,5 +1,5 @@
1 import 'dart:convert';
2 -import 'package:dio/dio.dart' as Dio;
2 +import 'package:dio/dio.dart' as __dio;
3 import 'package:crypto/crypto.dart' as crypto;
4 import 'dart:math' as math;
5
@@ -8,13 +8,13 @@ class DigestRequest {
8
9 String generateCnonce() {
10 final rnd = math.Random.secure();
11 - var values = List<int>.generate(32, (i) => rnd.nextInt(256));
11 + final values = List<int>.generate(32, (i) => rnd.nextInt(256));
12 return base64Url.encode(values).substring(0, 8);
13 }
14
15 String generateHA1({String realm, String username, String password}) {
16 final ha1CredentialsData =
17 - Utf8Encoder().convert('$username:$realm:$password');
17 + Utf8Encoder().convert('$username:$realm:$password');
18 final ha1 = md5.convert(ha1CredentialsData).toString();
19
20 return ha1;
@@ -29,13 +29,13 @@ class DigestRequest {
29
30 String generateResponseString(
31 {String ha1,
32 - String ha2,
33 - String nonce,
34 - String nonceCount,
35 - String cnonce,
36 - String qop}) {
32 + String ha2,
33 + String nonce,
34 + String nonceCount,
35 + String cnonce,
36 + String qop}) {
37 final responseData =
38 - Utf8Encoder().convert('$ha1:$nonce:$nonceCount:$cnonce:$qop:$ha2');
38 + Utf8Encoder().convert('$ha1:$nonce:$nonceCount:$cnonce:$qop:$ha2');
39 final response = md5.convert(responseData).toString();
40
41 return response;
@@ -43,8 +43,8 @@ class DigestRequest {
43
44 Map<String, String> parsetAuthorizationHeader({String source}) {
45 final authHeaderParts =
46 - source.substring(7).split(',').map((item) => item.trim());
47 - var authenticate = Map<String, String>();
46 + source.substring(7).split(',').map((item) => item.trim());
47 + final authenticate = Map<String, String>();
48
49 for (final part in authHeaderParts) {
50 final kv = part.split('=');
@@ -55,30 +55,25 @@ class DigestRequest {
55 return authenticate;
56 }
57
58 - Future<Dio.Response> request(
58 + Future<__dio.Response> request(
59 {String uri, String login, String password}) async {
60 - final path = '/json_rpc';
61 - final method = 'POST';
60 + const path = '/json_rpc';
61 + const method = 'POST';
62 final url = Uri.http(uri, path);
63 - final dio = Dio.Dio();
64 -
65 - Map<String, String> headers = {'Content-type': 'application/json'};
66 - String body =
67 - json.encode({"jsonrpc": "2.0", "id": "0", "method": "get_info"});
68 -
69 - var credentialsResponse = await dio.post(url.toString(),
70 - options: Dio.Options(headers: headers, validateStatus: (_) => true));
71 - var resHeaeders = credentialsResponse.headers;
72 - final authenticate =
73 - parsetAuthorizationHeader(source: resHeaeders['www-authenticate'].first);
63 + final dio = __dio.Dio();
64 + final headers = {'Content-type': 'application/json'};
65 + final body =
66 + json.encode({"jsonrpc": "2.0", "id": "0", "method": "get_info"});
67 + final credentialsResponse = await dio.post<Object>(url.toString(),
68 + options: __dio.Options(headers: headers, validateStatus: (_) => true));
69 + final authenticate = parsetAuthorizationHeader(
70 + source: credentialsResponse.headers['www-authenticate'].first);
71 final qop = authenticate['qop'];
72 final algorithm = 'MD5';
73 final realm = 'monero-rpc';
74 final nonce = authenticate['nonce'];
75 final cnonce = generateCnonce();
79 -
80 - var nonceCount = '00000001';
81 -
76 + final nonceCount = '00000001';
77 final ha1 = generateHA1(realm: realm, username: login, password: password);
78 final ha2 = generateHA2(method: method, uri: path);
79 final response = generateResponseString(
@@ -92,11 +87,10 @@ class DigestRequest {
87 final authorizationHeaders = {
88 'Content-type': 'application/json',
89 'Authorization':
95 - 'Digest username="$login",realm="$realm",nonce="$nonce",uri="$path",algorithm="$algorithm",qop=$qop,nc=$nonceCount,cnonce="$cnonce",response="$response"'
90 + 'Digest username="$login",realm="$realm",nonce="$nonce",uri="$path",algorithm="$algorithm",qop=$qop,nc=$nonceCount,cnonce="$cnonce",response="$response"'
91 };
92
98 - final res = await dio.post(url.toString(),
99 - options: Dio.Options(headers: authorizationHeaders), data: body);
100 - return res;
93 + return await dio.post<Object>(url.toString(),
94 + options: __dio.Options(headers: authorizationHeaders), data: body);
95 }
102 -}
\ No newline at end of file
96 +}
lib/src/domain/common/enumerable_item.dart
+2 -2
@@ -1,11 +1,11 @@
1 import 'package:flutter/foundation.dart';
2
3 abstract class EnumerableItem<T> {
4 + const EnumerableItem({@required this.title, @required this.raw});
5 +
6 final T raw;
7 final String title;
8
7 - const EnumerableItem({@required this.title, @required this.raw});
8 -
9 @override
10 String toString() => title;
11 }
lib/src/domain/common/fetch_price.dart
+3 -3
@@ -20,12 +20,12 @@ Future<double> fetchPriceFor({CryptoCurrency crypto, FiatCurrency fiat}) async {
20 return 0.0;
21 }
22
23 - final responseJSON = json.decode(response.body);
24 - final data = responseJSON['data'];
23 + final responseJSON = json.decode(response.body) as Map<String, dynamic>;
24 + final data = responseJSON['data'] as List<Map<String, dynamic>>;
25
26 for (final item in data) {
27 if (item['symbol'] == cryptoToString(crypto)) {
28 - price = item['quote'][fiatStringified]['price'];
28 + price = item['quote'][fiatStringified]['price'] as double;
29 break;
30 }
31 }
lib/src/domain/common/fiat_currency.dart
+5 -4
@@ -1,6 +1,11 @@
1 import 'package:cake_wallet/src/domain/common/enumerable_item.dart';
2
3 class FiatCurrency extends EnumerableItem<String> with Serializable<String> {
4 + const FiatCurrency({String symbol}) : super(title: symbol, raw: symbol);
5 +
6 + @override
7 + bool operator ==(Object other) => other is FiatCurrency && other.raw == raw;
8 +
9 static const all = [
10 FiatCurrency.aud,
11 FiatCurrency.bgn,
@@ -71,10 +76,6 @@ class FiatCurrency extends EnumerableItem<String> with Serializable<String> {
76 static const zar = FiatCurrency(symbol: 'ZAR');
77 static const vef = FiatCurrency(symbol: 'VEF');
78
74 - const FiatCurrency({String symbol}) : super(title: symbol, raw: symbol);
75 -
76 - operator ==(o) => o is FiatCurrency && o.raw == raw;
77 -
79 @override
80 int get hashCode => raw.hashCode ^ title.hashCode;
81 }
lib/src/domain/common/language.dart
+3 -5
@@ -1,16 +1,14 @@
1 import 'package:flutter/material.dart';
2
3 class Language with ChangeNotifier {
4 + Language(this._currentLanguage);
5
6 String _currentLanguage;
7
7 - Language(this._currentLanguage);
8 -
9 - getCurrentLanguage() => _currentLanguage;
8 + String getCurrentLanguage() => _currentLanguage;
9
11 - setCurrentLanguage(String language){
10 + void setCurrentLanguage(String language) {
11 _currentLanguage = language;
12 notifyListeners();
13 }
15 -
14 }
\ No newline at end of file
lib/src/domain/common/mnemotic_item.dart
+3 -5
@@ -1,13 +1,11 @@
1 class MnemoticItem {
2 + MnemoticItem({String text, this.dic}) : _text = text;
3 +
4 String get text => _text;
5 final List<String> dic;
6
7 String _text;
8
7 - MnemoticItem({String text, this.dic}) {
8 - _text = text;
9 - }
10 -
9 bool isCorrect() => dic.contains(text);
10
11 void changeText(String text) {
@@ -16,4 +14,4 @@ class MnemoticItem {
14
15 @override
16 String toString() => text;
19 -}
\ No newline at end of file
17 +}
lib/src/domain/common/node.dart
+15 -15
@@ -8,6 +8,13 @@ part 'node.g.dart';
8
9 @HiveType()
10 class Node extends HiveObject {
11 + Node({@required this.uri, this.login, this.password});
12 +
13 + Node.fromMap(Map map)
14 + : uri = (map['uri'] ?? '') as String,
15 + login = map['login'] as String,
16 + password = map['password'] as String;
17 +
18 static const boxName = 'Nodes';
19
20 @HiveField(0)
@@ -19,31 +26,24 @@ class Node extends HiveObject {
26 @HiveField(2)
27 String password;
28
22 - Node({@required this.uri, this.login, this.password});
23 -
24 - Node.fromMap(Map map)
25 - : uri = map['uri'] ?? '',
26 - login = map['login'],
27 - password = map['password'];
28 -
29 Future<bool> requestNode(String uri, {String login, String password}) async {
30 - var resBody;
30 + Map<String, dynamic> resBody;
31
32 if (login != null && password != null) {
33 final digestRequest = DigestRequest();
34 - var response = await digestRequest.request(
34 + final response = await digestRequest.request(
35 uri: uri, login: login, password: password);
36 - resBody = response.data;
36 + resBody = response.data as Map<String, dynamic>;
37 } else {
38 final url = Uri.http(uri, '/json_rpc');
39 - Map<String, String> headers = {'Content-type': 'application/json'};
40 - String body =
39 + final headers = {'Content-type': 'application/json'};
40 + final body =
41 json.encode({"jsonrpc": "2.0", "id": "0", "method": "get_info"});
42 - var response =
42 + final response =
43 await http.post(url.toString(), headers: headers, body: body);
44 - resBody = json.decode(response.body);
44 + resBody = json.decode(response.body) as Map<String, dynamic>;
45 }
46
47 - return !resBody["result"]["offline"];
47 + return !(resBody["result"]["offline"] as bool);
48 }
49 }
lib/src/domain/common/node_list.dart
+6 -5
@@ -4,20 +4,21 @@ import "package:yaml/yaml.dart";
4 import 'package:cake_wallet/src/domain/common/node.dart';
5
6 Future<List<Node>> loadDefaultNodes() async {
7 - String nodesRaw = await rootBundle.loadString('assets/node_list.yml');
8 - List nodes = loadYaml(nodesRaw);
7 + final nodesRaw = await rootBundle.loadString('assets/node_list.yml');
8 + final nodes = loadYaml(nodesRaw) as List<Map<dynamic, dynamic>>;
9 +
10 return nodes.map((raw) => Node.fromMap(raw)).toList();
11 }
12
13 Future resetToDefault(Box<Node> nodeSource) async {
14 final nodes = await loadDefaultNodes();
14 - await nodeSource.clear();
15 + final enteties = Map<int, Node>();
16
16 - Map<int, Node> enteties = {};
17 + await nodeSource.clear();
18
19 for (var i = 0; i < nodes.length; i++) {
20 enteties[i] = nodes[i];
21 }
22
23 await nodeSource.putAll(enteties);
23 -}
\ No newline at end of file
24 +}
lib/src/domain/common/pending_transaction.dart
+8 -8
@@ -1,15 +1,9 @@
1 import 'package:flutter/foundation.dart';
2 -import 'package:cw_monero/transaction_history.dart' as transactionHistory;
2 +import 'package:cw_monero/transaction_history.dart' as transaction_history;
3 import 'package:cw_monero/structs/pending_transaction.dart';
4 import 'package:cake_wallet/src/domain/monero/monero_amount_format.dart';
5
6 class PendingTransaction {
7 - final String amount;
8 - final String fee;
9 - final String hash;
10 -
11 - int _pointerAddress;
12 -
7 PendingTransaction(
8 {@required this.amount, @required this.fee, @required this.hash});
9
@@ -20,6 +14,12 @@ class PendingTransaction {
14 hash = transactionDescription.hash,
15 _pointerAddress = transactionDescription.pointerAddress;
16
23 - Future commit() async => transactionHistory
17 + final String amount;
18 + final String fee;
19 + final String hash;
20 +
21 + int _pointerAddress;
22 +
23 + Future<void> commit() async => transaction_history
24 .commitTransactionFromPointerAddress(address: _pointerAddress);
25 }
lib/src/domain/common/qr_scanner.dart
+1 -1
@@ -10,6 +10,6 @@ Future<String> presentQRScanner() async {
10 return result;
11 } catch (e) {
12 isQrScannerShown = false;
13 - throw e;
13 + rethrow;
14 }
15 }
lib/src/domain/common/sync_status.dart
+17 -3
@@ -9,18 +9,20 @@ abstract class SyncStatus {
9 }
10
11 class SyncingSyncStatus extends SyncStatus {
12 + SyncingSyncStatus(this.height, this.blockchainHeight, this.refreshHeight);
13 +
14 final int height;
15 final int blockchainHeight;
16 final int refreshHeight;
17
16 - SyncingSyncStatus(this.height, this.blockchainHeight, this.refreshHeight);
17 -
18 + @override
19 double progress() {
20 final line = blockchainHeight - refreshHeight;
21 final diff = line - (blockchainHeight - height);
22 return diff <= 0 ? 0.0 : diff / line;
23 }
24
25 + @override
26 String title() => S.current.sync_status_syncronizing;
27
28 @override
@@ -28,39 +30,51 @@ class SyncingSyncStatus extends SyncStatus {
30 }
31
32 class SyncedSyncStatus extends SyncStatus {
33 + @override
34 double progress() => 1.0;
35
36 + @override
37 String title() => S.current.sync_status_syncronized;
38 }
39
40 class NotConnectedSyncStatus extends SyncStatus {
41 const NotConnectedSyncStatus();
42
43 + @override
44 double progress() => 0.0;
45
46 + @override
47 String title() => S.current.sync_status_not_connected;
48 }
49
50 class StartingSyncStatus extends SyncStatus {
51 + @override
52 double progress() => 0.0;
53
54 + @override
55 String title() => S.current.sync_status_starting_sync;
56 }
57
58 class FailedSyncStatus extends SyncStatus {
59 + @override
60 double progress() => 1.0;
61
62 + @override
63 String title() => S.current.sync_status_failed_connect;
64 }
65
66 class ConnectingSyncStatus extends SyncStatus {
67 + @override
68 double progress() => 0.0;
69
70 + @override
71 String title() => S.current.sync_status_connecting;
72 }
73
74 class ConnectedSyncStatus extends SyncStatus {
75 + @override
76 double progress() => 0.0;
77
78 + @override
79 String title() => S.current.sync_status_connected;
66 -}
\ No newline at end of file
80 +}
lib/src/domain/common/transaction_info.dart
+22 -20
@@ -4,26 +4,20 @@ import 'package:cake_wallet/src/domain/common/parseBoolFromString.dart';
4 import 'package:cake_wallet/src/domain/common/transaction_direction.dart';
5
6 class TransactionInfo {
7 - final String id;
8 - final int height;
9 - final TransactionDirection direction;
10 - final DateTime date;
11 - final int accountIndex;
12 - final bool isPending;
13 - final int amount;
14 - String recipientAddress;
15 - String _fiatAmount;
7 + TransactionInfo(this.id, this.height, this.direction, this.date,
8 + this.isPending, this.amount, this.accountIndex);
9
10 TransactionInfo.fromMap(Map map)
18 - : id = map['hash'] ?? '',
19 - height = map['height'] ?? '',
20 - direction = parseTransactionDirectionFromNumber(map['direction']) ??
21 - TransactionDirection.incoming,
11 + : id = (map['hash'] ?? '') as String,
12 + height = (map['height'] ?? 0) as int,
13 + direction =
14 + parseTransactionDirectionFromNumber(map['direction'] as String) ??
15 + TransactionDirection.incoming,
16 date = DateTime.fromMillisecondsSinceEpoch(
23 - (int.parse(map['timestamp']) ?? 0) * 1000),
24 - isPending = parseBoolFromString(map['isPending']),
25 - amount = map['amount'],
26 - accountIndex = int.parse(map['accountIndex']);
17 + (int.parse(map['timestamp'] as String) ?? 0) * 1000),
18 + isPending = parseBoolFromString(map['isPending'] as String),
19 + amount = map['amount'] as int,
20 + accountIndex = int.parse(map['accountIndex'] as String);
21
22 TransactionInfo.fromRow(TransactionInfoRow row)
23 : id = row.getHash(),
@@ -35,12 +29,20 @@ class TransactionInfo {
29 amount = row.getAmount(),
30 accountIndex = row.subaddrAccount;
31
38 - TransactionInfo(this.id, this.height, this.direction, this.date,
39 - this.isPending, this.amount, this.accountIndex);
32 + final String id;
33 + final int height;
34 + final TransactionDirection direction;
35 + final DateTime date;
36 + final int accountIndex;
37 + final bool isPending;
38 + final int amount;
39 + String recipientAddress;
40 +
41 + String _fiatAmount;
42
43 String amountFormatted() => '${moneroAmountToString(amount: amount)} XMR';
44
45 String fiatAmount() => _fiatAmount ?? '';
46
45 - changeFiatAmount(String amount) => _fiatAmount = amount;
47 + void changeFiatAmount(String amount) => _fiatAmount = amount;
48 }
lib/src/domain/common/transaction_priority.dart
+3 -3
@@ -2,6 +2,9 @@ import 'package:cake_wallet/generated/i18n.dart';
2 import 'package:cake_wallet/src/domain/common/enumerable_item.dart';
3
4 class TransactionPriority extends EnumerableItem<int> with Serializable<int> {
5 + const TransactionPriority({String title, int raw})
6 + : super(title: title, raw: raw);
7 +
8 static const all = [
9 TransactionPriority.slow,
10 TransactionPriority.regular,
@@ -33,9 +36,6 @@ class TransactionPriority extends EnumerableItem<int> with Serializable<int> {
36 }
37 }
38
36 - const TransactionPriority({String title, int raw})
37 - : super(title: title, raw: raw);
38 -
39 @override
40 String toString() {
41 switch (this) {
lib/src/domain/common/wallet_description.dart
+2 -2
@@ -1,8 +1,8 @@
1 import 'package:cake_wallet/src/domain/common/wallet_type.dart';
2
3 class WalletDescription {
4 + WalletDescription({this.name, this.type});
5 +
6 final String name;
7 final WalletType type;
6 -
7 - WalletDescription({this.name, this.type});
8 }
\ No newline at end of file
lib/src/domain/common/wallet_info.dart
+4 -4
@@ -5,8 +5,11 @@ part 'wallet_info.g.dart';
5
6 @HiveType()
7 class WalletInfo extends HiveObject {
8 + WalletInfo(
9 + {this.id, this.name, this.type, this.isRecovery, this.restoreHeight});
10 +
11 static const boxName = 'WalletInfo';
9 -
12 +
13 @HiveField(0)
14 String id;
15
@@ -21,7 +24,4 @@ class WalletInfo extends HiveObject {
24
25 @HiveField(4)
26 int restoreHeight;
24 -
25 - WalletInfo(
26 - {this.id, this.name, this.type, this.isRecovery, this.restoreHeight});
27 }
lib/src/domain/exchange/changenow/changenow_exchange_provider.dart
+65 -41
@@ -15,45 +15,50 @@ import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.da
15 import 'package:cake_wallet/src/domain/exchange/trade_not_created_exeption.dart';
16
17 class ChangeNowExchangeProvider extends ExchangeProvider {
18 + ChangeNowExchangeProvider()
19 + : super(
20 + pairList: CryptoCurrency.all
21 + .map((i) {
22 + return CryptoCurrency.all.map((k) {
23 + if (i == CryptoCurrency.btc && k == CryptoCurrency.xmr) {
24 + return ExchangePair(from: i, to: k, reverse: false);
25 + }
26 +
27 + if (i == CryptoCurrency.xmr && k == CryptoCurrency.btc) {
28 + return null;
29 + }
30 +
31 + return ExchangePair(from: i, to: k, reverse: true);
32 + }).where((c) => c != null);
33 + })
34 + .expand((i) => i)
35 + .toList());
36 +
37 static const apiUri = 'https://changenow.io/api/v1';
38 static const apiKey = secrets.change_now_api_key;
39 static const _exchangeAmountUriSufix = '/exchange-amount/';
40 static const _transactionsUriSufix = '/transactions/';
41 static const _minAmountUriSufix = '/min-amount/';
42
43 + @override
44 String get title => 'ChangeNOW';
45 +
46 + @override
47 ExchangeProviderDescription get description =>
48 ExchangeProviderDescription.changeNow;
49
28 - ChangeNowExchangeProvider() {
29 - pairList = CryptoCurrency.all
30 - .map((i) {
31 - return CryptoCurrency.all.map((k) {
32 - if (i == CryptoCurrency.btc && k == CryptoCurrency.xmr) {
33 - return ExchangePair(from: i, to: k, reverse: false);
34 - }
35 -
36 - if (i == CryptoCurrency.xmr && k == CryptoCurrency.btc) {
37 - return null;
38 - }
39 -
40 - return ExchangePair(from: i, to: k, reverse: true);
41 - }).where((c) => c != null);
42 - })
43 - .expand((i) => i)
44 - .toList();
45 - }
46 -
50 + @override
51 Future<Limits> fetchLimits({CryptoCurrency from, CryptoCurrency to}) async {
52 final symbol = from.toString() + '_' + to.toString();
53 final url = apiUri + _minAmountUriSufix + symbol;
54 final response = await get(url);
51 - final responseJSON = json.decode(response.body);
52 - final double min = responseJSON['minAmount'];
55 + final responseJSON = json.decode(response.body) as Map<String, dynamic>;
56 + final min = responseJSON['minAmount'] as double;
57
58 return Limits(min: min, max: null);
59 }
60
61 + @override
62 Future<Trade> createTrade({TradeRequest request}) async {
63 const url = apiUri + _transactionsUriSufix + apiKey;
64 final _request = request as ChangeNowRequest;
@@ -70,37 +75,44 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
75
76 if (response.statusCode != 200) {
77 if (response.statusCode == 400) {
73 - final responseJSON = json.decode(response.body);
74 - final error = responseJSON['message'];
78 + final responseJSON = json.decode(response.body) as Map<String, dynamic>;
79 + final error = responseJSON['message'] as String;
80 +
81 throw TradeNotCreatedException(description, description: error);
82 }
83
84 throw TradeNotCreatedException(description);
85 }
86
81 - final responseJSON = json.decode(response.body);
87 + final responseJSON = json.decode(response.body) as Map<String, dynamic>;
88 + final id = responseJSON['id'] as String;
89 + final inputAddress = responseJSON['payinAddress'] as String;
90 + final refundAddress = responseJSON['refundAddress'] as String;
91 + final extraId = responseJSON['payinExtraId'] as String;
92
93 return Trade(
84 - id: responseJSON['id'],
94 + id: id,
95 from: _request.from,
96 to: _request.to,
97 provider: description,
88 - inputAddress: responseJSON['payinAddress'],
89 - refundAddress: responseJSON['refundAddress'],
90 - extraId: responseJSON["payinExtraId"],
98 + inputAddress: inputAddress,
99 + refundAddress: refundAddress,
100 + extraId: extraId,
101 createdAt: DateTime.now(),
102 amount: _request.amount,
103 state: TradeState.created);
104 }
105
106 + @override
107 Future<Trade> findTradeById({@required String id}) async {
108 final url = apiUri + _transactionsUriSufix + id + '/' + apiKey;
109 final response = await get(url);
110
111 if (response.statusCode != 200) {
112 if (response.statusCode == 400) {
102 - final responseJSON = json.decode(response.body);
103 - final error = responseJSON['message'];
113 + final responseJSON = json.decode(response.body) as Map<String, dynamic>;
114 + final error = responseJSON['message'] as String;
115 +
116 throw TradeNotFoundException(id,
117 provider: description, description: error);
118 }
@@ -108,20 +120,31 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
120 throw TradeNotFoundException(id, provider: description);
121 }
122
111 - final responseJSON = json.decode(response.body);
112 -
123 + final responseJSON = json.decode(response.body) as Map<String, dynamic>;
124 + final fromCurrency = responseJSON['fromCurrency'] as String;
125 + final from = CryptoCurrency.fromString(fromCurrency);
126 + final toCurrency = responseJSON['toCurrency'] as String;
127 + final to = CryptoCurrency.fromString(toCurrency);
128 + final inputAddress = responseJSON['payinAddress'] as String;
129 + final expectedSendAmount = responseJSON['expectedSendAmount'].toString();
130 + final status = responseJSON['status'] as String;
131 + final state = TradeState.deserialize(raw: status);
132 + final extraId = responseJSON['payinExtraId'] as String;
133 + final outputTransaction = responseJSON['payoutHash'] as String;
134 +
135 return Trade(
136 id: id,
115 - from: CryptoCurrency.fromString(responseJSON['fromCurrency']),
116 - to: CryptoCurrency.fromString(responseJSON['toCurrency']),
137 + from: from,
138 + to: to,
139 provider: description,
118 - inputAddress: responseJSON['payinAddress'],
119 - amount: responseJSON['expectedSendAmount'].toString(),
120 - state: TradeState.deserialize(raw: responseJSON['status']),
121 - extraId: responseJSON['payinExtraId'],
122 - outputTransaction: responseJSON['payoutHash']);
140 + inputAddress: inputAddress,
141 + amount: expectedSendAmount,
142 + state: state,
143 + extraId: extraId,
144 + outputTransaction: outputTransaction);
145 }
146
147 + @override
148 Future<double> calculateAmount(
149 {CryptoCurrency from, CryptoCurrency to, double amount}) async {
150 final url = apiUri +
@@ -132,8 +155,9 @@ class ChangeNowExchangeProvider extends ExchangeProvider {
155 '_' +
156 to.toString();
157 final response = await get(url);
135 - final responseJSON = json.decode(response.body);
158 + final responseJSON = json.decode(response.body) as Map<String, dynamic>;
159 + final estimatedAmount = responseJSON['estimatedAmount'] as double;
160
137 - return responseJSON['estimatedAmount'];
161 + return estimatedAmount;
162 }
163 }
lib/src/domain/exchange/changenow/changenow_request.dart
+6 -6
@@ -3,16 +3,16 @@ import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
3 import 'package:cake_wallet/src/domain/exchange/trade_request.dart';
4
5 class ChangeNowRequest extends TradeRequest {
6 - CryptoCurrency from;
7 - CryptoCurrency to;
8 - String address;
9 - String amount;
10 - String refundAddress;
11 -
6 ChangeNowRequest(
7 {@required this.from,
8 @required this.to,
9 @required this.address,
10 @required this.amount,
11 @required this.refundAddress});
12 +
13 + CryptoCurrency from;
14 + CryptoCurrency to;
15 + String address;
16 + String amount;
17 + String refundAddress;
18 }
lib/src/domain/exchange/exchange_pair.dart
+3 -3
@@ -1,9 +1,9 @@
1 import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
2
3 class ExchangePair {
4 + ExchangePair({this.from, this.to, this.reverse = true});
5 +
6 final CryptoCurrency from;
7 final CryptoCurrency to;
8 final bool reverse;
7 -
8 - ExchangePair({this.from, this.to, this.reverse = true});
9 -}
\ No newline at end of file
9 +}
lib/src/domain/exchange/exchange_provider.dart
+2
@@ -7,6 +7,8 @@ import 'package:cake_wallet/src/domain/exchange/trade.dart';
7 import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
8
9 abstract class ExchangeProvider {
10 + ExchangeProvider({this.pairList});
11 +
12 String get title;
13 List<ExchangePair> pairList;
14 ExchangeProviderDescription description;
lib/src/domain/exchange/exchange_provider_description.dart
+3 -5
@@ -2,6 +2,9 @@ import 'package:cake_wallet/src/domain/common/enumerable_item.dart';
2
3 class ExchangeProviderDescription extends EnumerableItem<int>
4 with Serializable<int> {
5 + const ExchangeProviderDescription({String title, int raw})
6 + : super(title: title, raw: raw);
7 +
8 static const xmrto = ExchangeProviderDescription(title: 'XMR.TO', raw: 0);
9 static const changeNow =
10 ExchangeProviderDescription(title: 'ChangeNOW', raw: 1);
@@ -16,9 +19,4 @@ class ExchangeProviderDescription extends EnumerableItem<int>
19 return null;
20 }
21 }
19 -
20 - final String title;
21 -
22 - const ExchangeProviderDescription({this.title, int raw})
23 - : super(title: title, raw: raw);
22 }
lib/src/domain/exchange/limits.dart
+2 -2
@@ -1,6 +1,6 @@
1 class Limits {
2 + const Limits({this.min, this.max});
3 +
4 final double min;
5 final double max;
4 -
5 - const Limits({this.min, this.max});
6 }
\ No newline at end of file
lib/src/domain/exchange/trade.dart
+28 -27
@@ -7,6 +7,25 @@ part 'trade.g.dart';
7
8 @HiveType()
9 class Trade extends HiveObject {
10 + Trade(
11 + {this.id,
12 + ExchangeProviderDescription provider,
13 + CryptoCurrency from,
14 + CryptoCurrency to,
15 + TradeState state,
16 + this.createdAt,
17 + this.expiredAt,
18 + this.amount,
19 + this.inputAddress,
20 + this.extraId,
21 + this.outputTransaction,
22 + this.refundAddress,
23 + this.walletId})
24 + : providerRaw = provider?.raw,
25 + fromRaw = from?.raw,
26 + toRaw = to?.raw,
27 + stateRaw = state?.raw;
28 +
29 static const boxName = 'Trades';
30
31 @HiveField(0)
@@ -59,38 +78,20 @@ class Trade extends HiveObject {
78
79 static Trade fromMap(Map map) {
80 return Trade(
62 - id: map['id'],
63 - provider: ExchangeProviderDescription.deserialize(raw: map['provider']),
64 - from: CryptoCurrency.deserialize(raw: map['input']),
65 - to: CryptoCurrency.deserialize(raw: map['output']),
81 + id: map['id'] as String,
82 + provider: ExchangeProviderDescription.deserialize(
83 + raw: map['provider'] as int),
84 + from: CryptoCurrency.deserialize(raw: map['input'] as int),
85 + to: CryptoCurrency.deserialize(raw: map['output'] as int),
86 createdAt: map['date'] != null
67 - ? DateTime.fromMillisecondsSinceEpoch(map['date'])
87 + ? DateTime.fromMillisecondsSinceEpoch(map['date'] as int)
88 : null,
69 - amount: map['amount'],
70 - walletId: map['wallet_id']);
89 + amount: map['amount'] as String,
90 + walletId: map['wallet_id'] as String);
91 }
92
73 - Trade(
74 - {this.id,
75 - ExchangeProviderDescription provider,
76 - CryptoCurrency from,
77 - CryptoCurrency to,
78 - TradeState state,
79 - this.createdAt,
80 - this.expiredAt,
81 - this.amount,
82 - this.inputAddress,
83 - this.extraId,
84 - this.outputTransaction,
85 - this.refundAddress,
86 - this.walletId})
87 - : providerRaw = provider?.raw,
88 - fromRaw = from?.raw,
89 - toRaw = to?.raw,
90 - stateRaw = state?.raw;
91 -
93 Map<String, dynamic> toMap() {
93 - return {
94 + return <String, dynamic>{
95 'id': id,
96 'provider': provider.serialize(),
97 'input': from.serialize(),
lib/src/domain/exchange/trade_not_created_exeption.dart
+2 -2
@@ -2,11 +2,11 @@ import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.da
2 import 'package:cake_wallet/generated/i18n.dart';
3
4 class TradeNotCreatedException implements Exception {
5 + TradeNotCreatedException(this.provider, {this.description = ''});
6 +
7 ExchangeProviderDescription provider;
8 String description;
9
8 - TradeNotCreatedException(this.provider, {this.description = ''});
9 -
10 @override
11 String toString() {
12 var text = provider != null
lib/src/domain/exchange/trade_not_found_exeption.dart
+2 -2
@@ -2,12 +2,12 @@ import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.da
2 import 'package:cake_wallet/generated/i18n.dart';
3
4 class TradeNotFoundException implements Exception {
5 + TradeNotFoundException(this.tradeId, {this.provider, this.description = ''});
6 +
7 String tradeId;
8 ExchangeProviderDescription provider;
9 String description;
10
9 - TradeNotFoundException(this.tradeId, {this.provider, this.description = ''});
10 -
11 @override
12 String toString() {
13 var text = tradeId != null && provider != null
lib/src/domain/exchange/trade_state.dart
+6 -5
@@ -2,6 +2,12 @@ import 'package:flutter/foundation.dart';
2 import 'package:cake_wallet/src/domain/common/enumerable_item.dart';
3
4 class TradeState extends EnumerableItem<String> with Serializable<String> {
5 + const TradeState({@required String raw, @required String title})
6 + : super(raw: raw, title: title);
7 +
8 + @override
9 + bool operator ==(Object other) => other is TradeState && other.raw == raw;
10 +
11 static const pending = TradeState(raw: 'pending', title: 'Pending');
12 static const confirming = TradeState(raw: 'confirming', title: 'Confirming');
13 static const trading = TradeState(raw: 'trading', title: 'Trading');
@@ -58,11 +64,6 @@ class TradeState extends EnumerableItem<String> with Serializable<String> {
64 }
65 }
66
61 - const TradeState({@required String raw, @required String title})
62 - : super(raw: raw, title: title);
63 -
64 - operator ==(o) => o is TradeState && o.raw == raw;
65 -
67 @override
68 int get hashCode => raw.hashCode ^ title.hashCode;
69 }
lib/src/domain/exchange/xmrto/xmrto_exchange_provider.dart
+34 -24
@@ -14,6 +14,12 @@ import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.da
14 import 'package:cake_wallet/src/domain/exchange/trade_not_found_exeption.dart';
15
16 class XMRTOExchangeProvider extends ExchangeProvider {
17 + XMRTOExchangeProvider()
18 + : super(pairList: [
19 + ExchangePair(
20 + from: CryptoCurrency.xmr, to: CryptoCurrency.btc, reverse: false)
21 + ]);
22 +
23 static const userAgent = 'CakeWallet/XMR iOS';
24 static const originalApiUri = 'https://xmr.to/api/v2/xmr2btc';
25 static const proxyApiUri = 'https://xmrproxy.net/api/v2/xmr2btc';
@@ -35,18 +41,16 @@ class XMRTOExchangeProvider extends ExchangeProvider {
41 return _apiUri;
42 }
43
44 + @override
45 String get title => 'XMR.TO';
46
47 + @override
48 ExchangeProviderDescription get description =>
49 ExchangeProviderDescription.xmrto;
50
43 - List<ExchangePair> pairList = [
44 - ExchangePair(
45 - from: CryptoCurrency.xmr, to: CryptoCurrency.btc, reverse: false)
46 - ];
47 -
51 double _rate = 0;
52
53 + @override
54 Future<Limits> fetchLimits({CryptoCurrency from, CryptoCurrency to}) async {
55 final url = await getApiUri() + _orderParameterUriSufix;
56 final response = await get(url);
@@ -55,13 +59,14 @@ class XMRTOExchangeProvider extends ExchangeProvider {
59 return Limits(min: 0, max: 0);
60 }
61
58 - final responseJSON = json.decode(response.body);
59 - final double min = responseJSON['lower_limit'];
60 - final double max = responseJSON['upper_limit'];
62 + final responseJSON = json.decode(response.body) as Map<String, dynamic>;
63 + final min = responseJSON['lower_limit'] as double;
64 + final max = responseJSON['upper_limit'] as double;
65
66 return Limits(min: min, max: max);
67 }
68
69 + @override
70 Future<Trade> createTrade({TradeRequest request}) async {
71 final _request = request as XMRTOTradeRequest;
72 final url = await getApiUri() + _orderCreateUriSufix;
@@ -74,16 +79,17 @@ class XMRTOExchangeProvider extends ExchangeProvider {
79
80 if (response.statusCode != 201) {
81 if (response.statusCode == 400) {
77 - final responseJSON = json.decode(response.body);
78 - throw TradeNotCreatedException(description,
79 - description: responseJSON['error_msg']);
82 + final responseJSON = json.decode(response.body) as Map<String, dynamic>;
83 + final error = responseJSON['error_msg'] as String;
84 +
85 + throw TradeNotCreatedException(description, description: error);
86 }
87
88 throw TradeNotCreatedException(description);
89 }
90
85 - final responseJSON = json.decode(response.body);
86 - final uuid = responseJSON["uuid"];
91 + final responseJSON = json.decode(response.body) as Map<String, dynamic>;
92 + final uuid = responseJSON["uuid"] as String;
93
94 return Trade(
95 id: uuid,
@@ -95,6 +101,7 @@ class XMRTOExchangeProvider extends ExchangeProvider {
101 createdAt: DateTime.now());
102 }
103
104 + @override
105 Future<Trade> findTradeById({@required String id}) async {
106 const headers = {
107 'Content-Type': 'application/json',
@@ -106,8 +113,9 @@ class XMRTOExchangeProvider extends ExchangeProvider {
113
114 if (response.statusCode != 200) {
115 if (response.statusCode == 400) {
109 - final responseJSON = json.decode(response.body);
110 - final error = responseJSON['error_msg'];
116 + final responseJSON = json.decode(response.body) as Map<String, dynamic>;
117 + final error = responseJSON['error_msg'] as String;
118 +
119 throw TradeNotFoundException(id,
120 provider: description, description: error);
121 }
@@ -115,14 +123,14 @@ class XMRTOExchangeProvider extends ExchangeProvider {
123 throw TradeNotFoundException(id, provider: description);
124 }
125
118 - final responseJSON = json.decode(response.body);
119 - final address = responseJSON['xmr_receiving_integrated_address'];
120 - final paymentId = responseJSON['xmr_required_payment_id_short'];
126 + final responseJSON = json.decode(response.body) as Map<String, dynamic>;
127 + final address = responseJSON['xmr_receiving_integrated_address'] as String;
128 + final paymentId = responseJSON['xmr_required_payment_id_short'] as String;
129 final amount = responseJSON['xmr_amount_total'].toString();
122 - final stateRaw = responseJSON['state'];
123 - final expiredAtRaw = responseJSON['expires_at'];
130 + final stateRaw = responseJSON['state'] as String;
131 + final expiredAtRaw = responseJSON['expires_at'] as String;
132 final expiredAt = DateTime.parse(expiredAtRaw).toLocal();
125 - final outputTransaction = responseJSON['btc_transaction_id'];
133 + final outputTransaction = responseJSON['btc_transaction_id'] as String;
134 final state = TradeState.deserialize(raw: stateRaw);
135
136 return Trade(
@@ -138,6 +146,7 @@ class XMRTOExchangeProvider extends ExchangeProvider {
146 outputTransaction: outputTransaction);
147 }
148
149 + @override
150 Future<double> calculateAmount(
151 {CryptoCurrency from, CryptoCurrency to, double amount}) async {
152 if (from != CryptoCurrency.xmr && to != CryptoCurrency.btc) {
@@ -158,9 +167,10 @@ class XMRTOExchangeProvider extends ExchangeProvider {
167 final url = await getApiUri() + _orderParameterUriSufix;
168 final response =
169 await get(url, headers: {'Content-Type': 'application/json'});
161 - final responseJSON = json.decode(response.body);
162 - double btcprice = responseJSON['price'];
163 - double price = 1 / btcprice;
170 + final responseJSON = json.decode(response.body) as Map<String, dynamic>;
171 + final btcprice = responseJSON['price'] as double;
172 + final price = 1 / btcprice;
173 +
174 return price;
175 } catch (e) {
176 print(e.toString());
lib/src/domain/exchange/xmrto/xmrto_trade_request.dart
+6 -6
@@ -3,16 +3,16 @@ import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
3 import 'package:cake_wallet/src/domain/exchange/trade_request.dart';
4
5 class XMRTOTradeRequest extends TradeRequest {
6 - final CryptoCurrency from;
7 - final CryptoCurrency to;
8 - final String amount;
9 - final String address;
10 - final String refundAddress;
11 -
6 XMRTOTradeRequest(
7 {@required this.from,
8 @required this.to,
9 @required this.amount,
10 @required this.address,
11 @required this.refundAddress});
12 +
13 + final CryptoCurrency from;
14 + final CryptoCurrency to;
15 + final String amount;
16 + final String address;
17 + final String refundAddress;
18 }
lib/src/domain/monero/account.dart
+5 -5
@@ -1,16 +1,16 @@
1 import 'package:cw_monero/structs/account_row.dart';
2
3 class Account {
4 - final int id;
5 - final String label;
6 -
4 Account({this.id, this.label});
5
6 Account.fromMap(Map map)
10 - : this.id = map['id'] == null ? 0 : int.parse(map['id']),
11 - this.label = map['label'] ?? '';
7 + : this.id = map['id'] == null ? 0 : int.parse(map['id'] as String),
8 + this.label = (map['label'] ?? '') as String;
9
10 Account.fromRow(AccountRow row)
11 : this.id = row.getId(),
12 this.label = row.getLabel();
13 +
14 + final int id;
15 + final String label;
16 }
lib/src/domain/monero/account_list.dart
+16 -15
@@ -1,20 +1,20 @@
1 import 'package:rxdart/rxdart.dart';
2 -import 'package:cw_monero/account_list.dart' as accountListAPI;
2 +import 'package:cw_monero/account_list.dart' as account_list;
3 import 'package:cake_wallet/src/domain/monero/account.dart';
4
5 class AccountList {
6 - get accounts => _accounts.stream;
7 - BehaviorSubject<List<Account>> _accounts;
8 -
9 - bool _isRefreshing;
10 - bool _isUpdating;
11 -
6 AccountList() {
7 _isRefreshing = false;
8 _isUpdating = false;
9 _accounts = BehaviorSubject<List<Account>>();
10 }
11
12 + Observable<List<Account>> get accounts => _accounts.stream;
13 +
14 + BehaviorSubject<List<Account>> _accounts;
15 + bool _isRefreshing;
16 + bool _isUpdating;
17 +
18 Future update() async {
19 if (_isUpdating) {
20 return;
@@ -22,46 +22,47 @@ class AccountList {
22
23 try {
24 _isUpdating = true;
25 - await refresh();
25 + refresh();
26 final accounts = getAll();
27 _accounts.add(accounts);
28 _isUpdating = false;
29 } catch (e) {
30 _isUpdating = false;
31 - throw e;
31 + rethrow;
32 }
33 }
34
35 List<Account> getAll() {
36 - return accountListAPI
36 + return account_list
37 .getAllAccount()
38 .map((accountRow) => Account.fromRow(accountRow))
39 .toList();
40 }
41
42 Future addAccount({String label}) async {
43 - await accountListAPI.addAccount(label: label);
43 + await account_list.addAccount(label: label);
44 await update();
45 }
46
47 Future setLabelSubaddress({int accountIndex, String label}) async {
48 - await accountListAPI.setLabelForAccount(accountIndex: accountIndex, label: label);
48 + await account_list.setLabelForAccount(
49 + accountIndex: accountIndex, label: label);
50 await update();
51 }
52
52 - refresh() {
53 + void refresh() {
54 if (_isRefreshing) {
55 return;
56 }
57
58 try {
59 _isRefreshing = true;
59 - accountListAPI.refreshAccounts();
60 + account_list.refreshAccounts();
61 _isRefreshing = false;
62 } catch (e) {
63 _isRefreshing = false;
64 print(e);
64 - throw e;
65 + rethrow;
66 }
67 }
68 }
lib/src/domain/monero/get_height_by_date.dart
+8 -7
@@ -77,7 +77,8 @@ int getHeigthByDate({DateTime date}) {
77
78 if (endHeight <= 0) {
79 endHeight = dates.values.toList()[dates.length - 1];
80 - final preLastDate = dateFormat.parse(dates.keys.elementAt(dates.keys.length - 2));
80 + final preLastDate =
81 + dateFormat.parse(dates.keys.elementAt(dates.keys.length - 2));
82 preLastYear = preLastDate.year;
83 preLastMonth = preLastDate.month;
84 } else {
@@ -90,12 +91,12 @@ int getHeigthByDate({DateTime date}) {
91 preLastYear -= 1;
92 }
93
93 - var startRaw = '$preLastYear' + '-' + '$preLastMonth';
94 - var startHeight = dates[startRaw];
95 - var diff = endHeight - startHeight;
96 - var heightPerDay = diff / 30;
97 - var daysHeight = date.day * heightPerDay.round();
98 - var height = endHeight + daysHeight;
94 + final startRaw = '$preLastYear' + '-' + '$preLastMonth';
95 + final startHeight = dates[startRaw];
96 + final diff = endHeight - startHeight;
97 + final heightPerDay = diff / 30;
98 + final daysHeight = date.day * heightPerDay.round();
99 + final height = endHeight + daysHeight;
100
101 return height;
102 }
lib/src/domain/monero/monero_balance.dart
+2 -2
@@ -2,8 +2,8 @@ import 'package:flutter/foundation.dart';
2 import 'package:cake_wallet/src/domain/common/balance.dart';
3
4 class MoneroBalance extends Balance {
5 + MoneroBalance({@required this.fullBalance, @required this.unlockedBalance});
6 +
7 final String fullBalance;
8 final String unlockedBalance;
7 -
8 - MoneroBalance({@required this.fullBalance, @required this.unlockedBalance});
9 }
lib/src/domain/monero/monero_transaction_creation_credentials.dart
+4 -4
@@ -3,11 +3,11 @@ import 'package:cake_wallet/src/domain/common/transaction_priority.dart';
3
4 class MoneroTransactionCreationCredentials
5 extends TransactionCreationCredentials {
6 + MoneroTransactionCreationCredentials(
7 + {this.address, this.paymentId, this.priority, this.amount});
8 +
9 final String address;
10 final String paymentId;
11 final String amount;
12 final TransactionPriority priority;
10 -
11 - MoneroTransactionCreationCredentials(
12 - {this.address, this.paymentId, this.priority, this.amount});
13 -}
\ No newline at end of file
13 +}
lib/src/domain/monero/monero_transaction_history.dart
+17 -11
@@ -1,26 +1,29 @@
1 import 'dart:core';
2 import 'package:flutter/services.dart';
3 import 'package:rxdart/rxdart.dart';
4 -import 'package:cw_monero/transaction_history.dart' as moneroTransactionHistory;
4 +import 'package:cw_monero/transaction_history.dart'
5 + as monero_transaction_history;
6 import 'package:cake_wallet/src/domain/common/transaction_history.dart';
7 import 'package:cake_wallet/src/domain/common/transaction_info.dart';
8
8 -List<TransactionInfo> _getAllTransactions(_) => moneroTransactionHistory
9 +List<TransactionInfo> _getAllTransactions(dynamic _) => monero_transaction_history
10 .getAllTransations()
11 .map((row) => TransactionInfo.fromRow(row))
12 .toList();
13
14 class MoneroTransactionHistory extends TransactionHistory {
14 - get transactions => _transactions.stream;
15 - BehaviorSubject<List<TransactionInfo>> _transactions;
15 + MoneroTransactionHistory()
16 + : _transactions = BehaviorSubject<List<TransactionInfo>>.seeded([]);
17 +
18 + @override
19 + Observable<List<TransactionInfo>> get transactions => _transactions.stream;
20
21 + final BehaviorSubject<List<TransactionInfo>> _transactions;
22 bool _isUpdating = false;
23 bool _isRefreshing = false;
24 bool _needToCheckForRefresh = false;
25
21 - MoneroTransactionHistory()
22 - : _transactions = BehaviorSubject<List<TransactionInfo>>.seeded([]);
23 -
26 + @override
27 Future update() async {
28 if (_isUpdating) {
29 return;
@@ -38,15 +41,18 @@ class MoneroTransactionHistory extends TransactionHistory {
41 } catch (e) {
42 _isUpdating = false;
43 print(e);
41 - throw e;
44 + rethrow;
45 }
46 }
47
48 + @override
49 Future<List<TransactionInfo>> getAll({bool force = false}) async =>
50 _getAllTransactions(null);
51
48 - Future<int> count() async => moneroTransactionHistory.countOfTransactions();
52 + @override
53 + Future<int> count() async => monero_transaction_history.countOfTransactions();
54
55 + @override
56 Future refresh() async {
57 if (_isRefreshing) {
58 return;
@@ -54,12 +60,12 @@ class MoneroTransactionHistory extends TransactionHistory {
60
61 try {
62 _isRefreshing = true;
57 - moneroTransactionHistory.refreshTransactions();
63 + monero_transaction_history.refreshTransactions();
64 _isRefreshing = false;
65 } on PlatformException catch (e) {
66 _isRefreshing = false;
67 print(e);
62 - throw e;
68 + rethrow;
69 }
70 }
71 }
lib/src/domain/monero/monero_wallet.dart
+132 -99
@@ -3,8 +3,8 @@ import 'package:flutter/foundation.dart';
3 import 'package:flutter/services.dart';
4 import 'package:hive/hive.dart';
5 import 'package:rxdart/rxdart.dart';
6 -import 'package:cw_monero/wallet.dart' as moneroWallet;
7 -import 'package:cw_monero/transaction_history.dart' as transactionHistory;
6 +import 'package:cw_monero/wallet.dart' as monero_wallet;
7 +import 'package:cw_monero/transaction_history.dart' as transaction_history;
8 import 'package:cake_wallet/src/domain/common/wallet_info.dart';
9 import 'package:cake_wallet/src/domain/common/wallet.dart';
10 import 'package:cake_wallet/src/domain/common/sync_status.dart';
@@ -23,9 +23,25 @@ import 'package:cake_wallet/src/domain/monero/subaddress.dart';
23 import 'package:cake_wallet/src/domain/common/balance.dart';
24 import 'package:cake_wallet/src/domain/monero/monero_balance.dart';
25
26 -const monero_block_size = 1000;
26 +const moneroBlockSize = 1000;
27
28 class MoneroWallet extends Wallet {
29 + MoneroWallet({this.walletInfoSource, this.walletInfo}) {
30 + _cachedBlockchainHeight = 0;
31 + _isSaving = false;
32 + _lastSaveTime = 0;
33 + _lastRefreshTime = 0;
34 + _refreshHeight = 0;
35 + _lastSyncHeight = 0;
36 + _name = BehaviorSubject<String>();
37 + _address = BehaviorSubject<String>();
38 + _syncStatus = BehaviorSubject<SyncStatus>();
39 + _onBalanceChange = BehaviorSubject<MoneroBalance>();
40 + _account = BehaviorSubject<Account>()..add(Account(id: 0));
41 + _subaddress = BehaviorSubject<Subaddress>();
42 + setListeners();
43 + }
44 +
45 static Future<MoneroWallet> createdWallet(
46 {Box<WalletInfo> walletInfoSource,
47 String name,
@@ -48,8 +64,8 @@ class MoneroWallet extends Wallet {
64 static Future<MoneroWallet> load(
65 Box<WalletInfo> walletInfoSource, String name, WalletType type) async {
66 final id = walletTypeToString(type).toLowerCase() + '_' + name;
51 - final walletInfo =
52 - walletInfoSource.values.firstWhere((info) => info.id == id, orElse: () => null);
67 + final walletInfo = walletInfoSource.values
68 + .firstWhere((info) => info.id == id, orElse: () => null);
69 return await configured(
70 walletInfoSource: walletInfoSource, walletInfo: walletInfo);
71 }
@@ -61,29 +77,44 @@ class MoneroWallet extends Wallet {
77 walletInfoSource: walletInfoSource, walletInfo: walletInfo);
78
79 if (walletInfo.isRecovery) {
64 - await wallet.setRecoveringFromSeed();
80 + wallet.setRecoveringFromSeed();
81
82 if (walletInfo.restoreHeight != null) {
67 - await wallet.setRefreshFromBlockHeight(
68 - height: walletInfo.restoreHeight);
83 + wallet.setRefreshFromBlockHeight(height: walletInfo.restoreHeight);
84 }
85 }
86
87 return wallet;
88 }
89
90 + @override
91 + String get address => _address.value;
92 +
93 + @override
94 + String get name => _name.value;
95 +
96 + @override
97 WalletType getType() => WalletType.monero;
76 - bool get isRecovery => walletInfo.isRecovery;
98 +
99 + @override
100 Observable<SyncStatus> get syncStatus => _syncStatus.stream;
101 +
102 + @override
103 Observable<Balance> get onBalanceChange => _onBalanceChange.stream;
79 - Observable<Account> get onAccountChange => _account.stream;
104 +
105 + @override
106 Observable<String> get onNameChange => _name.stream;
107 +
108 + @override
109 Observable<String> get onAddressChange => _address.stream;
110 +
111 + Observable<Account> get onAccountChange => _account.stream;
112 +
113 Observable<Subaddress> get subaddress => _subaddress.stream;
114
115 + bool get isRecovery => walletInfo.isRecovery;
116 +
117 Account get account => _account.value;
85 - String get address => _address.value;
86 - String get name => _name.value;
118
119 Box<WalletInfo> walletInfoSource;
120 WalletInfo walletInfo;
@@ -105,27 +136,11 @@ class MoneroWallet extends Wallet {
136 SubaddressList _cachedSubaddressList;
137 AccountList _cachedAccountList;
138
108 - MoneroWallet(
109 - {this.walletInfoSource, this.walletInfo}) {
110 - _cachedBlockchainHeight = 0;
111 - _isSaving = false;
112 - _lastSaveTime = 0;
113 - _lastRefreshTime = 0;
114 - _refreshHeight = 0;
115 - _lastSyncHeight = 0;
116 - _name = BehaviorSubject<String>();
117 - _address = BehaviorSubject<String>();
118 - _syncStatus = BehaviorSubject<SyncStatus>();
119 - _onBalanceChange = BehaviorSubject<MoneroBalance>();
120 - _account = BehaviorSubject<Account>()..add(Account(id: 0));
121 - _subaddress = BehaviorSubject<Subaddress>();
122 - setListeners();
123 - }
124 -
139 + @override
140 Future updateInfo() async {
141 _name.value = await getName();
142 final acccountList = getAccountList();
128 - await acccountList.refresh();
143 + acccountList.refresh();
144 _account.value = acccountList.getAll().first;
145 final subaddressList = getSubaddress();
146 await subaddressList.refresh(
@@ -135,44 +150,87 @@ class MoneroWallet extends Wallet {
150 _address.value = await getAddress();
151 }
152
138 - Future<String> getFilename() async => moneroWallet.getFilename();
153 + @override
154 + Future<String> getFilename() async => monero_wallet.getFilename();
155
156 + @override
157 Future<String> getName() async => getFilename()
158 .then((filename) => filename.split('/'))
159 .then((splitted) => splitted.last);
160
144 - Future<String> getAddress() async => moneroWallet.getAddress(
161 + @override
162 + Future<String> getAddress() async => monero_wallet.getAddress(
163 accountIndex: _account.value.id, addressIndex: _subaddress.value.id);
164
147 - Future<String> getSeed() async => moneroWallet.getSeed();
165 + @override
166 + Future<String> getSeed() async => monero_wallet.getSeed();
167
168 + @override
169 Future<String> getFullBalance() async => moneroAmountToString(
150 - amount: moneroWallet.getFullBalance(accountIndex: _account.value.id));
170 + amount: monero_wallet.getFullBalance(accountIndex: _account.value.id));
171
172 + @override
173 Future<String> getUnlockedBalance() async => moneroAmountToString(
153 - amount: moneroWallet.getUnlockedBalance(accountIndex: _account.value.id));
174 + amount:
175 + monero_wallet.getUnlockedBalance(accountIndex: _account.value.id));
176 +
177 + @override
178 + Future<int> getCurrentHeight() async => monero_wallet.getCurrentHeight();
179
155 - Future<int> getCurrentHeight() async => moneroWallet.getCurrentHeight();
180 + @override
181 + Future<int> getNodeHeight() async => monero_wallet.getNodeHeight();
182
157 - Future<int> getNodeHeight() async => moneroWallet.getNodeHeight();
183 + @override
184 + Future<bool> isConnected() async => monero_wallet.isConnected();
185
186 + @override
187 Future<Map<String, String>> getKeys() async => {
160 - 'publicViewKey': moneroWallet.getPublicViewKey(),
161 - 'privateViewKey': moneroWallet.getSecretViewKey(),
162 - 'publicSpendKey': moneroWallet.getPublicSpendKey(),
163 - 'privateSpendKey': moneroWallet.getSecretSpendKey()
188 + 'publicViewKey': monero_wallet.getPublicViewKey(),
189 + 'privateViewKey': monero_wallet.getSecretViewKey(),
190 + 'publicSpendKey': monero_wallet.getPublicSpendKey(),
191 + 'privateSpendKey': monero_wallet.getSecretSpendKey()
192 };
193
194 + @override
195 + TransactionHistory getHistory() {
196 + if (_cachedTransactionHistory == null) {
197 + _cachedTransactionHistory = MoneroTransactionHistory();
198 + }
199 +
200 + return _cachedTransactionHistory;
201 + }
202 +
203 + SubaddressList getSubaddress() {
204 + if (_cachedSubaddressList == null) {
205 + _cachedSubaddressList = SubaddressList();
206 + }
207 +
208 + return _cachedSubaddressList;
209 + }
210 +
211 + AccountList getAccountList() {
212 + if (_cachedAccountList == null) {
213 + _cachedAccountList = AccountList();
214 + }
215 +
216 + return _cachedAccountList;
217 + }
218 +
219 + @override
220 Future close() async {
167 - moneroWallet.closeListeners();
168 - moneroWallet.closeCurrentWallet();
221 + monero_wallet.closeListeners();
222 + monero_wallet.closeCurrentWallet();
223 + await _name.close();
224 + await _address.close();
225 + await _subaddress.close();
226 }
227
228 + @override
229 Future connectToNode(
230 {Node node, bool useSSL = false, bool isLightWallet = false}) async {
231 try {
232 _syncStatus.value = ConnectingSyncStatus();
175 - await moneroWallet.setupNode(
233 + await monero_wallet.setupNode(
234 address: node.uri,
235 login: node.login,
236 password: node.password,
@@ -185,39 +243,16 @@ class MoneroWallet extends Wallet {
243 }
244 }
245
246 + @override
247 Future startSync() async {
248 try {
249 _syncStatus.value = StartingSyncStatus();
191 - moneroWallet.startRefresh();
250 + monero_wallet.startRefresh();
251 } on PlatformException catch (e) {
252 _syncStatus.value = FailedSyncStatus();
253 print(e);
195 - throw e;
196 - }
197 - }
198 -
199 - TransactionHistory getHistory() {
200 - if (_cachedTransactionHistory == null) {
201 - _cachedTransactionHistory = MoneroTransactionHistory();
202 - }
203 -
204 - return _cachedTransactionHistory;
205 - }
206 -
207 - SubaddressList getSubaddress() {
208 - if (_cachedSubaddressList == null) {
209 - _cachedSubaddressList = SubaddressList();
254 + rethrow;
255 }
211 -
212 - return _cachedSubaddressList;
213 - }
214 -
215 - AccountList getAccountList() {
216 - if (_cachedAccountList == null) {
217 - _cachedAccountList = AccountList();
218 - }
219 -
220 - return _cachedAccountList;
256 }
257
258 Future askForSave() async {
@@ -238,12 +273,11 @@ class MoneroWallet extends Wallet {
273 return _cachedBlockchainHeight;
274 }
275
276 + @override
277 Future<PendingTransaction> createTransaction(
278 TransactionCreationCredentials credentials) async {
243 - MoneroTransactionCreationCredentials _credentials =
244 - credentials as MoneroTransactionCreationCredentials;
245 -
246 - final transactionDescription = await transactionHistory.createTransaction(
279 + final _credentials = credentials as MoneroTransactionCreationCredentials;
280 + final transactionDescription = await transaction_history.createTransaction(
281 address: _credentials.address,
282 paymentId: _credentials.paymentId,
283 amount: _credentials.amount,
@@ -254,13 +288,19 @@ class MoneroWallet extends Wallet {
288 transactionDescription);
289 }
290
257 - setRecoveringFromSeed() =>
258 - moneroWallet.setRecoveringFromSeed(isRecovery: true);
291 + @override
292 + Future rescan({int restoreHeight = 0}) async {
293 + _syncStatus.value = StartingSyncStatus();
294 + setRefreshFromBlockHeight(height: restoreHeight);
295 + monero_wallet.rescanBlockchainAsync();
296 + _syncStatus.value = StartingSyncStatus();
297 + }
298
260 - setRefreshFromBlockHeight({int height}) =>
261 - moneroWallet.setRefreshFromBlockHeight(height: height);
299 + void setRecoveringFromSeed() =>
300 + monero_wallet.setRecoveringFromSeed(isRecovery: true);
301
263 - Future<bool> isConnected() async => moneroWallet.isConnected();
302 + void setRefreshFromBlockHeight({int height}) =>
303 + monero_wallet.setRefreshFromBlockHeight(height: height);
304
305 Future setAsRecovered() async {
306 walletInfo.isRecovery = false;
@@ -285,22 +325,15 @@ class MoneroWallet extends Wallet {
325
326 Future askForUpdateTransactionHistory() async => await getHistory().update();
327
288 - Future rescan({int restoreHeight = 0}) async {
289 - _syncStatus.value = StartingSyncStatus();
290 - setRefreshFromBlockHeight(height: restoreHeight);
291 - moneroWallet.rescanBlockchainAsync();
292 - _syncStatus.value = StartingSyncStatus();
293 - }
294 -
295 - changeCurrentSubaddress(Subaddress subaddress) =>
328 + void changeCurrentSubaddress(Subaddress subaddress) =>
329 _subaddress.value = subaddress;
330
298 - changeAccount(Account account) {
331 + void changeAccount(Account account) {
332 _account.add(account);
333
334 getSubaddress()
335 .refresh(accountIndex: account.id)
303 - .then((_) => getSubaddress().getAll())
336 + .then((dynamic _) => getSubaddress().getAll())
337 .then((subaddresses) => _subaddress.value = subaddresses[0]);
338 }
339
@@ -311,16 +344,16 @@ class MoneroWallet extends Wallet {
344
345 try {
346 _isSaving = true;
314 - moneroWallet.store();
347 + await monero_wallet.store();
348 _isSaving = false;
349 } on PlatformException catch (e) {
350 print(e);
351 _isSaving = false;
319 - throw e;
352 + rethrow;
353 }
354 }
355
323 - setListeners() => moneroWallet.setListeners(
356 + void setListeners() => monero_wallet.setListeners(
357 _onNewBlock, _onNeedToRefresh, _onNewTransaction);
358
359 Future _onNewBlock(int height) async {
@@ -333,13 +366,13 @@ class MoneroWallet extends Wallet {
366
367 if (isRecovery &&
368 (_lastSyncHeight == 0 ||
336 - (height - _lastSyncHeight) > monero_block_size)) {
369 + (height - _lastSyncHeight) > moneroBlockSize)) {
370 _lastSyncHeight = height;
338 - askForUpdateBalance();
339 - askForUpdateTransactionHistory();
371 + await askForUpdateBalance();
372 + await askForUpdateTransactionHistory();
373 }
374
342 - if (height > 0 && ((nodeHeight - height) < monero_block_size)) {
375 + if (height > 0 && ((nodeHeight - height) < moneroBlockSize)) {
376 _syncStatus.add(SyncedSyncStatus());
377 } else {
378 _syncStatus.add(SyncingSyncStatus(height, nodeHeight, _refreshHeight));
@@ -363,15 +396,15 @@ class MoneroWallet extends Wallet {
396 return;
397 }
398
366 - askForUpdateBalance();
399 + await askForUpdateBalance();
400
401 _syncStatus.add(SyncedSyncStatus());
402
403 if (isRecovery) {
371 - askForUpdateTransactionHistory();
404 + await askForUpdateTransactionHistory();
405 }
406
374 - if (isRecovery && (nodeHeight - currentHeight < monero_block_size)) {
407 + if (isRecovery && (nodeHeight - currentHeight < moneroBlockSize)) {
408 await setAsRecovered();
409 }
410
lib/src/domain/monero/monero_wallets_manager.dart
+35 -24
@@ -3,7 +3,7 @@ import 'dart:io';
3 import 'package:flutter/foundation.dart';
4 import 'package:hive/hive.dart';
5 import 'package:path_provider/path_provider.dart';
6 -import 'package:cw_monero/wallet_manager.dart' as moneroWalletManager;
6 +import 'package:cw_monero/wallet_manager.dart' as monero_wallet_manager;
7 import 'package:cake_wallet/src/domain/common/wallet_info.dart';
8 import 'package:cake_wallet/src/domain/common/wallet_type.dart';
9 import 'package:cake_wallet/src/domain/common/wallets_manager.dart';
@@ -24,54 +24,61 @@ Future<String> pathForWallet({String name}) async {
24 }
25
26 class MoneroWalletsManager extends WalletsManager {
27 + MoneroWalletsManager({@required this.walletInfoSource});
28 +
29 static const type = WalletType.monero;
30
31 Box<WalletInfo> walletInfoSource;
32
31 - MoneroWalletsManager({@required this.walletInfoSource});
32 -
33 + @override
34 Future<Wallet> create(String name, String password) async {
35 try {
36 const isRecovery = false;
37 final path = await pathForWallet(name: name);
38
38 - await moneroWalletManager.createWallet(path: path, password: password);
39 + await monero_wallet_manager.createWallet(path: path, password: password);
40
41 final wallet = await MoneroWallet.createdWallet(
41 - walletInfoSource: walletInfoSource, name: name, isRecovery: isRecovery)
42 - ..updateInfo();
42 + walletInfoSource: walletInfoSource,
43 + name: name,
44 + isRecovery: isRecovery);
45 + await wallet.updateInfo();
46
47 return wallet;
48 } catch (e) {
49 print('MoneroWalletsManager Error: $e');
47 - throw e;
50 + rethrow;
51 }
52 }
53
54 + @override
55 Future<Wallet> restoreFromSeed(
56 String name, String password, String seed, int restoreHeight) async {
57 try {
58 const isRecovery = true;
59 final path = await pathForWallet(name: name);
60
57 - await moneroWalletManager.restoreFromSeed(
61 + await monero_wallet_manager.restoreFromSeed(
62 path: path,
63 password: password,
64 seed: seed,
65 restoreHeight: restoreHeight);
66
63 - return await MoneroWallet.createdWallet(
67 + final wallet = await MoneroWallet.createdWallet(
68 walletInfoSource: walletInfoSource,
69 name: name,
70 isRecovery: isRecovery,
67 - restoreHeight: restoreHeight)
68 - ..updateInfo();
71 + restoreHeight: restoreHeight);
72 + await wallet.updateInfo();
73 +
74 + return wallet;
75 } catch (e) {
76 print('MoneroWalletsManager Error: $e');
71 - throw e;
77 + rethrow;
78 }
79 }
80
81 + @override
82 Future<Wallet> restoreFromKeys(
83 String name,
84 String password,
@@ -83,7 +90,7 @@ class MoneroWalletsManager extends WalletsManager {
90 const isRecovery = true;
91 final path = await pathForWallet(name: name);
92
86 - await moneroWalletManager.restoreFromKeys(
93 + await monero_wallet_manager.restoreFromKeys(
94 path: path,
95 password: password,
96 restoreHeight: restoreHeight,
@@ -95,40 +102,43 @@ class MoneroWalletsManager extends WalletsManager {
102 walletInfoSource: walletInfoSource,
103 name: name,
104 isRecovery: isRecovery,
98 - restoreHeight: restoreHeight)
99 - ..updateInfo();
105 + restoreHeight: restoreHeight);
106 + await wallet.updateInfo();
107
108 return wallet;
109 } catch (e) {
110 print('MoneroWalletsManager Error: $e');
104 - throw e;
111 + rethrow;
112 }
113 }
114
115 + @override
116 Future<Wallet> openWallet(String name, String password) async {
117 try {
118 final path = await pathForWallet(name: name);
111 - await moneroWalletManager.openWallet(path: path, password: password);
112 - final wallet = await MoneroWallet.load(walletInfoSource, name, type)
113 - ..updateInfo();
119 + monero_wallet_manager.openWallet(path: path, password: password);
120 + final wallet = await MoneroWallet.load(walletInfoSource, name, type);
121 + await wallet.updateInfo();
122
123 return wallet;
124 } catch (e) {
125 print('MoneroWalletsManager Error: $e');
118 - throw e;
126 + rethrow;
127 }
128 }
129
130 + @override
131 Future<bool> isWalletExit(String name) async {
132 try {
133 final path = await pathForWallet(name: name);
125 - return moneroWalletManager.isWalletExist(path: path);
134 + return monero_wallet_manager.isWalletExist(path: path);
135 } catch (e) {
136 print('MoneroWalletsManager Error: $e');
128 - throw e;
137 + rethrow;
138 }
139 }
140
141 + @override
142 Future remove(WalletDescription wallet) async {
143 final dir = await getApplicationDocumentsDirectory();
144 final root = dir.path.replaceAll('app_flutter', 'files');
@@ -153,8 +163,9 @@ class MoneroWalletsManager extends WalletsManager {
163
164 final id =
165 walletTypeToString(wallet.type).toLowerCase() + '_' + wallet.name;
156 - final info = walletInfoSource.values.firstWhere((info) => info.id == id, orElse: () => null);
157 -
166 + final info = walletInfoSource.values
167 + .firstWhere((info) => info.id == id, orElse: () => null);
168 +
169 await info?.delete();
170 }
171 }
lib/src/domain/monero/subaddress.dart
+7 -7
@@ -1,19 +1,19 @@
1 import 'package:cw_monero/structs/subaddress_row.dart';
2
3 class Subaddress {
4 - final int id;
5 - final String address;
6 - final String label;
7 -
4 Subaddress({this.id, this.address, this.label});
5
6 Subaddress.fromMap(Map map)
11 - : this.id = map['id'] == null ? 0 : int.parse(map['id']),
12 - this.address = map['address'] ?? '',
13 - this.label = map['label'] ?? '';
7 + : this.id = map['id'] == null ? 0 : int.parse(map['id'] as String),
8 + this.address = (map['address'] ?? '') as String,
9 + this.label = (map['label'] ?? '') as String;
10
11 Subaddress.fromRow(SubaddressRow row)
12 : this.id = row.getId(),
13 this.address = row.getAddress(),
14 this.label = row.getLabel();
15 +
16 + final int id;
17 + final String address;
18 + final String label;
19 }
lib/src/domain/monero/subaddress_list.dart
+14 -13
@@ -1,21 +1,21 @@
1 import 'package:flutter/services.dart';
2 import 'package:rxdart/rxdart.dart';
3 -import 'package:cw_monero/subaddress_list.dart' as subaddressListAPI;
3 +import 'package:cw_monero/subaddress_list.dart' as subaddress_list;
4 import 'package:cake_wallet/src/domain/monero/subaddress.dart';
5
6 class SubaddressList {
7 - get subaddresses => _subaddress.stream;
8 - BehaviorSubject<List<Subaddress>> _subaddress;
9 -
10 - bool _isRefreshing;
11 - bool _isUpdating;
12 -
7 SubaddressList() {
8 _isRefreshing = false;
9 _isUpdating = false;
10 _subaddress = BehaviorSubject<List<Subaddress>>();
11 }
12
13 + Observable<List<Subaddress>> get subaddresses => _subaddress.stream;
14 +
15 + BehaviorSubject<List<Subaddress>> _subaddress;
16 + bool _isRefreshing;
17 + bool _isUpdating;
18 +
19 Future update({int accountIndex}) async {
20 if (_isUpdating) {
21 return;
@@ -29,25 +29,26 @@ class SubaddressList {
29 _isUpdating = false;
30 } catch (e) {
31 _isUpdating = false;
32 - throw e;
32 + rethrow;
33 }
34 }
35
36 List<Subaddress> getAll() {
37 - return subaddressListAPI
37 + return subaddress_list
38 .getAllSubaddresses()
39 .map((subaddressRow) => Subaddress.fromRow(subaddressRow))
40 .toList();
41 }
42
43 Future addSubaddress({int accountIndex, String label}) async {
44 - await subaddressListAPI.addSubaddress(accountIndex: accountIndex, label: label);
44 + await subaddress_list.addSubaddress(
45 + accountIndex: accountIndex, label: label);
46 await update(accountIndex: accountIndex);
47 }
48
49 Future setLabelSubaddress(
50 {int accountIndex, int addressIndex, String label}) async {
50 - await subaddressListAPI.setLabelForSubaddress(
51 + await subaddress_list.setLabelForSubaddress(
52 accountIndex: accountIndex, addressIndex: addressIndex, label: label);
53 await update();
54 }
@@ -59,12 +60,12 @@ class SubaddressList {
60
61 try {
62 _isRefreshing = true;
62 - subaddressListAPI.refreshSubaddresses(accountIndex: accountIndex);
63 + subaddress_list.refreshSubaddresses(accountIndex: accountIndex);
64 _isRefreshing = false;
65 } on PlatformException catch (e) {
66 _isRefreshing = false;
67 print(e);
67 - throw e;
68 + rethrow;
69 }
70 }
71 }
lib/src/domain/monero/transaction_description.dart
+3 -3
@@ -4,6 +4,8 @@ part 'transaction_description.g.dart';
4
5 @HiveType()
6 class TransactionDescription extends HiveObject {
7 + TransactionDescription({this.id, this.recipientAddress});
8 +
9 static const boxName = 'TransactionDescriptions';
10
11 @HiveField(0)
@@ -11,6 +13,4 @@ class TransactionDescription extends HiveObject {
13
14 @HiveField(1)
15 String recipientAddress;
14 -
15 - TransactionDescription({this.id, this.recipientAddress});
16 -}
\ No newline at end of file
16 +}
lib/src/domain/services/user_service.dart
+2 -2
@@ -4,11 +4,11 @@ import 'package:cake_wallet/src/domain/common/secret_store_key.dart';
4 import 'package:cake_wallet/src/domain/common/encrypt.dart';
5
6 class UserService {
7 + UserService({this.sharedPreferences, this.secureStorage});
8 +
9 final FlutterSecureStorage secureStorage;
10 final SharedPreferences sharedPreferences;
11
10 - UserService({this.sharedPreferences, this.secureStorage});
11 -
12 Future setPassword(String password) async {
13 final key = generateStoreKeyFor(key: SecretStoreKey.pinCodePassword);
14
lib/src/domain/services/wallet_list_service.dart
+10 -10
@@ -15,21 +15,15 @@ import 'package:cake_wallet/src/domain/monero/monero_wallets_manager.dart';
15 import 'package:cake_wallet/src/domain/services/wallet_service.dart';
16
17 class WalletIsExistException implements Exception {
18 - String name;
19 -
18 WalletIsExistException(this.name);
19
20 + String name;
21 +
22 @override
23 String toString() => "Wallet with name $name is already exist!";
24 }
25
26 class WalletListService {
27 - final FlutterSecureStorage secureStorage;
28 - final WalletService walletService;
29 - final Box<WalletInfo> walletInfoSource;
30 - final SharedPreferences sharedPreferences;
31 - WalletsManager walletsManager;
32 -
27 WalletListService(
28 {this.secureStorage,
29 this.walletInfoSource,
@@ -37,6 +31,12 @@ class WalletListService {
31 @required this.walletService,
32 @required this.sharedPreferences});
33
34 + final FlutterSecureStorage secureStorage;
35 + final WalletService walletService;
36 + final Box<WalletInfo> walletInfoSource;
37 + final SharedPreferences sharedPreferences;
38 + WalletsManager walletsManager;
39 +
40 Future<List<WalletDescription>> getAll() async => walletInfoSource.values
41 .map((info) => WalletDescription(name: info.name, type: info.type))
42 .toList();
@@ -52,7 +52,7 @@ class WalletListService {
52
53 final password = Uuid().v4();
54 await saveWalletPassword(password: password, walletName: name);
55 -
55 +
56 final wallet = await walletsManager.create(name, password);
57
58 await onWalletChange(wallet);
@@ -131,7 +131,7 @@ class WalletListService {
131 final key = generateStoreKeyFor(
132 key: SecretStoreKey.moneroWalletPassword, walletName: walletName);
133 final encodedPassword = await secureStorage.read(key: key);
134 -
134 +
135 return decodeWalletPassword(password: encodedPassword);
136 }
137
lib/src/domain/services/wallet_service.dart
+49 -16
@@ -10,17 +10,40 @@ import 'package:cake_wallet/src/domain/common/pending_transaction.dart';
10 import 'package:cake_wallet/src/domain/common/node.dart';
11
12 class WalletService extends Wallet {
13 - Observable<Wallet> get onWalletChange => _onWalletChanged.stream;
13 + WalletService() {
14 + _currentWallet = null;
15 + walletType = WalletType.none;
16 + _syncStatus = BehaviorSubject<SyncStatus>();
17 + _onBalanceChange = BehaviorSubject<Balance>();
18 + _onWalletChanged = BehaviorSubject<Wallet>();
19 + }
20 +
21 + @override
22 Observable<Balance> get onBalanceChange => _onBalanceChange.stream;
23 +
24 + @override
25 Observable<SyncStatus> get syncStatus => _syncStatus.stream;
26 +
27 + @override
28 Observable<String> get onAddressChange => _currentWallet.onAddressChange;
29 +
30 + @override
31 Observable<String> get onNameChange => _currentWallet.onNameChange;
32 +
33 + @override
34 String get address => _currentWallet.address;
35 +
36 + @override
37 String get name => _currentWallet.name;
20 - SyncStatus get syncStatusValue => _syncStatus.value;
38 +
39 + @override
40 WalletType get walletType => _currentWallet.walletType;
41
23 - get currentWallet => _currentWallet;
42 + Observable<Wallet> get onWalletChange => _onWalletChanged.stream;
43 +
44 + SyncStatus get syncStatusValue => _syncStatus.value;
45 +
46 + Wallet get currentWallet => _currentWallet;
47
48 set currentWallet(Wallet wallet) {
49 _currentWallet = wallet;
@@ -44,55 +67,65 @@ class WalletService extends Wallet {
67 BehaviorSubject<SyncStatus> _syncStatus;
68 Wallet _currentWallet;
69
47 - WalletService() {
48 - _currentWallet = null;
49 - walletType = WalletType.none;
50 - _syncStatus = BehaviorSubject<SyncStatus>();
51 - _onBalanceChange = BehaviorSubject<Balance>();
52 - _onWalletChanged = BehaviorSubject<Wallet>();
53 - }
54 -
70 WalletDescription description;
71
72 + @override
73 WalletType getType() => WalletType.monero;
74
75 + @override
76 Future<String> getFilename() => _currentWallet.getFilename();
77
78 + @override
79 Future<String> getName() => _currentWallet.getName();
80
81 + @override
82 Future<String> getAddress() => _currentWallet.getAddress();
83
84 + @override
85 Future<String> getSeed() => _currentWallet.getSeed();
86
87 + @override
88 Future<Map<String, String>> getKeys() => _currentWallet.getKeys();
89
90 + @override
91 Future<String> getFullBalance() => _currentWallet.getFullBalance();
92
93 + @override
94 Future<String> getUnlockedBalance() => _currentWallet.getUnlockedBalance();
95
96 + @override
97 Future<int> getCurrentHeight() => _currentWallet.getCurrentHeight();
98
99 + @override
100 Future<int> getNodeHeight() => _currentWallet.getNodeHeight();
101
102 + @override
103 Future<bool> isConnected() => _currentWallet.isConnected();
104
105 + @override
106 Future close() => _currentWallet.close();
107
81 - Future connectToNode({Node node, bool useSSL = false, bool isLightWallet = false}) =>
108 + @override
109 + Future connectToNode(
110 + {Node node, bool useSSL = false, bool isLightWallet = false}) =>
111 _currentWallet.connectToNode(
83 - node: node,
84 - useSSL: useSSL,
85 - isLightWallet: isLightWallet);
112 + node: node, useSSL: useSSL, isLightWallet: isLightWallet);
113
114 + @override
115 Future startSync() => _currentWallet.startSync();
116
117 + @override
118 TransactionHistory getHistory() => _currentWallet.getHistory();
119
120 + @override
121 Future<PendingTransaction> createTransaction(
122 TransactionCreationCredentials credentials) =>
123 _currentWallet.createTransaction(credentials);
124
125 + @override
126 Future updateInfo() async => _currentWallet.updateInfo();
127
97 - Future rescan({int restoreHeight = 0}) async => _currentWallet.rescan(restoreHeight: restoreHeight);
128 + @override
129 + Future rescan({int restoreHeight = 0}) async =>
130 + _currentWallet.rescan(restoreHeight: restoreHeight);
131 }
lib/src/reactions/set_reactions.dart
+41 -29
@@ -1,6 +1,7 @@
1 import 'dart:async';
2 import 'package:flutter/foundation.dart';
3 import 'package:mobx/mobx.dart';
4 +import 'package:cake_wallet/src/domain/common/node.dart';
5 import 'package:cake_wallet/src/domain/common/sync_status.dart';
6 import 'package:cake_wallet/src/domain/services/wallet_service.dart';
7 import 'package:cake_wallet/src/start_updating_price.dart';
@@ -11,7 +12,12 @@ import 'package:cake_wallet/src/stores/price/price_store.dart';
12 import 'package:cake_wallet/src/stores/authentication/authentication_store.dart';
13 import 'package:cake_wallet/src/stores/login/login_store.dart';
14
14 -setReactions(
15 +Timer _reconnectionTimer;
16 +ReactionDisposer _connectToNodeDisposer;
17 +ReactionDisposer _onSyncStatusChangeDisposer;
18 +ReactionDisposer _onCurrentWalletChangeDisposer;
19 +
20 +void setReactions(
21 {@required SettingsStore settingsStore,
22 @required PriceStore priceStore,
23 @required SyncStore syncStore,
@@ -36,29 +42,44 @@ setReactions(
42 });
43 }
44
39 -connectToNode({SettingsStore settingsStore, WalletStore walletStore}) =>
40 - reaction((_) => settingsStore.node,
41 - (node) async => await walletStore.connectToNode(node: node));
45 +void connectToNode({SettingsStore settingsStore, WalletStore walletStore}) {
46 + _connectToNodeDisposer?.call();
47
43 -onSyncStatusChange(
44 - {SyncStore syncStore,
45 - WalletStore walletStore,
46 - SettingsStore settingsStore}) =>
47 - reaction((_) => syncStore.status, (status) async {
48 - if (status is ConnectedSyncStatus) {
49 - await walletStore.startSync();
50 - }
48 + _connectToNodeDisposer = reaction((_) => settingsStore.node,
49 + (Node node) async => await walletStore.connectToNode(node: node));
50 +}
51
52 - // Reconnect to the node if the app is not started sync after 30 seconds
53 - if (status is StartingSyncStatus) {
54 - await startReconnectionObserver(
55 - syncStore: syncStore, walletStore: walletStore);
56 - }
57 - });
52 +void onCurrentWalletChange(
53 + {WalletStore walletStore,
54 + SettingsStore settingsStore,
55 + PriceStore priceStore}) {
56 + _onCurrentWalletChangeDisposer?.call();
57
59 -Timer _reconnectionTimer;
58 + reaction((_) => walletStore.name, (String _) {
59 + walletStore.connectToNode(node: settingsStore.node);
60 + startUpdatingPrice(settingsStore: settingsStore, priceStore: priceStore);
61 + });
62 +}
63
61 -startReconnectionObserver({SyncStore syncStore, WalletStore walletStore}) {
64 +void onSyncStatusChange(
65 + {SyncStore syncStore,
66 + WalletStore walletStore,
67 + SettingsStore settingsStore}) {
68 + _onSyncStatusChangeDisposer?.call();
69 +
70 + reaction((_) => syncStore.status, (SyncStatus status) async {
71 + if (status is ConnectedSyncStatus) {
72 + await walletStore.startSync();
73 + }
74 +
75 + // Reconnect to the node if the app is not started sync after 30 seconds
76 + if (status is StartingSyncStatus) {
77 + startReconnectionObserver(syncStore: syncStore, walletStore: walletStore);
78 + }
79 + });
80 +}
81 +
82 +void startReconnectionObserver({SyncStore syncStore, WalletStore walletStore}) {
83 if (_reconnectionTimer != null) {
84 _reconnectionTimer.cancel();
85 }
@@ -75,12 +96,3 @@ startReconnectionObserver({SyncStore syncStore, WalletStore walletStore}) {
96 }
97 });
98 }
78 -
79 -onCurrentWalletChange(
80 - {WalletStore walletStore,
81 - SettingsStore settingsStore,
82 - PriceStore priceStore}) =>
83 - reaction((_) => walletStore.name, (_) {
84 - walletStore.connectToNode(node: settingsStore.node);
85 - startUpdatingPrice(settingsStore: settingsStore, priceStore: priceStore);
86 - });
lib/src/screens/accounts/account_list_page.dart
+15 -15
@@ -11,6 +11,7 @@ import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
11 import 'package:cake_wallet/src/screens/base_page.dart';
12
13 class AccountListPage extends BasePage {
14 + @override
15 String get title => S.current.accounts;
16
17 @override
@@ -21,8 +22,7 @@ class AccountListPage extends BasePage {
22 width: 28.0,
23 height: 28.0,
24 decoration: BoxDecoration(
24 - shape: BoxShape.circle,
25 - color: Theme.of(context).selectedRowColor),
25 + shape: BoxShape.circle, color: Theme.of(context).selectedRowColor),
26 child: Stack(
27 alignment: Alignment.center,
28 children: <Widget>[
@@ -35,7 +35,7 @@ class AccountListPage extends BasePage {
35 onPressed: () async {
36 await Navigator.of(context)
37 .pushNamed(Routes.accountCreation);
38 - await accountListStore.updateAccountList();
38 + accountListStore.updateAccountList();
39 },
40 child: Offstage()),
41 )
@@ -53,13 +53,10 @@ class AccountListPage extends BasePage {
53
54 return Container(
55 padding: EdgeInsets.only(top: 10, bottom: 20),
56 - child: Observer(
57 - builder: (_) {
58 - final accounts = accountListStore.accounts;
59 - return ListView.builder(
60 - itemCount: accounts == null
61 - ? 0
62 - : accounts.length,
56 + child: Observer(builder: (_) {
57 + final accounts = accountListStore.accounts;
58 + return ListView.builder(
59 + itemCount: accounts == null ? 0 : accounts.length,
60 itemBuilder: (BuildContext context, int index) {
61 final account = accounts[index];
62
@@ -78,7 +75,10 @@ class AccountListPage extends BasePage {
75 account.label,
76 style: TextStyle(
77 fontSize: 16.0,
81 - color: Theme.of(context).primaryTextTheme.headline.color),
78 + color: Theme.of(context)
79 + .primaryTextTheme
80 + .headline
81 + .color),
82 ),
83 onTap: () {
84 if (isCurrent) {
@@ -102,8 +102,9 @@ class AccountListPage extends BasePage {
102 color: Colors.blue,
103 icon: Icons.edit,
104 onTap: () async {
105 - await Navigator.of(context)
106 - .pushNamed(Routes.accountCreation, arguments: account);
105 + await Navigator.of(context).pushNamed(
106 + Routes.accountCreation,
107 + arguments: account);
108 // await accountListStore.updateAccountList().then((_) {
109 // if (isCurrent) walletStore.setAccount(accountListStore.accounts[index]);
110 // });
@@ -113,8 +114,7 @@ class AccountListPage extends BasePage {
114 );
115 });
116 });
116 - }
117 - ),
117 + }),
118 );
119 }
120 }
lib/src/screens/accounts/account_page.dart
+10 -8
@@ -10,22 +10,24 @@ import 'package:cake_wallet/src/domain/monero/account.dart';
10 import 'package:cake_wallet/palette.dart';
11
12 class AccountPage extends BasePage {
13 - String get title => 'Account';
13 + AccountPage({this.account});
14 +
15 final Account account;
16
16 - AccountPage({this.account});
17 + @override
18 + String get title => 'Account';
19
20 @override
21 Widget body(BuildContext context) => AccountForm(account);
22 }
23
24 class AccountForm extends StatefulWidget {
23 - final Account account;
24 -
25 AccountForm(this.account);
26
27 + final Account account;
28 +
29 @override
28 - createState() => AccountFormState();
30 + AccountFormState createState() => AccountFormState();
31 }
32
33 class AccountFormState extends State<AccountForm> {
@@ -61,8 +63,8 @@ class AccountFormState extends State<AccountForm> {
63 hintStyle: TextStyle(color: Theme.of(context).hintColor),
64 hintText: S.of(context).account,
65 focusedBorder: UnderlineInputBorder(
64 - borderSide: BorderSide(
65 - color: Palette.cakeGreen, width: 2.0)),
66 + borderSide:
67 + BorderSide(color: Palette.cakeGreen, width: 2.0)),
68 enabledBorder: UnderlineInputBorder(
69 borderSide: BorderSide(
70 color: Theme.of(context).focusColor, width: 1.0))),
@@ -88,7 +90,7 @@ class AccountFormState extends State<AccountForm> {
90 await accountListStore.addAccount(
91 label: _textController.text);
92 }
91 - Navigator.pop(context, _textController.text);
93 + Navigator.of(context).pop(_textController.text);
94 },
95 text:
96 widget.account != null ? 'Rename' : S.of(context).add,
lib/src/screens/address_book/address_book_page.dart
+87 -81
@@ -12,13 +12,18 @@ import 'package:cake_wallet/src/stores/address_book/address_book_store.dart';
12 import 'package:cake_wallet/src/screens/base_page.dart';
13
14 class AddressBookPage extends BasePage {
15 - bool get isModalBackButton => true;
16 - String get title => S.current.address_book;
17 - AppBarStyle get appBarStyle => AppBarStyle.withShadow;
15 + AddressBookPage({this.isEditable = true});
16
17 final bool isEditable;
18
21 - AddressBookPage({this.isEditable = true});
19 + @override
20 + bool get isModalBackButton => true;
21 +
22 + @override
23 + String get title => S.current.address_book;
24 +
25 + @override
26 + AppBarStyle get appBarStyle => AppBarStyle.withShadow;
27
28 @override
29 Widget trailing(BuildContext context) {
@@ -32,8 +37,7 @@ class AddressBookPage extends BasePage {
37 width: 28.0,
38 height: 28.0,
39 decoration: BoxDecoration(
35 - shape: BoxShape.circle,
36 - color: Theme.of(context).selectedRowColor),
40 + shape: BoxShape.circle, color: Theme.of(context).selectedRowColor),
41 child: Stack(
42 alignment: Alignment.center,
43 children: <Widget>[
@@ -79,16 +83,17 @@ class AddressBookPage extends BasePage {
83 return;
84 }
85
82 - bool isCopied = await showNameAndAddressDialog(context, contact.name, contact.address);
86 + final isCopied = await showNameAndAddressDialog(
87 + context, contact.name, contact.address);
88 +
89 if (isCopied) {
84 - Clipboard.setData(ClipboardData(text: contact.address));
90 + await Clipboard.setData(
91 + ClipboardData(text: contact.address));
92 Scaffold.of(context).showSnackBar(
93 SnackBar(
87 - content:
88 - Text('Copied to Clipboard'),
94 + content: Text('Copied to Clipboard'),
95 backgroundColor: Colors.green,
90 - duration:
91 - Duration(milliseconds: 1500),
96 + duration: Duration(milliseconds: 1500),
97 ),
98 );
99 }
@@ -117,48 +122,51 @@ class AddressBookPage extends BasePage {
122 ),
123 );
124
120 - return !isEditable ? content
121 - : Slidable(
122 - key: Key('1'),// Key(contact.id.toString()),
123 - actionPane: SlidableDrawerActionPane(),
124 - child: content,
125 - secondaryActions: <Widget>[
126 - IconSlideAction(
127 - caption: 'Edit',
128 - color: Colors.blue,
129 - icon: Icons.edit,
130 - onTap: () async {
131 - await Navigator.of(context)
132 - .pushNamed(Routes.addressBookAddContact, arguments: contact);
133 - await addressBookStore.updateContactList();
134 - },
135 - ),
136 - IconSlideAction(
137 - caption: 'Delete',
138 - color: Colors.red,
139 - icon: CupertinoIcons.delete,
140 - onTap: () async {
141 - await showAlertDialog(context).then((isDelete) async{
142 - if (isDelete != null && isDelete) {
143 - await addressBookStore.delete(contact: contact);
125 + return !isEditable
126 + ? content
127 + : Slidable(
128 + key: Key('${contact.key}'),
129 + actionPane: SlidableDrawerActionPane(),
130 + child: content,
131 + secondaryActions: <Widget>[
132 + IconSlideAction(
133 + caption: 'Edit',
134 + color: Colors.blue,
135 + icon: Icons.edit,
136 + onTap: () async {
137 + await Navigator.of(context).pushNamed(
138 + Routes.addressBookAddContact,
139 + arguments: contact);
140 await addressBookStore.updateContactList();
145 - }
146 - });
147 - },
148 - ),
149 - ],
150 - dismissal: SlidableDismissal(
151 - child: SlidableDrawerDismissal(),
152 - onDismissed: (actionType) async {
153 - await addressBookStore.delete(contact: contact);
154 - await addressBookStore.updateContactList();
155 - },
156 - onWillDismiss: (actionType) async {
157 - return await showAlertDialog(context);
158 - },
159 - ),
160 -
161 - );
141 + },
142 + ),
143 + IconSlideAction(
144 + caption: 'Delete',
145 + color: Colors.red,
146 + icon: CupertinoIcons.delete,
147 + onTap: () async {
148 + await showAlertDialog(context)
149 + .then((isDelete) async {
150 + if (isDelete != null && isDelete) {
151 + await addressBookStore.delete(
152 + contact: contact);
153 + await addressBookStore.updateContactList();
154 + }
155 + });
156 + },
157 + ),
158 + ],
159 + dismissal: SlidableDismissal(
160 + child: SlidableDrawerDismissal(),
161 + onDismissed: (actionType) async {
162 + await addressBookStore.delete(contact: contact);
163 + await addressBookStore.updateContactList();
164 + },
165 + onWillDismiss: (actionType) async {
166 + return await showAlertDialog(context);
167 + },
168 + ),
169 + );
170 }),
171 ));
172 }
@@ -220,42 +228,40 @@ class AddressBookPage extends BasePage {
228 ),
229 actions: <Widget>[
230 FlatButton(
223 - onPressed: () =>
224 - Navigator.pop(context, false),
231 + onPressed: () => Navigator.of(context).pop( false),
232 child: const Text('Cancel')),
233 FlatButton(
227 - onPressed: () =>
228 - Navigator.pop(context, true),
234 + onPressed: () => Navigator.of(context).pop(true),
235 child: const Text('Remove')),
236 ],
237 );
238 });
239 }
240
235 - showNameAndAddressDialog(BuildContext context, String name, String address) async {
241 + Future<bool> showNameAndAddressDialog(
242 + BuildContext context, String name, String address) async {
243 return await showDialog(
237 - context: context,
238 - builder: (BuildContext context) {
239 - return AlertDialog(
240 - title: Text(
241 - name,
242 - textAlign: TextAlign.center,
243 - style: TextStyle(fontWeight: FontWeight.bold),
244 - ),
245 - content: Text(
246 - address,
247 - textAlign: TextAlign.center,
248 - ),
249 - actions: <Widget>[
250 - FlatButton(
251 - onPressed: () => Navigator.of(context).pop(false),
252 - child: Text('Cancel')),
253 - FlatButton(
254 - onPressed: () => Navigator.of(context).pop(true),
255 - child: Text('Copy'))
256 - ],
257 - );
258 - }
259 - );
244 + context: context,
245 + builder: (BuildContext context) {
246 + return AlertDialog(
247 + title: Text(
248 + name,
249 + textAlign: TextAlign.center,
250 + style: TextStyle(fontWeight: FontWeight.bold),
251 + ),
252 + content: Text(
253 + address,
254 + textAlign: TextAlign.center,
255 + ),
256 + actions: <Widget>[
257 + FlatButton(
258 + onPressed: () => Navigator.of(context).pop(false),
259 + child: Text('Cancel')),
260 + FlatButton(
261 + onPressed: () => Navigator.of(context).pop(true),
262 + child: Text('Copy'))
263 + ],
264 + );
265 + });
266 }
267 }
lib/src/screens/address_book/contact_page.dart
+20 -16
@@ -12,22 +12,24 @@ import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
12 import 'package:cake_wallet/palette.dart';
13
14 class ContactPage extends BasePage {
15 - String get title => S.current.contact;
15 + ContactPage({this.contact});
16 +
17 final Contact contact;
18
18 - ContactPage({this.contact});
19 + @override
20 + String get title => S.current.contact;
21
22 @override
23 Widget body(BuildContext context) => ContactForm(contact);
24 }
25
26 class ContactForm extends StatefulWidget {
25 - final Contact contact;
26 -
27 ContactForm(this.contact);
28
29 + final Contact contact;
30 +
31 @override
30 - createState() => ContactFormState();
32 + State<ContactForm> createState() => ContactFormState();
33 }
34
35 class ContactFormState extends State<ContactForm> {
@@ -59,10 +61,11 @@ class ContactFormState extends State<ContactForm> {
61 super.dispose();
62 }
63
62 - _setCurrencyType(BuildContext context) async {
63 - String currencyType = CryptoCurrency.all[0].toString();
64 - CryptoCurrency selectedCurrency = CryptoCurrency.all[0];
65 - await showDialog(
64 + Future<void> _setCurrencyType(BuildContext context) async {
65 + var currencyType = CryptoCurrency.all[0].toString();
66 + var selectedCurrency = CryptoCurrency.all[0];
67 +
68 + await showDialog<void>(
69 context: context,
70 builder: (BuildContext context) {
71 return AlertDialog(
@@ -127,8 +130,8 @@ class ContactFormState extends State<ContactForm> {
130 hintStyle: TextStyle(color: Theme.of(context).hintColor),
131 hintText: S.of(context).contact_name,
132 focusedBorder: UnderlineInputBorder(
130 - borderSide: BorderSide(
131 - color: Palette.cakeGreen, width: 2.0)),
133 + borderSide:
134 + BorderSide(color: Palette.cakeGreen, width: 2.0)),
135 enabledBorder: UnderlineInputBorder(
136 borderSide: BorderSide(
137 color: Theme.of(context).focusColor, width: 1.0))),
@@ -153,8 +156,7 @@ class ContactFormState extends State<ContactForm> {
156 decoration: InputDecoration(
157 focusedBorder: UnderlineInputBorder(
158 borderSide: BorderSide(
156 - color: Palette.cakeGreen,
157 - width: 2.0)),
159 + color: Palette.cakeGreen, width: 2.0)),
160 enabledBorder: UnderlineInputBorder(
161 borderSide: BorderSide(
162 color: Theme.of(context).focusColor,
@@ -215,13 +217,15 @@ class ContactFormState extends State<ContactForm> {
217 } else {
218 widget.contact.name = _contactNameController.text;
219 widget.contact.address = _addressController.text;
218 - widget.contact.updateCryptoCurrency(currency: _selectectCrypto);
220 + widget.contact
221 + .updateCryptoCurrency(currency: _selectectCrypto);
222
220 - await addressBookStore.update(contact: widget.contact);
223 + await addressBookStore.update(
224 + contact: widget.contact);
225 }
226 Navigator.pop(context);
227 } catch (e) {
224 - await showDialog(
228 + await showDialog<void>(
229 context: context,
230 builder: (BuildContext context) {
231 return AlertDialog(
lib/src/screens/auth/auth_page.dart
+23 -5
@@ -7,13 +7,14 @@ import 'package:cake_wallet/src/stores/auth/auth_state.dart';
7 import 'package:cake_wallet/src/stores/auth/auth_store.dart';
8 import 'package:cake_wallet/src/screens/pin_code/pin_code.dart';
9
10 +typedef OnAuthenticationFinished = void Function(bool, AuthPageState);
11
12 class AuthPage extends StatefulWidget {
12 - final Function(bool, AuthPageState) onAuthenticationFinished;
13 - final bool closable;
14 -
13 AuthPage({this.onAuthenticationFinished, this.closable = true});
14
15 + final OnAuthenticationFinished onAuthenticationFinished;
16 + final bool closable;
17 +
18 @override
19 AuthPageState createState() => AuthPageState();
20 }
@@ -33,7 +34,7 @@ class AuthPageState extends State<AuthPage> {
34 Widget build(BuildContext context) {
35 final authStore = Provider.of<AuthStore>(context);
36
36 - reaction((_) => authStore.state, (state) {
37 + reaction((_) => authStore.state, (AuthState state) {
38 if (state is AuthenticatedSuccessfully) {
39 WidgetsBinding.instance.addPostFrameCallback((_) {
40 if (widget.onAuthenticationFinished != null) {
@@ -60,7 +61,24 @@ class AuthPageState extends State<AuthPage> {
61 });
62 }
63
63 - if (state is AuthenticationFailure || state is AuthenticationBanned) {
64 + if (state is AuthenticationFailure) {
65 + WidgetsBinding.instance.addPostFrameCallback((_) {
66 + _pinCodeKey.currentState.clear();
67 + _key.currentState.hideCurrentSnackBar();
68 + _key.currentState.showSnackBar(
69 + SnackBar(
70 + content: Text(S.of(context).failed_authentication(state.error)),
71 + backgroundColor: Colors.red,
72 + ),
73 + );
74 +
75 + if (widget.onAuthenticationFinished != null) {
76 + widget.onAuthenticationFinished(false, this);
77 + }
78 + });
79 + }
80 +
81 + if (state is AuthenticationBanned) {
82 WidgetsBinding.instance.addPostFrameCallback((_) {
83 _pinCodeKey.currentState.clear();
84 _key.currentState.hideCurrentSnackBar();
lib/src/screens/base_page.dart
+2 -2
@@ -28,7 +28,7 @@ abstract class BasePage extends StatelessWidget {
28 return null;
29 }
30
31 - ThemeChanger _themeChanger = Provider.of<ThemeChanger>(context);
31 + final _themeChanger = Provider.of<ThemeChanger>(context);
32 Image _closeButton, _backButton;
33
34 if (_themeChanger.getTheme() == Themes.darkTheme) {
@@ -70,7 +70,7 @@ abstract class BasePage extends StatelessWidget {
70
71 Widget floatingActionButton(BuildContext context) => null;
72
73 - Widget appBar(BuildContext context) {
73 + ObstructingPreferredSizeWidget appBar(BuildContext context) {
74 final _themeChanger = Provider.of<ThemeChanger>(context);
75 final _isDarkTheme = _themeChanger.getTheme() == Themes.darkTheme;
76
lib/src/screens/dashboard/dashboard_page.dart
+29 -36
@@ -1,6 +1,6 @@
1 import 'package:provider/provider.dart';
2 import 'package:intl/intl.dart';
3 -import 'package:date_range_picker/date_range_picker.dart' as DateRagePicker;
3 +import 'package:date_range_picker/date_range_picker.dart' as date_rage_picker;
4 import 'package:flutter/material.dart';
5 import 'package:flutter/cupertino.dart';
6 import 'package:flutter_mobx/flutter_mobx.dart';
@@ -86,24 +86,19 @@ class DashboardPage extends BasePage {
86 child: Image.asset('assets/images/exchange_icon.png',
87 color: Colors.white, height: 26, width: 22),
88 backgroundColor: Palette.floatingActionButton,
89 - onPressed: () async {
90 - final actionListStore = Provider.of<ActionListStore>(context);
91 -
92 - await Navigator.of(context, rootNavigator: true)
93 - .pushNamed(Routes.exchange);
94 - actionListStore.updateTradeList();
95 - });
89 + onPressed: () async => await Navigator.of(context, rootNavigator: true)
90 + .pushNamed(Routes.exchange));
91
92 void _presentWalletMenu(BuildContext bodyContext) {
93 final walletMenu = WalletMenu(bodyContext);
94
100 - showDialog(
95 + showDialog<void>(
96 builder: (_) => Picker(
97 items: walletMenu.items,
98 selectedAtIndex: -1,
99 title: S.of(bodyContext).wallet_menu,
100 pickerHeight: 510,
106 - onItemSelected: (item) =>
101 + onItemSelected: (String item) =>
102 walletMenu.action(walletMenu.items.indexOf(item))),
103 context: bodyContext);
104 }
@@ -136,8 +131,9 @@ class DashboardPageBodyState extends State<DashboardPageBody> {
131 return Observer(
132 key: _listObserverKey,
133 builder: (_) {
139 - final items =
140 - actionListStore.items == null ? [] : actionListStore.items;
134 + final items = actionListStore.items == null
135 + ? <String>[]
136 + : actionListStore.items;
137 final itemsCount = items.length + 2;
138
139 return ListView.builder(
@@ -225,19 +221,17 @@ class DashboardPageBodyState extends State<DashboardPageBody> {
221 builder: (_) {
222 final savedDisplayMode =
223 settingsStore.balanceDisplayMode;
228 - final displayMode =
229 - balanceStore.isReversing
230 - ? (savedDisplayMode ==
231 - BalanceDisplayMode
232 - .availableBalance
233 - ? BalanceDisplayMode
234 - .fullBalance
235 - : BalanceDisplayMode
236 - .availableBalance)
237 - : savedDisplayMode;
238 - var title = displayMode.toString();
239 -
240 - return Text(title,
224 + final displayMode = balanceStore
225 + .isReversing
226 + ? (savedDisplayMode ==
227 + BalanceDisplayMode
228 + .availableBalance
229 + ? BalanceDisplayMode.fullBalance
230 + : BalanceDisplayMode
231 + .availableBalance)
232 + : savedDisplayMode;
233 +
234 + return Text(displayMode.toString(),
235 style: TextStyle(
236 color: Palette.violet,
237 fontSize: 16));
@@ -248,16 +242,15 @@ class DashboardPageBodyState extends State<DashboardPageBody> {
242 final savedDisplayMode =
243 settingsStore.balanceDisplayMode;
244 var balance = '---';
251 - final displayMode =
252 - balanceStore.isReversing
253 - ? (savedDisplayMode ==
254 - BalanceDisplayMode
255 - .availableBalance
256 - ? BalanceDisplayMode
257 - .fullBalance
258 - : BalanceDisplayMode
259 - .availableBalance)
260 - : savedDisplayMode;
245 + final displayMode = balanceStore
246 + .isReversing
247 + ? (savedDisplayMode ==
248 + BalanceDisplayMode
249 + .availableBalance
250 + ? BalanceDisplayMode.fullBalance
251 + : BalanceDisplayMode
252 + .availableBalance)
253 + : savedDisplayMode;
254
255 if (displayMode ==
256 BalanceDisplayMode.availableBalance) {
@@ -499,7 +492,7 @@ class DashboardPageBodyState extends State<DashboardPageBody> {
492 onSelected: (item) async {
493 if (item == 2) {
494 final List<DateTime> picked =
502 - await DateRagePicker.showDatePicker(
495 + await date_rage_picker.showDatePicker(
496 context: context,
497 initialFirstDate: DateTime.now()
498 .subtract(Duration(days: 1)),
lib/src/screens/dashboard/date_section_raw.dart
+6 -4
@@ -4,19 +4,21 @@ import 'package:intl/intl.dart';
4 import 'package:cake_wallet/generated/i18n.dart';
5
6 class DateSectionRaw extends StatelessWidget {
7 + DateSectionRaw({this.date});
8 +
9 static final dateSectionDateFormat = DateFormat("d MMM");
10 static final nowDate = DateTime.now();
11
12 final DateTime date;
13
12 - DateSectionRaw({this.date});
13 -
14 @override
15 Widget build(BuildContext context) {
16 final diffDays = date.difference(nowDate).inDays;
17 - final isToday = nowDate.day == date.day && nowDate.month == date.month && nowDate.year == date.year;
17 + final isToday = nowDate.day == date.day &&
18 + nowDate.month == date.month &&
19 + nowDate.year == date.year;
20 var title = "";
19 -
21 +
22 if (isToday) {
23 title = S.of(context).today;
24 } else if (diffDays == 0) {
lib/src/screens/dashboard/trade_row.dart
+11 -8
@@ -4,13 +4,6 @@ import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
4 import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
5
6 class TradeRow extends StatelessWidget {
7 - final VoidCallback onTap;
8 - final ExchangeProviderDescription provider;
9 - final CryptoCurrency from;
10 - final CryptoCurrency to;
11 - final String createdAtFormattedDate;
12 - final String formattedAmount;
13 -
7 TradeRow(
8 {this.provider,
9 this.from,
@@ -19,6 +12,13 @@ class TradeRow extends StatelessWidget {
12 this.formattedAmount,
13 @required this.onTap});
14
15 + final VoidCallback onTap;
16 + final ExchangeProviderDescription provider;
17 + final CryptoCurrency from;
18 + final CryptoCurrency to;
19 + final String createdAtFormattedDate;
20 + final String formattedAmount;
21 +
22 @override
23 Widget build(BuildContext context) {
24 final amountCrypto = provider == ExchangeProviderDescription.xmrto
@@ -48,7 +48,10 @@ class TradeRow extends StatelessWidget {
48 Text('${from.toString()} → ${to.toString()}',
49 style: TextStyle(
50 fontSize: 16,
51 - color: Theme.of(context).primaryTextTheme.subhead.color)),
51 + color: Theme.of(context)
52 + .primaryTextTheme
53 + .subhead
54 + .color)),
55 formattedAmount != null
56 ? Text(formattedAmount + ' ' + amountCrypto,
57 style: const TextStyle(
lib/src/screens/dashboard/transaction_raw.dart
+11 -8
@@ -4,13 +4,6 @@ import 'package:cake_wallet/src/domain/common/transaction_direction.dart';
4 import 'package:cake_wallet/generated/i18n.dart';
5
6 class TransactionRow extends StatelessWidget {
7 - final VoidCallback onTap;
8 - final TransactionDirection direction;
9 - final String formattedDate;
10 - final String formattedAmount;
11 - final String formattedFiatAmount;
12 - final bool isPending;
13 -
7 TransactionRow(
8 {this.direction,
9 this.formattedDate,
@@ -19,6 +12,13 @@ class TransactionRow extends StatelessWidget {
12 this.isPending,
13 @required this.onTap});
14
15 + final VoidCallback onTap;
16 + final TransactionDirection direction;
17 + final String formattedDate;
18 + final String formattedAmount;
19 + final String formattedFiatAmount;
20 + final bool isPending;
21 +
22 @override
23 Widget build(BuildContext context) {
24 return InkWell(
@@ -53,7 +53,10 @@ class TransactionRow extends StatelessWidget {
53 (isPending ? S.of(context).pending : ''),
54 style: TextStyle(
55 fontSize: 16,
56 - color: Theme.of(context).primaryTextTheme.subhead.color)),
56 + color: Theme.of(context)
57 + .primaryTextTheme
58 + .subhead
59 + .color)),
60 Text(formattedAmount,
61 style: const TextStyle(
62 fontSize: 16, color: Palette.purpleBlue))
lib/src/screens/dashboard/wallet_menu.dart
+9 -7
@@ -1,10 +1,13 @@
1 import 'package:flutter/material.dart';
2 import 'package:cake_wallet/routes.dart';
3 import 'package:provider/provider.dart';
4 -import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
4 import 'package:cake_wallet/generated/i18n.dart';
5 +import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
6 +import 'package:cake_wallet/src/screens/auth/auth_page.dart';
7
8 class WalletMenu {
9 + WalletMenu(this.context);
10 +
11 final List<String> items = [
12 S.current.reconnect,
13 S.current.rescan,
@@ -14,9 +17,8 @@ class WalletMenu {
17 S.current.accounts,
18 S.current.address_book_menu
19 ];
17 - final BuildContext context;
20
19 - WalletMenu(this.context);
21 + final BuildContext context;
22
23 void action(int index) {
24 switch (index) {
@@ -32,7 +34,7 @@ class WalletMenu {
34 break;
35 case 3:
36 Navigator.of(context).pushNamed(Routes.auth,
35 - arguments: (isAuthenticatedSuccessfully, auth) =>
37 + arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) =>
38 isAuthenticatedSuccessfully
39 ? Navigator.of(auth.context).popAndPushNamed(Routes.seed)
40 : null);
@@ -40,7 +42,7 @@ class WalletMenu {
42 break;
43 case 4:
44 Navigator.of(context).pushNamed(Routes.auth,
43 - arguments: (isAuthenticatedSuccessfully, auth) =>
45 + arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) =>
46 isAuthenticatedSuccessfully
47 ? Navigator.of(auth.context)
48 .popAndPushNamed(Routes.showKeys)
@@ -57,10 +59,10 @@ class WalletMenu {
59 }
60 }
61
60 - Future _presentReconnectAlert(BuildContext context) async {
62 + Future<void> _presentReconnectAlert(BuildContext context) async {
63 final walletStore = Provider.of<WalletStore>(context);
64
63 - await showDialog(
65 + await showDialog<void>(
66 context: context,
67 builder: (BuildContext context) {
68 return AlertDialog(
lib/src/screens/disclaimer/disclaimer_page.dart
+36 -33
@@ -8,10 +8,10 @@ import 'package:cake_wallet/src/screens/base_page.dart';
8 import 'package:cake_wallet/src/widgets/primary_button.dart';
9
10 class DisclaimerPage extends BasePage {
11 - final bool isReadOnly;
12 -
11 DisclaimerPage({this.isReadOnly = false});
12
13 + final bool isReadOnly;
14 +
15 @override
16 bool get isModalBackButton => false;
17
@@ -23,25 +23,25 @@ class DisclaimerPage extends BasePage {
23 }
24
25 class DisclaimerPageBody extends StatefulWidget {
26 - final bool isReadOnly;
27 -
26 DisclaimerPageBody({this.isReadOnly = true});
27
28 + final bool isReadOnly;
29 +
30 @override
31 - createState() => DisclaimerBodyState(false);
31 + DisclaimerBodyState createState() => DisclaimerBodyState(false);
32 }
33
34 class DisclaimerBodyState extends State<DisclaimerPageBody> {
35 - static const xmrto_url = 'https://xmr.to/app_static/html/tos.html';
36 - static const changenow_url = 'https://changenow.io/terms-of-use';
35 + DisclaimerBodyState(this._isAccepted);
36
38 - bool _isAccepted;
37 + static const xmrtoUrl = 'https://xmr.to/app_static/html/tos.html';
38 + static const changenowUrl = 'https://changenow.io/terms-of-use';
39 +
40 + final bool _isAccepted;
41 bool _checked = false;
42 String _fileText = '';
43
42 - DisclaimerBodyState(this._isAccepted);
43 -
44 - launchUrl(String url) async {
44 + Future<void> launchUrl(String url) async {
45 if (await canLaunch(url)) await launch(url);
46 }
47
@@ -50,8 +50,8 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
50 setState(() {});
51 }
52
53 - _showAlertDialog(BuildContext context) async {
54 - await showDialog(
53 + Future<void> _showAlertDialog(BuildContext context) async {
54 + await showDialog<void>(
55 context: context,
56 builder: (BuildContext context) {
57 return AlertDialog(
@@ -66,7 +66,7 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
66 actions: <Widget>[
67 FlatButton(
68 onPressed: () {
69 - Navigator.pop(context);
69 + Navigator.of(context).pop();
70 },
71 child: Text('OK')),
72 ],
@@ -74,9 +74,7 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
74 });
75 }
76
77 - _afterLayout(_) {
78 - _showAlertDialog(context);
79 - }
77 + void _afterLayout(Duration _) => _showAlertDialog(context);
78
79 @override
80 void initState() {
@@ -87,7 +85,6 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
85
86 @override
87 Widget build(BuildContext context) {
90 -
88 return Column(
89 children: <Widget>[
90 SizedBox(height: 10.0),
@@ -166,9 +163,9 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
163 children: <Widget>[
164 Expanded(
165 child: GestureDetector(
169 - onTap: () => launchUrl(xmrto_url),
166 + onTap: () => launchUrl(xmrtoUrl),
167 child: Text(
171 - xmrto_url,
168 + xmrtoUrl,
169 textAlign: TextAlign.left,
170 style: TextStyle(
171 color: Colors.blue,
@@ -187,17 +184,17 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
184 children: <Widget>[
185 Expanded(
186 child: GestureDetector(
190 - onTap: () => launchUrl(changenow_url),
191 - child: Text(
192 - changenow_url,
193 - textAlign: TextAlign.left,
194 - style: TextStyle(
195 - color: Colors.blue,
196 - fontSize: 14.0,
197 - fontWeight: FontWeight.normal,
198 - decoration: TextDecoration.underline),
199 - ),
200 - ))
187 + onTap: () => launchUrl(changenowUrl),
188 + child: Text(
189 + changenowUrl,
190 + textAlign: TextAlign.left,
191 + style: TextStyle(
192 + color: Colors.blue,
193 + fontSize: 14.0,
194 + fontWeight: FontWeight.normal,
195 + decoration: TextDecoration.underline),
196 + ),
197 + ))
198 ],
199 ),
200 SizedBox(
@@ -288,8 +285,14 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
285 child: PrimaryButton(
286 onPressed: _checked ? () {} : null,
287 text: 'Accept',
291 - color: Theme.of(context).primaryTextTheme.button.backgroundColor,
292 - borderColor: Theme.of(context).primaryTextTheme.button.decorationColor,
288 + color: Theme.of(context)
289 + .primaryTextTheme
290 + .button
291 + .backgroundColor,
292 + borderColor: Theme.of(context)
293 + .primaryTextTheme
294 + .button
295 + .decorationColor,
296 ),
297 )
298 : Offstage(),
lib/src/screens/exchange/exchange_page.dart
+26 -21
@@ -6,8 +6,9 @@ import 'package:provider/provider.dart';
6 import 'package:cake_wallet/palette.dart';
7 import 'package:cake_wallet/routes.dart';
8 import 'package:cake_wallet/generated/i18n.dart';
9 -import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
9 import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
10 +import 'package:cake_wallet/src/domain/exchange/exchange_provider.dart';
11 +import 'package:cake_wallet/src/domain/exchange/exchange_provider_description.dart';
12 import 'package:cake_wallet/src/domain/exchange/xmrto/xmrto_exchange_provider.dart';
13 import 'package:cake_wallet/src/stores/exchange/exchange_trade_state.dart';
14 import 'package:cake_wallet/src/stores/exchange/limits_state.dart';
@@ -20,15 +21,14 @@ import 'package:cake_wallet/src/widgets/picker.dart';
21 import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
22
23 class ExchangePage extends BasePage {
24 + @override
25 String get title => S.current.exchange;
26
27 @override
28 bool get isModalBackButton => true;
29
28 - final Image arrowBottomPurple = Image.asset(
29 - 'assets/images/arrow_bottom_purple_icon.png',
30 - height: 8,
31 - );
30 + final Image arrowBottomPurple =
31 + Image.asset('assets/images/arrow_bottom_purple_icon.png', height: 8);
32
33 @override
34 Widget middle(BuildContext context) {
@@ -93,12 +93,12 @@ class ExchangePage extends BasePage {
93 final items = exchangeStore.providersForCurrentPair();
94 final selectedItem = items.indexOf(exchangeStore.provider);
95
96 - showDialog(
96 + showDialog<void>(
97 builder: (_) => Picker(
98 items: items,
99 selectedAtIndex: selectedItem,
100 title: S.of(context).change_exchange_provider,
101 - onItemSelected: (provider) =>
101 + onItemSelected: (ExchangeProvider provider) =>
102 exchangeStore.changeProvider(provider: provider)),
103 context: context);
104 }
@@ -253,8 +253,9 @@ class ExchangeFormState extends State<ExchangeForm> {
253 builder: (_) => LoadingPrimaryButton(
254 text: S.of(context).exchange,
255 onPressed: () {
256 - if (_formKey.currentState.validate())
256 + if (_formKey.currentState.validate()) {
257 exchangeStore.createTrade();
258 + }
259 },
260 color: Theme.of(context)
261 .primaryTextTheme
@@ -327,34 +328,38 @@ class ExchangeFormState extends State<ExchangeForm> {
328
329 reaction(
330 (_) => walletStore.name,
330 - (_) => _onWalletNameChange(
331 + (String _) => _onWalletNameChange(
332 walletStore, store.receiveCurrency, receiveKey));
333
334 reaction(
335 (_) => walletStore.name,
335 - (_) => _onWalletNameChange(
336 + (String _) => _onWalletNameChange(
337 walletStore, store.depositCurrency, depositKey));
338
338 - reaction((_) => store.receiveCurrency,
339 - (currency) => _onCurrencyChange(currency, walletStore, receiveKey));
339 + reaction(
340 + (_) => store.receiveCurrency,
341 + (CryptoCurrency currency) =>
342 + _onCurrencyChange(currency, walletStore, receiveKey));
343
341 - reaction((_) => store.depositCurrency,
342 - (currency) => _onCurrencyChange(currency, walletStore, depositKey));
344 + reaction(
345 + (_) => store.depositCurrency,
346 + (CryptoCurrency currency) =>
347 + _onCurrencyChange(currency, walletStore, depositKey));
348
344 - reaction((_) => store.depositAmount, (amount) {
349 + reaction((_) => store.depositAmount, (String amount) {
350 if (depositKey.currentState.amountController.text != amount) {
351 depositKey.currentState.amountController.text = amount;
352 }
353 });
354
350 - reaction((_) => store.receiveAmount, (amount) {
355 + reaction((_) => store.receiveAmount, (String amount) {
356 if (receiveKey.currentState.amountController.text !=
357 store.receiveAmount) {
358 receiveKey.currentState.amountController.text = amount;
359 }
360 });
361
357 - reaction((_) => store.provider, (provider) {
362 + reaction((_) => store.provider, (ExchangeProvider provider) {
363 final isReversed = provider is XMRTOExchangeProvider;
364
365 if (isReversed) {
@@ -373,10 +378,10 @@ class ExchangeFormState extends State<ExchangeForm> {
378 receiveKey.currentState.changeIsAmountEstimated(!isReversed);
379 });
380
376 - reaction((_) => store.tradeState, (state) {
381 + reaction((_) => store.tradeState, (ExchangeTradeState state) {
382 if (state is TradeIsCreatedFailure) {
383 WidgetsBinding.instance.addPostFrameCallback((_) {
379 - showDialog(
384 + showDialog<void>(
385 context: context,
386 builder: (BuildContext context) {
387 return AlertDialog(
@@ -397,7 +402,7 @@ class ExchangeFormState extends State<ExchangeForm> {
402 }
403 });
404
400 - reaction((_) => store.limitsState, (state) {
405 + reaction((_) => store.limitsState, (LimitsState state) {
406 final isXMRTO = store.provider is XMRTOExchangeProvider;
407 String min;
408 String max;
@@ -444,7 +449,7 @@ class ExchangeFormState extends State<ExchangeForm> {
449 }
450 });
451
447 - reaction((_) => walletStore.address, (address) {
452 + reaction((_) => walletStore.address, (String address) {
453 if (store.depositCurrency == CryptoCurrency.xmr) {
454 depositKey.currentState.changeAddress(address: address);
455 }
lib/src/screens/exchange/widgets/exchange_card.dart
+40 -27
@@ -7,18 +7,6 @@ import 'package:cake_wallet/src/widgets/picker.dart';
7 import 'package:cake_wallet/src/widgets/address_text_field.dart';
8
9 class ExchangeCard extends StatefulWidget {
10 - final List<CryptoCurrency> currencies;
11 - final Function(CryptoCurrency) onCurrencySelected;
12 - final CryptoCurrency initialCurrency;
13 - final String initialWalletName;
14 - final String initialAddress;
15 - final bool initialIsAmountEditable;
16 - final bool initialIsAddressEditable;
17 - final bool isAmountEstimated;
18 - final Image imageArrow;
19 - final FormFieldValidator<String> currencyValueValidator;
20 - final FormFieldValidator<String> addressTextFieldValidator;
21 -
10 ExchangeCard(
11 {Key key,
12 this.initialCurrency,
@@ -34,8 +22,20 @@ class ExchangeCard extends StatefulWidget {
22 this.addressTextFieldValidator})
23 : super(key: key);
24
25 + final List<CryptoCurrency> currencies;
26 + final Function(CryptoCurrency) onCurrencySelected;
27 + final CryptoCurrency initialCurrency;
28 + final String initialWalletName;
29 + final String initialAddress;
30 + final bool initialIsAmountEditable;
31 + final bool initialIsAddressEditable;
32 + final bool isAmountEstimated;
33 + final Image imageArrow;
34 + final FormFieldValidator<String> currencyValueValidator;
35 + final FormFieldValidator<String> addressTextFieldValidator;
36 +
37 @override
38 - createState() => ExchangeCardState();
38 + ExchangeCardState createState() => ExchangeCardState();
39 }
40
41 class ExchangeCardState extends State<ExchangeCard> {
@@ -102,7 +102,6 @@ class ExchangeCardState extends State<ExchangeCard> {
102
103 @override
104 Widget build(BuildContext context) {
105 -
105 return Container(
106 padding: EdgeInsets.fromLTRB(22, 15, 22, 30),
107 width: double.infinity,
@@ -150,7 +149,10 @@ class ExchangeCardState extends State<ExchangeCard> {
149 style: TextStyle(
150 fontWeight: FontWeight.bold,
151 fontSize: 24,
153 - color: Theme.of(context).primaryTextTheme.title.color)),
152 + color: Theme.of(context)
153 + .primaryTextTheme
154 + .title
155 + .color)),
156 widget.imageArrow
157 ]),
158 _walletName != null
@@ -173,7 +175,10 @@ class ExchangeCardState extends State<ExchangeCard> {
175 textAlign: TextAlign.right,
176 keyboardType: TextInputType.numberWithOptions(
177 signed: false, decimal: false),
176 - inputFormatters: [BlacklistingTextInputFormatter(new RegExp('[\\-|\\ |\\,]'))],
178 + inputFormatters: [
179 + BlacklistingTextInputFormatter(
180 + RegExp('[\\-|\\ |\\,]'))
181 + ],
182 decoration: InputDecoration(
183 hintStyle: TextStyle(
184 color: Theme.of(context).cardTheme.color,
@@ -182,15 +187,14 @@ class ExchangeCardState extends State<ExchangeCard> {
187 hintText: '0.00000000',
188 focusedBorder: UnderlineInputBorder(
189 borderSide: BorderSide(
185 - color: Palette.cakeGreen,
186 - width: 2.0)),
190 + color: Palette.cakeGreen, width: 2.0)),
191 enabledBorder: UnderlineInputBorder(
192 borderSide: BorderSide(
193 color: _isAmountEditable
194 ? Palette.deepPurple
195 : Theme.of(context).focusColor,
196 width: 1.0))),
193 - validator: widget.currencyValueValidator),
197 + validator: widget.currencyValueValidator),
198 SizedBox(height: 5),
199 SizedBox(
200 height: 15,
@@ -201,21 +205,29 @@ class ExchangeCardState extends State<ExchangeCard> {
205 children: <Widget>[
206 _min != null
207 ? Text(
204 - S.of(context).min_value(_min, _selectedCurrency.toString()),
208 + S.of(context).min_value(
209 + _min, _selectedCurrency.toString()),
210 style: TextStyle(
211 fontSize: 10,
212 height: 1.2,
208 - color: Theme.of(context).primaryTextTheme.subtitle.color),
213 + color: Theme.of(context)
214 + .primaryTextTheme
215 + .subtitle
216 + .color),
217 )
218 : SizedBox(),
219 _min != null ? SizedBox(width: 10) : SizedBox(),
220 _max != null
221 ? Text(
214 - S.of(context).max_value(_max, _selectedCurrency.toString()),
222 + S.of(context).max_value(
223 + _max, _selectedCurrency.toString()),
224 style: TextStyle(
225 fontSize: 10,
226 height: 1.2,
218 - color: Theme.of(context).primaryTextTheme.subtitle.color))
227 + color: Theme.of(context)
228 + .primaryTextTheme
229 + .subtitle
230 + .color))
231 : SizedBox(),
232 ]),
233 ),
@@ -248,14 +260,15 @@ class ExchangeCardState extends State<ExchangeCard> {
260 }
261
262 void _presentPicker(BuildContext context) {
251 - showDialog(
263 + showDialog<void>(
264 builder: (_) => Picker(
265 items: widget.currencies,
266 selectedAtIndex: widget.currencies.indexOf(_selectedCurrency),
267 title: S.of(context).change_currency,
256 - onItemSelected: (item) => widget.onCurrencySelected != null
257 - ? widget.onCurrencySelected(item)
258 - : null),
268 + onItemSelected: (CryptoCurrency item) =>
269 + widget.onCurrencySelected != null
270 + ? widget.onCurrencySelected(item)
271 + : null),
272 context: context);
273 }
274 }
lib/src/screens/exchange_trade/exchange_confirm_page.dart
+3 -2
@@ -8,11 +8,12 @@ import 'package:cake_wallet/src/screens/base_page.dart';
8 import 'package:cake_wallet/src/domain/exchange/trade.dart';
9
10 class ExchangeConfirmPage extends BasePage {
11 - String get title => S.current.copy_id;
11 + ExchangeConfirmPage({@required this.trade});
12
13 final Trade trade;
14
15 - ExchangeConfirmPage({@required this.trade});
15 + @override
16 + String get title => S.current.copy_id;
17
18 @override
19 Widget body(BuildContext context) {
lib/src/screens/exchange_trade/exchange_trade_page.dart
+5 -4
@@ -20,6 +20,7 @@ import 'package:cake_wallet/src/widgets/primary_button.dart';
20 import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
21
22 class ExchangeTradePage extends BasePage {
23 + @override
24 String get title => S.current.exchange;
25
26 @override
@@ -28,7 +29,7 @@ class ExchangeTradePage extends BasePage {
29
30 class ExchangeTradeForm extends StatefulWidget {
31 @override
31 - createState() => ExchangeTradeState();
32 + ExchangeTradeState createState() => ExchangeTradeState();
33 }
34
35 class ExchangeTradeState extends State<ExchangeTradeForm> {
@@ -330,10 +331,10 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
331
332 final sendStore = Provider.of<SendStore>(context);
333
333 - reaction((_) => sendStore.state, (state) {
334 + reaction((_) => sendStore.state, (SendingState state) {
335 if (state is SendingFailed) {
336 WidgetsBinding.instance.addPostFrameCallback((_) {
336 - showDialog(
337 + showDialog<void>(
338 context: context,
339 builder: (BuildContext context) {
340 return AlertDialog(
@@ -351,7 +352,7 @@ class ExchangeTradeState extends State<ExchangeTradeForm> {
352
353 if (state is TransactionCreatedSuccessfully) {
354 WidgetsBinding.instance.addPostFrameCallback((_) {
354 - showDialog(
355 + showDialog<void>(
356 context: context,
357 builder: (BuildContext context) {
358 return AlertDialog(
lib/src/screens/exchange_trade/widgets/copy_button.dart
+16 -16
@@ -2,29 +2,29 @@ import 'package:flutter/cupertino.dart';
2 import 'package:flutter/material.dart';
3
4 class CopyButton extends StatelessWidget {
5 + const CopyButton(
6 + {@required this.onPressed,
7 + @required this.text,
8 + @required this.color,
9 + @required this.borderColor});
10
11 final VoidCallback onPressed;
12 final Color color;
13 final Color borderColor;
14 final String text;
15
11 - const CopyButton({
12 - @required this.onPressed,
13 - @required this.text,
14 - @required this.color,
15 - @required this.borderColor});
16 -
16 @override
17 Widget build(BuildContext context) {
18 return ButtonTheme(
20 - minWidth: double.infinity,
21 - height: 44.0,
22 - child: FlatButton(
23 - onPressed: onPressed,
24 - color: color,
25 - shape: RoundedRectangleBorder(side: BorderSide(color: borderColor), borderRadius: BorderRadius.circular(10.0)),
26 - child: Text(text, style: TextStyle(fontSize: 14.0)),
27 - )
28 - );
19 + minWidth: double.infinity,
20 + height: 44.0,
21 + child: FlatButton(
22 + onPressed: onPressed,
23 + color: color,
24 + shape: RoundedRectangleBorder(
25 + side: BorderSide(color: borderColor),
26 + borderRadius: BorderRadius.circular(10.0)),
27 + child: Text(text, style: TextStyle(fontSize: 14.0)),
28 + ));
29 }
30 -}
\ No newline at end of file
30 +}
lib/src/screens/exchange_trade/widgets/timer_widget.dart
+7 -6
@@ -3,24 +3,24 @@ import 'dart:async';
3 import 'package:cake_wallet/generated/i18n.dart';
4
5 class TimerWidget extends StatefulWidget {
6 + TimerWidget(this.expiratedAt, {this.color = Colors.black});
7 +
8 final DateTime expiratedAt;
9 final Color color;
10
9 - TimerWidget(this.expiratedAt, {this.color = Colors.black});
10 -
11 @override
12 - createState() => TimerWidgetState();
12 + TimerWidgetState createState() => TimerWidgetState();
13 }
14
15 class TimerWidgetState extends State<TimerWidget> {
16 + TimerWidgetState();
17 +
18 int _leftSeconds;
19 int _minutes;
20 int _seconds;
21 bool _isExpired;
22 Timer _timer;
23
22 - TimerWidgetState();
23 -
24 @override
25 void initState() {
26 super.initState();
@@ -52,7 +52,8 @@ class TimerWidgetState extends State<TimerWidget> {
52 @override
53 Widget build(BuildContext context) {
54 return _isExpired
55 - ? Text(S.of(context).expired, style: TextStyle(fontSize: 14.0, color: Colors.red))
55 + ? Text(S.of(context).expired,
56 + style: TextStyle(fontSize: 14.0, color: Colors.red))
57 : Text(
58 S.of(context).time(_minutes.toString(), _seconds.toString()),
59 style: TextStyle(fontSize: 14.0, color: widget.color),
lib/src/screens/faq/faq_page.dart
+12 -21
@@ -7,14 +7,16 @@ import 'package:cake_wallet/src/stores/settings/settings_store.dart';
7 import 'package:cake_wallet/src/screens/base_page.dart';
8
9 class FaqPage extends BasePage {
10 + @override
11 String get title => S.current.faq;
12
13 @override
14 Widget body(BuildContext context) {
14 -
15 return FutureBuilder(
16 builder: (context, snapshot) {
17 - var faqItems = json.decode(snapshot.data.toString());
17 + final faqItems = (json.decode(snapshot.data.toString())
18 + as List<Map<String, String>>) ??
19 + <Map<String, String>>[];
20
21 return ListView.separated(
22 itemBuilder: (BuildContext context, int index) {
@@ -22,34 +24,24 @@ class FaqPage extends BasePage {
24 final itemChild = faqItems[index]["answer"];
25
26 return ExpansionTile(
25 - title: Text(
26 - itemTitle
27 - ),
27 + title: Text(itemTitle),
28 children: <Widget>[
29 Row(
30 mainAxisAlignment: MainAxisAlignment.start,
31 children: <Widget>[
32 Expanded(
33 child: Container(
34 - padding: EdgeInsets.only(
35 - left: 15.0,
36 - right: 15.0
37 - ),
38 - child: Text(
39 - itemChild,
40 - ),
41 - )
42 - )
34 + padding: EdgeInsets.only(left: 15.0, right: 15.0),
35 + child: Text(itemChild),
36 + ))
37 ],
38 )
39 ],
40 );
41 },
48 - separatorBuilder: (_, __) => Divider(
49 - color: Theme.of(context).dividerTheme.color,
50 - height: 1.0,
51 - ),
52 - itemCount: faqItems == null ? 0 : faqItems.length,
42 + separatorBuilder: (_, __) =>
43 + Divider(color: Theme.of(context).dividerTheme.color, height: 1.0),
44 + itemCount: faqItems.length,
45 );
46 },
47 future: rootBundle.loadString(getFaqPath(context)),
@@ -86,5 +78,4 @@ class FaqPage extends BasePage {
78 return 'assets/faq/faq_en.json';
79 }
80 }
89 -
90 -}
\ No newline at end of file
81 +}
lib/src/screens/new_wallet/new_wallet_page.dart
+11 -10
@@ -15,24 +15,25 @@ import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
15 import 'package:cake_wallet/palette.dart';
16
17 class NewWalletPage extends BasePage {
18 + NewWalletPage(
19 + {@required this.walletsService,
20 + @required this.walletService,
21 + @required this.sharedPreferences});
22 +
23 final WalletListService walletsService;
24 final WalletService walletService;
25 final SharedPreferences sharedPreferences;
26
27 + @override
28 String get title => S.current.new_wallet;
29
24 - NewWalletPage(
25 - {@required this.walletsService,
26 - @required this.walletService,
27 - @required this.sharedPreferences});
28 -
30 @override
31 Widget body(BuildContext context) => WalletNameForm();
32 }
33
34 class WalletNameForm extends StatefulWidget {
35 @override
35 - createState() => _WalletNameFormState();
36 + _WalletNameFormState createState() => _WalletNameFormState();
37 }
38
39 class _WalletNameFormState extends State<WalletNameForm> {
@@ -43,14 +44,14 @@ class _WalletNameFormState extends State<WalletNameForm> {
44 Widget build(BuildContext context) {
45 final walletCreationStore = Provider.of<WalletCreationStore>(context);
46
46 - reaction((_) => walletCreationStore.state, (state) {
47 + reaction((_) => walletCreationStore.state, (WalletCreationState state) {
48 if (state is WalletCreatedSuccessfully) {
49 Navigator.of(context).popUntil((route) => route.isFirst);
50 }
51
52 if (state is WalletCreationFailure) {
53 WidgetsBinding.instance.addPostFrameCallback((_) {
53 - showDialog(
54 + showDialog<void>(
55 context: context,
56 builder: (BuildContext context) {
57 return AlertDialog(
@@ -88,8 +89,8 @@ class _WalletNameFormState extends State<WalletNameForm> {
89 fontSize: 24.0, color: Theme.of(context).hintColor),
90 hintText: S.of(context).wallet_name,
91 focusedBorder: UnderlineInputBorder(
91 - borderSide: BorderSide(
92 - color: Palette.cakeGreen, width: 2.0)),
92 + borderSide:
93 + BorderSide(color: Palette.cakeGreen, width: 2.0)),
94 enabledBorder: UnderlineInputBorder(
95 borderSide: BorderSide(
96 color: Theme.of(context).focusColor,
lib/src/screens/nodes/new_node_page.dart
+1 -1
@@ -17,7 +17,7 @@ class NewNodePage extends BasePage {
17
18 class NewNodePageForm extends StatefulWidget {
19 @override
20 - createState() => NewNodeFormState();
20 + NewNodeFormState createState() => NewNodeFormState();
21 }
22
23 class NewNodeFormState extends State<NewNodePageForm> {
lib/src/screens/nodes/node_indicator.dart
+4 -6
@@ -2,18 +2,16 @@ import 'package:flutter/material.dart';
2 import 'package:cake_wallet/palette.dart';
3
4 class NodeIndicator extends StatelessWidget {
5 - final color;
6 -
5 NodeIndicator({this.color = Palette.red});
6
7 + final Color color;
8 +
9 @override
10 Widget build(BuildContext context) {
11 return Container(
12 width: 10.0,
13 height: 10.0,
14 - decoration: BoxDecoration(
15 - shape: BoxShape.circle,
16 - color: color),
14 + decoration: BoxDecoration(shape: BoxShape.circle, color: color),
15 );
16 }
19 -}
\ No newline at end of file
17 +}
lib/src/screens/nodes/nodes_list_page.dart
+7 -8
@@ -13,6 +13,7 @@ import 'package:cake_wallet/src/screens/base_page.dart';
13 class NodeListPage extends BasePage {
14 NodeListPage();
15
16 + @override
17 String get title => S.current.nodes;
18
19 @override
@@ -26,7 +27,7 @@ class NodeListPage extends BasePage {
27 minWidth: double.minPositive,
28 child: FlatButton(
29 onPressed: () async {
29 - await showDialog(
30 + await showDialog<void>(
31 context: context,
32 builder: (BuildContext context) {
33 return AlertDialog(
@@ -76,10 +77,8 @@ class NodeListPage extends BasePage {
77 height: 28.0,
78 child: FlatButton(
79 shape: CircleBorder(),
79 - onPressed: () async {
80 - await Navigator.of(context).pushNamed(Routes.newNode);
81 - nodeList.update();
82 - },
80 + onPressed: () async =>
81 + await Navigator.of(context).pushNamed(Routes.newNode),
82 child: Offstage()),
83 )
84 ],
@@ -94,7 +93,7 @@ class NodeListPage extends BasePage {
93
94 class NodeListPageBody extends StatefulWidget {
95 @override
97 - createState() => NodeListPageBodyState();
96 + NodeListPageBodyState createState() => NodeListPageBodyState();
97 }
98
99 class NodeListPageBodyState extends State<NodeListPageBody> {
@@ -141,7 +140,7 @@ class NodeListPageBodyState extends State<NodeListPageBody> {
140 switch (snapshot.connectionState) {
141 case ConnectionState.done:
142 return NodeIndicator(
144 - color: snapshot.data
143 + color: snapshot.data as bool
144 ? Palette.green
145 : Palette.red);
146 default:
@@ -150,7 +149,7 @@ class NodeListPageBodyState extends State<NodeListPageBody> {
149 }),
150 onTap: () async {
151 if (!isCurrent) {
153 - await showDialog(
152 + await showDialog<void>(
153 context: context,
154 builder: (BuildContext context) {
155 return AlertDialog(
lib/src/screens/pin_code/pin_code.dart
+33 -33
@@ -6,19 +6,20 @@ import 'package:cake_wallet/src/stores/settings/settings_store.dart';
6 import 'package:cake_wallet/generated/i18n.dart';
7
8 abstract class PinCodeWidget extends StatefulWidget {
9 - final Function(List<int> pin, PinCodeState state) onPinCodeEntered;
10 - final bool hasLengthSwitcher;
11 -
9 PinCodeWidget({Key key, this.onPinCodeEntered, this.hasLengthSwitcher})
10 : super(key: key);
14 -}
11
16 -class PinCode extends PinCodeWidget {
12 final Function(List<int> pin, PinCodeState state) onPinCodeEntered;
13 final bool hasLengthSwitcher;
14 +}
15
20 - PinCode(this.onPinCodeEntered, this.hasLengthSwitcher, Key key)
21 - : super(key: key);
16 +class PinCode extends PinCodeWidget {
17 + PinCode(Function(List<int> pin, PinCodeState state) onPinCodeEntered,
18 + bool hasLengthSwitcher, Key key)
19 + : super(
20 + key: key,
21 + onPinCodeEntered: onPinCodeEntered,
22 + hasLengthSwitcher: hasLengthSwitcher);
23
24 @override
25 PinCodeState createState() => PinCodeState();
@@ -30,27 +31,22 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
31 static const fourPinLength = 4;
32 static final deleteIconImage = Image.asset('assets/images/delete_icon.png');
33 static final backArrowImage = Image.asset('assets/images/back_arrow.png');
33 - GlobalKey _gridViewKey = GlobalKey();
34 + final _gridViewKey = GlobalKey();
35
36 int pinLength = defaultPinLength;
37 List<int> pin = List<int>.filled(defaultPinLength, null);
38 String title = S.current.enter_your_pin;
39 double _aspectRatio = 0;
40
40 - void setTitle(String title) {
41 - setState(() => this.title = title);
42 - }
41 + void setTitle(String title) => setState(() => this.title = title);
42
44 - void clear() {
45 - setState(() => pin = List<int>.filled(pinLength, null));
46 - }
43 + void clear() => setState(() => pin = List<int>.filled(pinLength, null));
44
48 - void onPinCodeEntered(PinCodeState state) {
49 - widget.onPinCodeEntered(state.pin, this);
50 - }
45 + void onPinCodeEntered(PinCodeState state) =>
46 + widget.onPinCodeEntered(state.pin, this);
47
48 void changePinLength(int length) {
53 - List<int> newPin = List<int>.filled(length, null);
49 + final newPin = List<int>.filled(length, null);
50
51 setState(() {
52 pinLength = length;
@@ -58,19 +54,23 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
54 });
55 }
56
61 - setDefaultPinLength() {
57 + void setDefaultPinLength() {
58 final settingsStore = Provider.of<SettingsStore>(context);
59
60 pinLength = settingsStore.defaultPinLength;
61 changePinLength(pinLength);
62 }
63
68 - getCurrentAspectRatio() {
69 - final RenderBox renderBox = _gridViewKey.currentContext.findRenderObject();
64 + void calculateAspectRatio() {
65 + final renderBox =
66 + _gridViewKey.currentContext.findRenderObject() as RenderBox;
67 + final cellWidth = renderBox.size.width / 3;
68 + final cellHeight = renderBox.size.height / 4;
69 +
70 + if (cellWidth > 0 && cellHeight > 0) {
71 + _aspectRatio = cellWidth / cellHeight;
72 + }
73
71 - double cellWidth = renderBox.size.width / 3;
72 - double cellHeight = renderBox.size.height / 4;
73 - if (cellWidth > 0 && cellHeight > 0) _aspectRatio = cellWidth / cellHeight;
74 setState(() {});
75 }
76
@@ -80,15 +80,13 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
80 WidgetsBinding.instance.addPostFrameCallback(afterLayout);
81 }
82
83 - afterLayout(_) {
83 + void afterLayout(dynamic _) {
84 setDefaultPinLength();
85 - getCurrentAspectRatio();
85 + calculateAspectRatio();
86 }
87
88 @override
89 - Widget build(BuildContext context) {
90 - return Scaffold(body: body(context));
91 - }
89 + Widget build(BuildContext context) => Scaffold(body: body(context));
90
91 Widget body(BuildContext context) {
92 return SafeArea(
@@ -196,7 +194,7 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
194 }
195
196 void _push(int num) {
199 - if (_pinLength() >= pinLength) {
197 + if (currentPinLength() >= pinLength) {
198 return;
199 }
200
@@ -207,13 +205,15 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
205 }
206 }
207
210 - if (_pinLength() == pinLength) {
208 + final _currentPinLength = currentPinLength();
209 +
210 + if (_currentPinLength == pinLength) {
211 onPinCodeEntered(this);
212 }
213 }
214
215 void _pop() {
216 - if (_pinLength() == 0) {
216 + if (currentPinLength() == 0) {
217 return;
218 }
219
@@ -225,7 +225,7 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
225 }
226 }
227
228 - int _pinLength() {
228 + int currentPinLength() {
229 return pin.fold(0, (v, e) {
230 if (e != null) {
231 return v + 1;
lib/src/screens/receive/qr_image.dart
+2 -2
@@ -10,7 +10,7 @@ class QrImage extends StatelessWidget {
10 Color foregroundColor = Colors.black,
11 int version = 7,
12 int errorCorrectionLevel = QrErrorCorrectLevel.L,
13 - }) : _painter = new QrPainter(data, foregroundColor, version, errorCorrectionLevel);
13 + }) : _painter = QrPainter(data, foregroundColor, version, errorCorrectionLevel);
14
15 final QrPainter _painter;
16 final Color backgroundColor;
@@ -18,7 +18,7 @@ class QrImage extends StatelessWidget {
18
19 @override
20 Widget build(BuildContext context) {
21 - return new Container(
21 + return Container(
22 width: size,
23 height: size,
24 color: backgroundColor,
lib/src/screens/receive/qr_painter.dart
+14 -11
@@ -3,31 +3,32 @@ import 'package:qr/qr.dart';
3
4 class QrPainter extends CustomPainter {
5 QrPainter(
6 - String data,
7 - this.color,
8 - this.version,
9 - this.errorCorrectionLevel,
10 - ) : this._qr = new QrCode(version, errorCorrectionLevel) {
6 + String data,
7 + this.color,
8 + this.version,
9 + this.errorCorrectionLevel,
10 + ) : this._qr = QrCode(version, errorCorrectionLevel) {
11 _p.color = this.color;
12
13 _qr.addData(data);
14 _qr.make();
15 }
16
17 - final QrCode _qr;
18 - final _p = new Paint()..style = PaintingStyle.fill;
19 -
17 final int version;
18 final int errorCorrectionLevel;
19 final Color color;
20
21 + final QrCode _qr;
22 + final _p = Paint()..style = PaintingStyle.fill;
23 +
24 @override
25 void paint(Canvas canvas, Size size) {
26 final squareSize = size.shortestSide / _qr.moduleCount;
27 for (int x = 0; x < _qr.moduleCount; x++) {
28 for (int y = 0; y < _qr.moduleCount; y++) {
29 if (_qr.isDark(y, x)) {
30 - final squareRect = new Rect.fromLTWH(x * squareSize, y * squareSize, squareSize, squareSize);
30 + final squareRect = Rect.fromLTWH(
31 + x * squareSize, y * squareSize, squareSize, squareSize);
32 canvas.drawRect(squareRect, _p);
33 }
34 }
@@ -37,9 +38,11 @@ class QrPainter extends CustomPainter {
38 @override
39 bool shouldRepaint(CustomPainter oldDelegate) {
40 if (oldDelegate is QrPainter) {
40 - return this.color != oldDelegate.color || this.errorCorrectionLevel != oldDelegate.errorCorrectionLevel ||
41 + return this.color != oldDelegate.color ||
42 + this.errorCorrectionLevel != oldDelegate.errorCorrectionLevel ||
43 this.version != oldDelegate.version;
44 }
45 +
46 return false;
47 }
45 -}
\ No newline at end of file
48 +}
lib/src/screens/receive/receive_page.dart
+12 -6
@@ -13,7 +13,10 @@ import 'package:cake_wallet/src/screens/receive/qr_image.dart';
13 import 'package:cake_wallet/src/screens/base_page.dart';
14
15 class ReceivePage extends BasePage {
16 + @override
17 bool get isModalBackButton => true;
18 +
19 + @override
20 String get title => S.current.receive;
21
22 @override
@@ -31,7 +34,10 @@ class ReceivePage extends BasePage {
34 padding: EdgeInsets.all(0),
35 onPressed: () => Share.text(
36 'Share address', walletStore.subaddress.address, 'text/plain'),
34 - child: Icon(Icons.share, size: 30.0,)),
37 + child: Icon(
38 + Icons.share,
39 + size: 30.0,
40 + )),
41 ),
42 );
43 }
@@ -43,7 +49,7 @@ class ReceivePage extends BasePage {
49
50 class ReceiveBody extends StatefulWidget {
51 @override
46 - createState() => ReceiveBodyState();
52 + ReceiveBodyState createState() => ReceiveBodyState();
53 }
54
55 class ReceiveBodyState extends State<ReceiveBody> {
@@ -67,8 +73,9 @@ class ReceiveBodyState extends State<ReceiveBody> {
73 amountController.addListener(() {
74 if (_formKey.currentState.validate()) {
75 walletStore.onChangedAmountValue(amountController.text);
70 - } else
76 + } else {
77 walletStore.onChangedAmountValue('');
78 + }
79 });
80
81 return SafeArea(
@@ -152,7 +159,7 @@ class ReceiveBodyState extends State<ReceiveBody> {
159 TextInputType.numberWithOptions(decimal: true),
160 inputFormatters: [
161 BlacklistingTextInputFormatter(
155 - new RegExp('[\\-|\\ |\\,]'))
162 + RegExp('[\\-|\\ |\\,]'))
163 ],
164 style: TextStyle(
165 fontSize: 14.0,
@@ -163,8 +170,7 @@ class ReceiveBodyState extends State<ReceiveBody> {
170 hintText: S.of(context).amount,
171 focusedBorder: UnderlineInputBorder(
172 borderSide: BorderSide(
166 - color: Palette.cakeGreen,
167 - width: 2.0)),
173 + color: Palette.cakeGreen, width: 2.0)),
174 enabledBorder: UnderlineInputBorder(
175 borderSide: BorderSide(
176 color: Theme.of(context).focusColor,
lib/src/screens/restore/restore_options_page.dart
+5 -1
@@ -9,7 +9,10 @@ import 'package:cake_wallet/generated/i18n.dart';
9 class RestoreOptionsPage extends BasePage {
10 static const _aspectRatioImage = 2.086;
11
12 + @override
13 String get title => S.current.restore_restore_wallet;
14 +
15 + @override
16 Color get backgroundColor => Palette.creamyGrey;
17
18 final _imageSeedKeys = Image.asset('assets/images/seedKeys.png');
@@ -26,7 +29,8 @@ class RestoreOptionsPage extends BasePage {
29 Flexible(
30 child: RestoreButton(
31 onPressed: () {
29 - Navigator.pushNamed(context, Routes.restoreWalletOptionsFromWelcome);
32 + Navigator.pushNamed(
33 + context, Routes.restoreWalletOptionsFromWelcome);
34 },
35 image: _imageSeedKeys,
36 aspectRatioImage: _aspectRatioImage,
lib/src/screens/restore/restore_wallet_from_keys_page.dart
+13 -16
@@ -17,24 +17,25 @@ import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
17 import 'package:cake_wallet/palette.dart';
18
19 class RestoreWalletFromKeysPage extends BasePage {
20 + RestoreWalletFromKeysPage(
21 + {@required this.walletsService,
22 + @required this.sharedPreferences,
23 + @required this.walletService});
24 +
25 final WalletListService walletsService;
26 final WalletService walletService;
27 final SharedPreferences sharedPreferences;
28
29 + @override
30 String get title => S.current.restore_title_from_keys;
31
26 - RestoreWalletFromKeysPage(
27 - {@required this.walletsService,
28 - @required this.sharedPreferences,
29 - @required this.walletService});
30 -
32 @override
33 Widget body(BuildContext context) => RestoreFromKeysFrom();
34 }
35
36 class RestoreFromKeysFrom extends StatefulWidget {
37 @override
37 - createState() => _RestoreFromKeysFromState();
38 + _RestoreFromKeysFromState createState() => _RestoreFromKeysFromState();
39 }
40
41 class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
@@ -49,14 +50,14 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
50 Widget build(BuildContext context) {
51 final walletRestorationStore = Provider.of<WalletRestorationStore>(context);
52
52 - reaction((_) => walletRestorationStore.state, (state) {
53 + reaction((_) => walletRestorationStore.state, (WalletRestorationState state) {
54 if (state is WalletRestoredSuccessfully) {
55 Navigator.of(context).popUntil((route) => route.isFirst);
56 }
57
58 if (state is WalletRestorationFailure) {
59 WidgetsBinding.instance.addPostFrameCallback((_) {
59 - showDialog(
60 + showDialog<void>(
61 context: context,
62 builder: (BuildContext context) {
63 return AlertDialog(
@@ -97,8 +98,7 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
98 hintText: S.of(context).restore_wallet_name,
99 focusedBorder: UnderlineInputBorder(
100 borderSide: BorderSide(
100 - color: Palette.cakeGreen,
101 - width: 2.0)),
101 + color: Palette.cakeGreen, width: 2.0)),
102 enabledBorder: UnderlineInputBorder(
103 borderSide: BorderSide(
104 color: Theme.of(context).focusColor,
@@ -127,8 +127,7 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
127 hintText: S.of(context).restore_address,
128 focusedBorder: UnderlineInputBorder(
129 borderSide: BorderSide(
130 - color: Palette.cakeGreen,
131 - width: 2.0)),
130 + color: Palette.cakeGreen, width: 2.0)),
131 enabledBorder: UnderlineInputBorder(
132 borderSide: BorderSide(
133 color: Theme.of(context).focusColor,
@@ -155,8 +154,7 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
154 hintText: S.of(context).restore_view_key_private,
155 focusedBorder: UnderlineInputBorder(
156 borderSide: BorderSide(
158 - color: Palette.cakeGreen,
159 - width: 2.0)),
157 + color: Palette.cakeGreen, width: 2.0)),
158 enabledBorder: UnderlineInputBorder(
159 borderSide: BorderSide(
160 color: Theme.of(context).focusColor,
@@ -183,8 +181,7 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
181 hintText: S.of(context).restore_spend_key_private,
182 focusedBorder: UnderlineInputBorder(
183 borderSide: BorderSide(
186 - color: Palette.cakeGreen,
187 - width: 2.0)),
184 + color: Palette.cakeGreen, width: 2.0)),
185 enabledBorder: UnderlineInputBorder(
186 borderSide: BorderSide(
187 color: Theme.of(context).focusColor,
lib/src/screens/restore/restore_wallet_from_seed_details.dart
+5 -3
@@ -13,6 +13,7 @@ import 'package:cake_wallet/src/widgets/primary_button.dart';
13 import 'package:cake_wallet/palette.dart';
14
15 class RestoreWalletFromSeedDetailsPage extends BasePage {
16 + @override
17 String get title => S.current.restore_wallet_restore_description;
18
19 @override
@@ -21,7 +22,8 @@ class RestoreWalletFromSeedDetailsPage extends BasePage {
22
23 class RestoreFromSeedDetailsForm extends StatefulWidget {
24 @override
24 - createState() => _RestoreFromSeedDetailsFormState();
25 + _RestoreFromSeedDetailsFormState createState() =>
26 + _RestoreFromSeedDetailsFormState();
27 }
28
29 class _RestoreFromSeedDetailsFormState
@@ -34,14 +36,14 @@ class _RestoreFromSeedDetailsFormState
36 Widget build(BuildContext context) {
37 final walletRestorationStore = Provider.of<WalletRestorationStore>(context);
38
37 - reaction((_) => walletRestorationStore.state, (state) {
39 + reaction((_) => walletRestorationStore.state, (WalletRestorationState state) {
40 if (state is WalletRestoredSuccessfully) {
41 Navigator.of(context).popUntil((route) => route.isFirst);
42 }
43
44 if (state is WalletRestorationFailure) {
45 WidgetsBinding.instance.addPostFrameCallback((_) {
44 - showDialog(
46 + showDialog<void>(
47 context: context,
48 builder: (BuildContext context) {
49 return AlertDialog(
lib/src/screens/restore/restore_wallet_from_seed_page.dart
+10 -10
@@ -14,24 +14,25 @@ import 'package:cake_wallet/src/stores/wallet_restoration/wallet_restoration_sto
14 import 'package:cake_wallet/src/widgets/seed_widget.dart';
15
16 class RestoreWalletFromSeedPage extends BasePage {
17 + RestoreWalletFromSeedPage(
18 + {@required this.walletsService,
19 + @required this.walletService,
20 + @required this.sharedPreferences});
21 +
22 final WalletListService walletsService;
23 final WalletService walletService;
24 final SharedPreferences sharedPreferences;
25
26 + @override
27 String get title => S.current.restore_title_from_seed;
28
23 - RestoreWalletFromSeedPage(
24 - {@required this.walletsService,
25 - @required this.walletService,
26 - @required this.sharedPreferences});
27 -
29 @override
30 Widget body(BuildContext context) => RestoreFromSeedForm();
31 }
32
33 class RestoreFromSeedForm extends StatefulWidget {
34 @override
34 - createState() => _RestoreFromSeedFormState();
35 + _RestoreFromSeedFormState createState() => _RestoreFromSeedFormState();
36 }
37
38 class _RestoreFromSeedFormState extends State<RestoreFromSeedForm> {
@@ -46,9 +47,8 @@ class _RestoreFromSeedFormState extends State<RestoreFromSeedForm> {
47 (_) => _setReactions(context, walletRestorationStore));
48
49 return GestureDetector(
49 - onTap: () {
50 - SystemChannels.textInput.invokeMethod('TextInput.hide');
51 - },
50 + onTap: () =>
51 + SystemChannels.textInput.invokeMethod<void>('TextInput.hide'),
52 child: Container(
53 padding: EdgeInsets.only(left: 20.0, right: 20.0, bottom: 20.0),
54 child: Column(
@@ -90,7 +90,7 @@ class _RestoreFromSeedFormState extends State<RestoreFromSeedForm> {
90 return;
91 }
92
93 - reaction((_) => store.errorMessage, (errorMessage) {
93 + reaction((_) => store.errorMessage, (String errorMessage) {
94 if (errorMessage == null || errorMessage.isEmpty) {
95 _seedKey.currentState.validated();
96 } else {
lib/src/screens/restore/restore_wallet_options_page.dart
+7 -4
@@ -9,7 +9,10 @@ import 'package:cake_wallet/generated/i18n.dart';
9 class RestoreWalletOptionsPage extends BasePage {
10 static const _aspectRatioImage = 2.086;
11
12 + @override
13 String get title => S.current.restore_seed_keys_restore;
14 +
15 + @override
16 Color get backgroundColor => Palette.creamyGrey;
17
18 final _imageSeed = Image.asset('assets/images/seedIco.png');
@@ -29,8 +32,8 @@ class RestoreWalletOptionsPage extends BasePage {
32 Navigator.pushNamed(context, Routes.restoreWalletFromSeed),
33 image: _imageSeed,
34 aspectRatioImage: _aspectRatioImage,
32 - titleColor: Palette.lightViolet,
33 - color: Palette.lightViolet,
35 + titleColor: Palette.lightViolet,
36 + color: Palette.lightViolet,
37 title: S.of(context).restore_title_from_seed,
38 description: S.of(context).restore_description_from_seed,
39 textButton: S.of(context).restore_next,
@@ -41,8 +44,8 @@ class RestoreWalletOptionsPage extends BasePage {
44 Navigator.pushNamed(context, Routes.restoreWalletFromKeys),
45 image: _imageKeys,
46 aspectRatioImage: _aspectRatioImage,
44 - titleColor: Palette.cakeGreen,
45 - color: Palette.cakeGreen,
47 + titleColor: Palette.cakeGreen,
48 + color: Palette.cakeGreen,
49 title: S.of(context).restore_title_from_keys,
50 description: S.of(context).restore_description_from_keys,
51 textButton: S.of(context).restore_next,
lib/src/screens/restore/widgets/restore_button.dart
+18 -16
@@ -2,15 +2,6 @@ import 'package:flutter/material.dart';
2 import 'package:cake_wallet/palette.dart';
3
4 class RestoreButton extends StatelessWidget {
5 - final VoidCallback onPressed;
6 - final Image image;
7 - final double aspectRatioImage;
8 - final Color color;
9 - final Color titleColor;
10 - final String title;
11 - final String description;
12 - final String textButton;
13 -
5 const RestoreButton(
6 {@required this.onPressed,
7 @required this.image,
@@ -21,9 +12,17 @@ class RestoreButton extends StatelessWidget {
12 this.description = '',
13 this.textButton = ''});
14
15 + final VoidCallback onPressed;
16 + final Image image;
17 + final double aspectRatioImage;
18 + final Color color;
19 + final Color titleColor;
20 + final String title;
21 + final String description;
22 + final String textButton;
23 +
24 @override
25 Widget build(BuildContext context) {
26 -
26 return Container(
27 margin: EdgeInsets.only(top: 20.0, bottom: 20.0),
28 decoration: BoxDecoration(
@@ -71,11 +70,11 @@ class RestoreButton extends StatelessWidget {
70 child: Text(
71 description,
72 textAlign: TextAlign.center,
74 - style:
75 - TextStyle(
76 - color: Theme.of(context).accentTextTheme.subhead.color,
77 - fontSize: 14.0,
78 - height: 1.4),
73 + style: TextStyle(
74 + color:
75 + Theme.of(context).accentTextTheme.subhead.color,
76 + fontSize: 14.0,
77 + height: 1.4),
78 ),
79 )
80 ],
@@ -88,7 +87,10 @@ class RestoreButton extends StatelessWidget {
87 decoration: BoxDecoration(
88 border: Border(
89 top: BorderSide(
91 - color: Theme.of(context).accentTextTheme.headline.decorationColor,
90 + color: Theme.of(context)
91 + .accentTextTheme
92 + .headline
93 + .decorationColor,
94 width: 1.15)),
95 color: Colors.transparent,
96 ),
lib/src/screens/root/root.dart
+3 -3
@@ -1,11 +1,9 @@
1 -import 'package:cake_wallet/src/screens/welcome/create_welcome_page.dart';
1 import 'package:flutter/material.dart';
2 import 'package:flutter_mobx/flutter_mobx.dart';
3 import 'package:hive/hive.dart';
4 import 'package:provider/provider.dart';
5 import 'package:shared_preferences/shared_preferences.dart';
6 import 'package:cake_wallet/routes.dart';
8 -import 'package:cake_wallet/router.dart';
7 import 'package:cake_wallet/src/stores/authentication/authentication_store.dart';
8 import 'package:cake_wallet/src/stores/price/price_store.dart';
9 import 'package:cake_wallet/src/stores/settings/settings_store.dart';
@@ -19,6 +17,8 @@ import 'package:cake_wallet/src/domain/monero/transaction_description.dart';
17 import 'package:cake_wallet/src/screens/auth/create_login_page.dart';
18 import 'package:cake_wallet/src/screens/seed/create_seed_page.dart';
19 import 'package:cake_wallet/src/screens/dashboard/create_dashboard_page.dart';
20 +import 'package:cake_wallet/src/screens/auth/auth_page.dart';
21 +import 'package:cake_wallet/src/screens/welcome/create_welcome_page.dart';
22
23 class Root extends StatefulWidget {
24 Root({Key key}) : super(key: key);
@@ -81,7 +81,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
81
82 WidgetsBinding.instance.addPostFrameCallback((_) {
83 Navigator.of(context).pushNamed(Routes.unlock,
84 - arguments: (isAuthenticatedSuccessfully, auth) {
84 + arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
85 if (!isAuthenticatedSuccessfully) {
86 return;
87 }
lib/src/screens/seed/seed_page.dart
+7 -2
@@ -11,14 +11,19 @@ import 'package:cake_wallet/src/stores/wallet_seed/wallet_seed_store.dart';
11 import 'package:cake_wallet/src/screens/base_page.dart';
12
13 class SeedPage extends BasePage {
14 + SeedPage({this.onCloseCallback});
15 +
16 static final image = Image.asset('assets/images/seed_image.png');
17 +
18 + @override
19 bool get isModalBackButton => true;
20 +
21 + @override
22 String get title => S.current.seed_title;
23
24 final VoidCallback onCloseCallback;
25
20 - SeedPage({this.onCloseCallback});
21 -
26 + @override
27 void onClose(BuildContext context) =>
28 onCloseCallback != null ? onCloseCallback() : Navigator.of(context).pop();
29
lib/src/screens/send/send_page.dart
+19 -14
@@ -1,3 +1,4 @@
1 +import 'package:cake_wallet/src/screens/auth/auth_page.dart';
2 import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
3 import 'package:flutter/cupertino.dart';
4 import 'package:flutter/material.dart';
@@ -23,8 +24,13 @@ import 'package:cake_wallet/src/domain/common/sync_status.dart';
24 import 'package:cake_wallet/src/stores/sync/sync_store.dart';
25
26 class SendPage extends BasePage {
27 + @override
28 String get title => S.current.send_title;
29 +
30 + @override
31 bool get isModalBackButton => true;
32 +
33 + @override
34 bool get resizeToAvoidBottomPadding => false;
35
36 @override
@@ -212,7 +218,7 @@ class SendFormState extends State<SendForm> {
218 signed: false, decimal: false),
219 inputFormatters: [
220 BlacklistingTextInputFormatter(
215 - new RegExp('[\\-|\\ |\\,]'))
221 + RegExp('[\\-|\\ |\\,]'))
222 ],
223 decoration: InputDecoration(
224 prefixIcon: Padding(
@@ -272,7 +278,7 @@ class SendFormState extends State<SendForm> {
278 signed: false, decimal: false),
279 inputFormatters: [
280 BlacklistingTextInputFormatter(
275 - new RegExp('[\\-|\\ |\\,]'))
281 + RegExp('[\\-|\\ |\\,]'))
282 ],
283 decoration: InputDecoration(
284 prefixIcon: Padding(
@@ -353,7 +359,7 @@ class SendFormState extends State<SendForm> {
359 FocusScope.of(context).requestFocus(FocusNode());
360
361 if (_formKey.currentState.validate()) {
356 - await showDialog(
362 + await showDialog<void>(
363 context: context,
364 builder: (dialogContext) {
365 return AlertDialog(
@@ -364,12 +370,11 @@ class SendFormState extends State<SendForm> {
370 FlatButton(
371 child: Text(S.of(context).send),
372 onPressed: () async {
367 - Navigator.of(dialogContext)
368 - .popAndPushNamed(
369 - Routes.auth,
370 - arguments:
371 - (isAuthenticatedSuccessfully,
372 - auth) {
373 + await Navigator.of(dialogContext)
374 + .popAndPushNamed(Routes.auth,
375 + arguments: (bool
376 + isAuthenticatedSuccessfully,
377 + AuthPageState auth) {
378 if (!isAuthenticatedSuccessfully) {
379 return;
380 }
@@ -408,13 +413,13 @@ class SendFormState extends State<SendForm> {
413
414 final sendStore = Provider.of<SendStore>(context);
415
411 - reaction((_) => sendStore.fiatAmount, (amount) {
416 + reaction((_) => sendStore.fiatAmount, (String amount) {
417 if (amount != _fiatAmountController.text) {
418 _fiatAmountController.text = amount;
419 }
420 });
421
417 - reaction((_) => sendStore.cryptoAmount, (amount) {
422 + reaction((_) => sendStore.cryptoAmount, (String amount) {
423 if (amount != _cryptoAmountController.text) {
424 _cryptoAmountController.text = amount;
425 }
@@ -436,10 +441,10 @@ class SendFormState extends State<SendForm> {
441 }
442 });
443
439 - reaction((_) => sendStore.state, (state) {
444 + reaction((_) => sendStore.state, (SendingState state) {
445 if (state is SendingFailed) {
446 WidgetsBinding.instance.addPostFrameCallback((_) {
442 - showDialog(
447 + showDialog<void>(
448 context: context,
449 builder: (BuildContext context) {
450 return AlertDialog(
@@ -457,7 +462,7 @@ class SendFormState extends State<SendForm> {
462
463 if (state is TransactionCreatedSuccessfully) {
464 WidgetsBinding.instance.addPostFrameCallback((_) {
460 - showDialog(
465 + showDialog<void>(
466 context: context,
467 builder: (BuildContext context) {
468 return AlertDialog(
lib/src/screens/settings/change_language.dart
+3 -2
@@ -21,7 +21,8 @@ const Map<String, String> _languages = {
21 };
22
23 class ChangeLanguage extends BasePage {
24 - get title => S.current.settings_change_language;
24 + @override
25 + String get title => S.current.settings_change_language;
26
27 @override
28 Widget body(BuildContext context) {
@@ -50,7 +51,7 @@ class ChangeLanguage extends BasePage {
51 ),
52 onTap: () async {
53 if (!isCurrent) {
53 - await showDialog(
54 + await showDialog<void>(
55 context: context,
56 builder: (BuildContext context) {
57 return AlertDialog(
lib/src/screens/settings/enter_pin_code.dart
+130 -139
@@ -7,39 +7,41 @@ import 'package:cake_wallet/theme_changer.dart';
7 import 'package:cake_wallet/themes.dart';
8 import 'package:cake_wallet/generated/i18n.dart';
9
10 -class EnterPinCode extends StatefulWidget{
10 +class EnterPinCode extends StatefulWidget {
11 + const EnterPinCode(this.currentPinLength, this.currentPin);
12
13 final int currentPinLength;
14 final List<int> currentPin;
15
15 - const EnterPinCode(this.currentPinLength, this.currentPin);
16 -
16 @override
18 - createState() => EnterPinCodeState(currentPinLength, currentPin);
19 -
17 + EnterPinCodeState createState() =>
18 + EnterPinCodeState(currentPinLength, currentPin);
19 }
20
22 -class EnterPinCodeState extends State<EnterPinCode>{
23 - GlobalKey _gridViewKey = GlobalKey();
21 +class EnterPinCodeState extends State<EnterPinCode> {
22 + EnterPinCodeState(this.pinLength, this.currentPin);
23
24 + final _gridViewKey = GlobalKey();
25 final _closeButtonImage = Image.asset('assets/images/close_button.png');
26 - final _closeButtonImageDarkTheme = Image.asset('assets/images/close_button_dark_theme.png');
26 + final _closeButtonImageDarkTheme =
27 + Image.asset('assets/images/close_button_dark_theme.png');
28 static final deleteIconImage = Image.asset('assets/images/delete_icon.png');
29 final int pinLength;
30 final List<int> currentPin;
31 List<int> pin;
32 double _aspectRatio = 0;
33
33 - EnterPinCodeState(this.pinLength, this.currentPin);
34 + void _calcualteCurrentAspectRatio() {
35 + final renderBox =
36 + _gridViewKey.currentContext.findRenderObject() as RenderBox;
37 + final cellWidth = renderBox.size.width / 3;
38 + final cellHeight = renderBox.size.height / 4;
39
35 - _getCurrentAspectRatio(){
36 - final RenderBox renderBox = _gridViewKey.currentContext.findRenderObject();
40 + if (cellWidth > 0 && cellHeight > 0) {
41 + _aspectRatio = cellWidth / cellHeight;
42 + }
43
38 - double cellWidth = renderBox.size.width/3;
39 - double cellHeight = renderBox.size.height/4;
40 - if (cellWidth > 0 && cellHeight > 0) _aspectRatio = cellWidth/cellHeight;
41 - setState(() {
42 - });
44 + setState(() {});
45 }
46
47 @override
@@ -49,130 +51,125 @@ class EnterPinCodeState extends State<EnterPinCode>{
51 WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
52 }
53
52 - _afterLayout(_) {
53 - _getCurrentAspectRatio();
54 - }
54 + void _afterLayout(dynamic _) => _calcualteCurrentAspectRatio();
55
56 @override
57 Widget build(BuildContext context) {
58 -
59 - ThemeChanger _themeChanger = Provider.of<ThemeChanger>(context);
60 - bool _isDarkTheme;
61 -
62 - if (_themeChanger.getTheme() == Themes.darkTheme) _isDarkTheme = true;
63 - else _isDarkTheme = false;
58 + final _themeChanger = Provider.of<ThemeChanger>(context);
59 + final _isDarkTheme = _themeChanger.getTheme() == Themes.darkTheme;
60
61 return Scaffold(
62 backgroundColor: Theme.of(context).backgroundColor,
63 appBar: CupertinoNavigationBar(
68 - leading: ButtonTheme(
69 - minWidth: double.minPositive,
70 - child: FlatButton(
71 - onPressed: (){ Navigator.pop(context, false); },
72 - child: _isDarkTheme ? _closeButtonImageDarkTheme : _closeButtonImage
64 + leading: ButtonTheme(
65 + minWidth: double.minPositive,
66 + child: FlatButton(
67 + onPressed: () {
68 + Navigator.pop(context, false);
69 + },
70 + child: _isDarkTheme
71 + ? _closeButtonImageDarkTheme
72 + : _closeButtonImage),
73 ),
74 - ),
75 - backgroundColor: Theme.of(context).backgroundColor,
76 - border: null,
77 - ),
74 + backgroundColor: Theme.of(context).backgroundColor,
75 + border: null),
76 body: SafeArea(
79 - child: Container(
80 - padding: EdgeInsets.only(left: 40.0, right: 40.0, bottom: 40.0),
81 - child: Column(
82 - children: <Widget>[
83 - Spacer(flex: 2),
84 - Text(S.of(context).enter_your_pin,
85 - style: TextStyle(
86 - fontSize: 24,
87 - color: Palette.wildDarkBlue
88 - )
89 - ),
90 - Spacer(flex: 3),
91 - Container(
92 - width: 180,
93 - child: Row(
94 - mainAxisAlignment: MainAxisAlignment.spaceBetween,
95 - children: List.generate(pinLength, (index) {
96 - const size = 10.0;
97 - final isFilled = pin[index] != null;
98 -
99 - return Container(
100 - width: size,
101 - height: size,
102 - decoration: BoxDecoration(
103 - shape: BoxShape.circle,
104 - color: isFilled ? Palette.deepPurple : Colors.transparent,
105 - border: Border.all(color: Palette.wildDarkBlue),
106 - ));
107 - }),
108 - ),
77 + child: Container(
78 + padding: EdgeInsets.only(left: 40.0, right: 40.0, bottom: 40.0),
79 + child: Column(
80 + children: <Widget>[
81 + Spacer(flex: 2),
82 + Text(S.of(context).enter_your_pin,
83 + style: TextStyle(fontSize: 24, color: Palette.wildDarkBlue)),
84 + Spacer(flex: 3),
85 + Container(
86 + width: 180,
87 + child: Row(
88 + mainAxisAlignment: MainAxisAlignment.spaceBetween,
89 + children: List.generate(pinLength, (index) {
90 + const size = 10.0;
91 + final isFilled = pin[index] != null;
92 +
93 + return Container(
94 + width: size,
95 + height: size,
96 + decoration: BoxDecoration(
97 + shape: BoxShape.circle,
98 + color:
99 + isFilled ? Palette.deepPurple : Colors.transparent,
100 + border: Border.all(color: Palette.wildDarkBlue),
101 + ));
102 + }),
103 ),
110 - Spacer(flex: 3),
111 - Flexible(
112 - flex: 24,
113 - child: Container(
114 - key: _gridViewKey,
115 - child: _aspectRatio > 0 ? GridView.count(
116 - crossAxisCount: 3,
117 - childAspectRatio: _aspectRatio,
118 - physics: const NeverScrollableScrollPhysics(),
119 - children: List.generate(12, (index) {
120 -
121 - if (index == 9) {
122 - return Container(
123 - margin: EdgeInsets.all(5.0),
124 - decoration: BoxDecoration(
125 - shape: BoxShape.circle,
126 - color: _isDarkTheme ? PaletteDark.darkThemePinButton
127 - : Palette.darkGrey,
128 - ),
129 - );
130 - } else if (index == 10) {
131 - index = 0;
132 - } else if (index == 11) {
133 - return Container(
134 - margin: EdgeInsets.all(5.0),
135 - child: FlatButton(
136 - onPressed: () { _pop(); },
137 - color: _isDarkTheme ? PaletteDark.darkThemePinButton
138 - : Palette.darkGrey,
139 - shape: CircleBorder(),
140 - child: deleteIconImage,
141 - ),
142 - );
143 - } else {
144 - index++;
145 - }
146 -
147 - return Container(
148 - margin: EdgeInsets.all(5.0),
149 - child: FlatButton(
150 - onPressed: () { _push(index); },
151 - color: _isDarkTheme ? PaletteDark.darkThemePinDigitButton
152 - : Palette.creamyGrey,
153 - shape: CircleBorder(),
154 - child: Text(
155 - '$index',
156 - style: TextStyle(
157 - fontSize: 23.0,
158 - color: Palette.blueGrey
159 - )
160 - ),
161 - ),
162 - );
163 - }),
164 - ) : null
165 - )
166 - )
167 - ],
168 - ),
169 - )
170 - ),
104 + ),
105 + Spacer(flex: 3),
106 + Flexible(
107 + flex: 24,
108 + child: Container(
109 + key: _gridViewKey,
110 + child: _aspectRatio > 0
111 + ? GridView.count(
112 + crossAxisCount: 3,
113 + childAspectRatio: _aspectRatio,
114 + physics: const NeverScrollableScrollPhysics(),
115 + children: List.generate(12, (index) {
116 + if (index == 9) {
117 + return Container(
118 + margin: EdgeInsets.all(5.0),
119 + decoration: BoxDecoration(
120 + shape: BoxShape.circle,
121 + color: _isDarkTheme
122 + ? PaletteDark.darkThemePinButton
123 + : Palette.darkGrey,
124 + ),
125 + );
126 + } else if (index == 10) {
127 + index = 0;
128 + } else if (index == 11) {
129 + return Container(
130 + margin: EdgeInsets.all(5.0),
131 + child: FlatButton(
132 + onPressed: () {
133 + _pop();
134 + },
135 + color: _isDarkTheme
136 + ? PaletteDark.darkThemePinButton
137 + : Palette.darkGrey,
138 + shape: CircleBorder(),
139 + child: deleteIconImage,
140 + ),
141 + );
142 + } else {
143 + index++;
144 + }
145 +
146 + return Container(
147 + margin: EdgeInsets.all(5.0),
148 + child: FlatButton(
149 + onPressed: () {
150 + _push(index);
151 + },
152 + color: _isDarkTheme
153 + ? PaletteDark.darkThemePinDigitButton
154 + : Palette.creamyGrey,
155 + shape: CircleBorder(),
156 + child: Text('$index',
157 + style: TextStyle(
158 + fontSize: 23.0,
159 + color: Palette.blueGrey)),
160 + ),
161 + );
162 + }),
163 + )
164 + : null))
165 + ],
166 + ),
167 + )),
168 );
169 }
170
174 - _showIncorrectPinDialog(BuildContext context) async {
175 - await showDialog(
171 + void _showIncorrectPinDialog(BuildContext context) async {
172 + await showDialog<void>(
173 context: context,
174 builder: (BuildContext context) {
175 return AlertDialog(
@@ -186,8 +183,7 @@ class EnterPinCodeState extends State<EnterPinCode>{
183 ),
184 ],
185 );
189 - }
190 - );
186 + });
187 }
188
189 void _push(int num) {
@@ -202,20 +198,16 @@ class EnterPinCodeState extends State<EnterPinCode>{
198 }
199 }
200
205 - if (_pinLength() == pinLength) {
206 -
207 - if (listEquals<int>(pin, currentPin)){
201 + final currentPinLength = _pinLength();
202
203 + if (currentPinLength == pinLength) {
204 + if (listEquals<int>(pin, currentPin)) {
205 Navigator.pop(context, true);
210 -
206 } else {
212 -
207 Navigator.pop(context, false);
208
209 _showIncorrectPinDialog(context);
216 -
210 }
218 -
211 }
212 }
213
@@ -226,7 +218,7 @@ class EnterPinCodeState extends State<EnterPinCode>{
218
219 for (var i = pin.length - 1; i >= 0; i--) {
220 if (pin[i] != null) {
229 - setState(() => pin[i] = null);
221 + setState(() => pin[i] = null);
222 break;
223 }
224 }
@@ -241,5 +233,4 @@ class EnterPinCodeState extends State<EnterPinCode>{
233 return v;
234 });
235 }
244 -
245 -}
\ No newline at end of file
236 +}
lib/src/screens/settings/items/settings_item.dart
+10 -9
@@ -2,6 +2,15 @@ import 'package:flutter/material.dart';
2 import 'package:cake_wallet/src/screens/settings/attributes.dart';
3
4 class SettingsItem {
5 + SettingsItem(
6 + {this.onTaped,
7 + this.title,
8 + this.link,
9 + this.image,
10 + this.widget,
11 + this.attribute,
12 + this.widgetBuilder});
13 +
14 final VoidCallback onTaped;
15 final String title;
16 final String link;
@@ -9,12 +18,4 @@ class SettingsItem {
18 final Widget widget;
19 final Attributes attribute;
20 final WidgetBuilder widgetBuilder;
12 -
13 - SettingsItem({this.onTaped,
14 - this.title,
15 - this.link,
16 - this.image,
17 - this.widget,
18 - this.attribute,
19 - this.widgetBuilder});
20 -}
\ No newline at end of file
21 +}
lib/src/screens/settings/settings.dart
+28 -18
@@ -1,3 +1,4 @@
1 +import 'package:cake_wallet/src/screens/auth/auth_page.dart';
2 import 'package:flutter/material.dart';
3 import 'package:flutter/cupertino.dart';
4 import 'package:cake_wallet/palette.dart';
@@ -25,8 +26,13 @@ import 'package:cake_wallet/src/screens/settings/widgets/settings_text_list_row.
26 import 'package:cake_wallet/src/screens/settings/widgets/settings_raw_widget_list_row.dart';
27
28 class SettingsPage extends BasePage {
29 + @override
30 String get title => S.current.settings_title;
31 +
32 + @override
33 bool get isModalBackButton => true;
34 +
35 + @override
36 Color get backgroundColor => Palette.lightGrey2;
37
38 @override
@@ -37,7 +43,7 @@ class SettingsPage extends BasePage {
43
44 class SettingsForm extends StatefulWidget {
45 @override
40 - createState() => SettingsFormState();
46 + SettingsFormState createState() => SettingsFormState();
47 }
48
49 class SettingsFormState extends State<SettingsForm> {
@@ -52,13 +58,13 @@ class SettingsFormState extends State<SettingsForm> {
58 final _changeNowUrl = 'mailto:support@changenow.io';
59 final _xmrToUrl = 'mailto:support@xmr.to';
60
55 - List<SettingsItem> _items = List<SettingsItem>();
61 + final _items = List<SettingsItem>();
62
57 - _launchUrl(String url) async {
63 + void _launchUrl(String url) async {
64 if (await canLaunch(url)) await launch(url);
65 }
66
61 - _setSettingsList() {
67 + void _setSettingsList() {
68 final settingsStore = Provider.of<SettingsStore>(context);
69
70 settingsStore.setItemHeaders();
@@ -121,11 +127,13 @@ class SettingsFormState extends State<SettingsForm> {
127 SettingsItem(
128 onTaped: () {
129 Navigator.of(context).pushNamed(Routes.auth,
124 - arguments: (isAuthenticatedSuccessfully, auth) =>
130 + arguments: (bool isAuthenticatedSuccessfully,
131 + AuthPageState auth) =>
132 isAuthenticatedSuccessfully
133 ? Navigator.of(context).popAndPushNamed(Routes.setupPin,
127 - arguments: (setupPinContext, _) =>
128 - Navigator.of(context).pop())
134 + arguments:
135 + (BuildContext setupPinContext, String _) =>
136 + Navigator.of(context).pop())
137 : null);
138 },
139 title: ItemHeaders.changePIN,
@@ -263,7 +271,7 @@ class SettingsFormState extends State<SettingsForm> {
271 onTaped: () {
272 Navigator.push(
273 context,
266 - CupertinoPageRoute(
274 + CupertinoPageRoute<void>(
275 builder: (BuildContext context) => DisclaimerPage()));
276 },
277 title: ItemHeaders.termsAndConditions,
@@ -276,7 +284,7 @@ class SettingsFormState extends State<SettingsForm> {
284 setState(() {});
285 }
286
279 - _afterLayout(_) => _setSettingsList();
287 + void _afterLayout(dynamic _) => _setSettingsList();
288
289 @override
290 void initState() {
@@ -335,11 +343,12 @@ class SettingsFormState extends State<SettingsForm> {
343 final item = _items[index];
344 bool _isDrawDivider = true;
345
338 - if (item.attribute == Attributes.header)
346 + if (item.attribute == Attributes.header) {
347 _isDrawDivider = false;
340 - else if (index < _items.length - 1) {
341 - if (_items[index + 1].attribute == Attributes.header)
348 + } else if (index < _items.length - 1) {
349 + if (_items[index + 1].attribute == Attributes.header) {
350 _isDrawDivider = false;
351 + }
352 }
353
354 return Column(
@@ -413,33 +422,34 @@ class SettingsFormState extends State<SettingsForm> {
422 });
423 }
424
416 - void _setBalance(BuildContext context) async {
425 + Future<void> _setBalance(BuildContext context) async {
426 final settingsStore = Provider.of<SettingsStore>(context);
427 final selectedDisplayMode =
428 await _presentPicker(context, BalanceDisplayMode.all);
429
430 if (selectedDisplayMode != null) {
422 - settingsStore.setCurrentBalanceDisplayMode(
431 + await settingsStore.setCurrentBalanceDisplayMode(
432 balanceDisplayMode: selectedDisplayMode);
433 }
434 }
435
427 - void _setCurrency(BuildContext context) async {
436 + Future<void> _setCurrency(BuildContext context) async {
437 final settingsStore = Provider.of<SettingsStore>(context);
438 final selectedCurrency = await _presentPicker(context, FiatCurrency.all);
439
440 if (selectedCurrency != null) {
432 - settingsStore.setCurrentFiatCurrency(currency: selectedCurrency);
441 + await settingsStore.setCurrentFiatCurrency(currency: selectedCurrency);
442 }
443 }
444
436 - void _setTransactionPriority(BuildContext context) async {
445 + Future<void> _setTransactionPriority(BuildContext context) async {
446 final settingsStore = Provider.of<SettingsStore>(context);
447 final selectedPriority =
448 await _presentPicker(context, TransactionPriority.all);
449
450 if (selectedPriority != null) {
442 - settingsStore.setCurrentTransactionPriority(priority: selectedPriority);
451 + await settingsStore.setCurrentTransactionPriority(
452 + priority: selectedPriority);
453 }
454 }
455 }
lib/src/screens/settings/widgets/settings_arrow_list_row.dart
+2 -2
@@ -4,12 +4,12 @@ import 'package:flutter_mobx/flutter_mobx.dart';
4 import 'package:cake_wallet/src/stores/settings/settings_store.dart';
5
6 class SettingsArrowListRow extends StatelessWidget {
7 + SettingsArrowListRow({@required this.onTaped, this.title});
8 +
9 final VoidCallback onTaped;
10 final String title;
11 final _cakeArrowImage = Image.asset('assets/images/cake_arrow.png');
12
11 - SettingsArrowListRow({@required this.onTaped, this.title});
12 -
13 @override
14 Widget build(BuildContext context) {
15 final settingsStore = Provider.of<SettingsStore>(context);
lib/src/screens/settings/widgets/settings_header_list_row.dart
+7 -8
@@ -5,10 +5,10 @@ import 'package:cake_wallet/palette.dart';
5 import 'package:provider/provider.dart';
6
7 class SettingsHeaderListRow extends StatelessWidget {
8 - final String title;
9 -
8 SettingsHeaderListRow({this.title});
9
10 + final String title;
11 +
12 @override
13 Widget build(BuildContext context) {
14 final settingsStore = Provider.of<SettingsStore>(context);
@@ -25,10 +25,10 @@ class SettingsHeaderListRow extends StatelessWidget {
25 children: <Widget>[
26 Observer(
27 builder: (_) => Text(
28 - settingsStore.itemHeaders[title],
29 - style: TextStyle(
30 - fontSize: 15.0, color: Palette.wildDarkBlue),
31 - ))
28 + settingsStore.itemHeaders[title],
29 + style: TextStyle(
30 + fontSize: 15.0, color: Palette.wildDarkBlue),
31 + ))
32 ],
33 ),
34 ),
@@ -38,5 +38,4 @@ class SettingsHeaderListRow extends StatelessWidget {
38 ],
39 );
40 }
41 -
42 -}
\ No newline at end of file
41 +}
lib/src/screens/settings/widgets/settings_link_list_row.dart
+6 -9
@@ -2,16 +2,16 @@ import 'package:flutter/material.dart';
2 import 'package:cake_wallet/palette.dart';
3
4 class SettingsLinktListRow extends StatelessWidget {
5 + SettingsLinktListRow(
6 + {@required this.onTaped, this.title, this.link, this.image});
7 +
8 final VoidCallback onTaped;
9 final String title;
10 final String link;
11 final Image image;
12
10 - SettingsLinktListRow({@required this.onTaped, this.title, this.link, this.image});
11 -
13 @override
14 Widget build(BuildContext context) {
14 -
15 return Container(
16 color: Theme.of(context).accentTextTheme.headline.backgroundColor,
17 child: ListTile(
@@ -28,20 +28,17 @@ class SettingsLinktListRow extends StatelessWidget {
28 style: TextStyle(
29 fontSize: 15.0,
30 fontWeight: FontWeight.w500,
31 - color: Theme.of(context).primaryTextTheme.title.color
32 - ),
31 + color: Theme.of(context).primaryTextTheme.title.color),
32 ),
33 )
34 ],
35 ),
36 trailing: Text(
37 link,
39 - style:
40 - TextStyle(fontSize: 14.0, color: Palette.cakeGreen),
38 + style: TextStyle(fontSize: 14.0, color: Palette.cakeGreen),
39 ),
40 onTap: onTaped,
41 ),
42 );
43 }
46 -
47 -}
\ No newline at end of file
44 +}
lib/src/screens/settings/widgets/settings_raw_widget_list_row.dart
+2 -3
@@ -1,13 +1,12 @@
1 import 'package:flutter/material.dart';
2
3 class SettingRawWidgetListRow extends StatelessWidget {
4 - final WidgetBuilder widgetBuilder;
5 -
4 SettingRawWidgetListRow({@required this.widgetBuilder});
5
6 + final WidgetBuilder widgetBuilder;
7 +
8 @override
9 Widget build(BuildContext context) {
10 -
10 return Container(
11 color: Theme.of(context).accentTextTheme.headline.backgroundColor,
12 child: widgetBuilder(context) ?? Container(),
lib/src/screens/settings/widgets/settings_switch_list_row.dart
+6 -6
@@ -8,13 +8,13 @@ import 'package:cake_wallet/src/stores/settings/settings_store.dart';
8 import 'package:cake_wallet/src/widgets/standart_switch.dart';
9
10 class SettingsSwitchListRow extends StatelessWidget {
11 - final String title;
12 -
11 SettingsSwitchListRow({@required this.title});
12
13 + final String title;
14 +
15 Widget _getSwitch(BuildContext context) {
16 final settingsStore = Provider.of<SettingsStore>(context);
17 - ThemeChanger _themeChanger = Provider.of<ThemeChanger>(context);
17 + final _themeChanger = Provider.of<ThemeChanger>(context);
18
19 if (settingsStore.itemHeaders[title] ==
20 S.of(context).settings_save_recipient_address) {
@@ -22,7 +22,7 @@ class SettingsSwitchListRow extends StatelessWidget {
22 builder: (_) => StandartSwitch(
23 value: settingsStore.shouldSaveRecipientAddress,
24 onTaped: () {
25 - bool _currentValue = !settingsStore.shouldSaveRecipientAddress;
25 + final _currentValue = !settingsStore.shouldSaveRecipientAddress;
26 settingsStore.setSaveRecipientAddress(
27 shouldSaveRecipientAddress: _currentValue);
28 }));
@@ -34,7 +34,7 @@ class SettingsSwitchListRow extends StatelessWidget {
34 builder: (_) => StandartSwitch(
35 value: settingsStore.allowBiometricalAuthentication,
36 onTaped: () {
37 - bool _currentValue =
37 + final _currentValue =
38 !settingsStore.allowBiometricalAuthentication;
39 settingsStore.setAllowBiometricalAuthentication(
40 allowBiometricalAuthentication: _currentValue);
@@ -46,7 +46,7 @@ class SettingsSwitchListRow extends StatelessWidget {
46 builder: (_) => StandartSwitch(
47 value: settingsStore.isDarkTheme,
48 onTaped: () {
49 - bool _currentValue = !settingsStore.isDarkTheme;
49 + final _currentValue = !settingsStore.isDarkTheme;
50 settingsStore.saveDarkTheme(isDarkTheme: _currentValue);
51 _themeChanger.setTheme(
52 _currentValue ? Themes.darkTheme : Themes.lightTheme);
lib/src/screens/settings/widgets/settings_text_list_row.dart
+2 -2
@@ -4,12 +4,12 @@ import 'package:flutter_mobx/flutter_mobx.dart';
4 import 'package:cake_wallet/src/stores/settings/settings_store.dart';
5
6 class SettingsTextListRow extends StatelessWidget {
7 + SettingsTextListRow({@required this.onTaped, this.title, this.widget});
8 +
9 final VoidCallback onTaped;
10 final String title;
11 final Widget widget;
12
11 - SettingsTextListRow({@required this.onTaped, this.title, this.widget});
12 -
13 @override
14 Widget build(BuildContext context) {
15 final settingsStore = Provider.of<SettingsStore>(context);
lib/src/screens/setup_pin_code/setup_pin_code.dart
+12 -13
@@ -9,24 +9,24 @@ import 'package:cake_wallet/src/stores/settings/settings_store.dart';
9 import 'package:cake_wallet/generated/i18n.dart';
10
11 class SetupPinCodePage extends BasePage {
12 + SetupPinCodePage({this.onPinCodeSetup});
13 +
14 final Function(BuildContext, String) onPinCodeSetup;
15
16 @override
17 String get title => S.current.setup_pin;
18
17 - SetupPinCodePage({this.onPinCodeSetup});
18 -
19 @override
20 Widget body(BuildContext context) =>
21 SetupPinCodeForm(onPinCodeSetup: onPinCodeSetup, hasLengthSwitcher: true);
22 }
23
24 class SetupPinCodeForm extends PinCodeWidget {
25 - final Function(BuildContext, String) onPinCodeSetup;
26 - final bool hasLengthSwitcher;
27 -
25 SetupPinCodeForm(
29 - {@required this.onPinCodeSetup, @required this.hasLengthSwitcher});
26 + {@required this.onPinCodeSetup, @required bool hasLengthSwitcher})
27 + : super(hasLengthSwitcher: hasLengthSwitcher);
28 +
29 + final Function(BuildContext, String) onPinCodeSetup;
30
31 @override
32 _SetupPinCodeFormState createState() => _SetupPinCodeFormState();
@@ -34,17 +34,16 @@ class SetupPinCodeForm extends PinCodeWidget {
34
35 class _SetupPinCodeFormState<WidgetType extends SetupPinCodeForm>
36 extends PinCodeState<WidgetType> {
37 + _SetupPinCodeFormState() {
38 + title = S.current.enter_your_pin;
39 + }
40
38 - bool isEnteredOriginalPin() => !(_originalPin.length == 0);
41 + bool isEnteredOriginalPin() => _originalPin.isNotEmpty;
42 Function(BuildContext) onPinCodeSetup;
43 List<int> _originalPin = [];
44 UserStore _userStore;
45 SettingsStore _settingsStore;
46
44 - _SetupPinCodeFormState() {
45 - title = S.current.enter_your_pin;
46 - }
47 -
47 @override
48 void onPinCodeEntered(PinCodeState state) {
49 if (!isEnteredOriginalPin()) {
@@ -57,7 +56,7 @@ class _SetupPinCodeFormState<WidgetType extends SetupPinCodeForm>
56 _userStore.set(password: pin);
57 _settingsStore.setDefaultPinLength(pinLength: state.pinLength);
58
60 - showDialog(
59 + showDialog<void>(
60 context: context,
61 barrierDismissible: false,
62 builder: (BuildContext context) {
@@ -76,7 +75,7 @@ class _SetupPinCodeFormState<WidgetType extends SetupPinCodeForm>
75 );
76 });
77 } else {
79 - showDialog(
78 + showDialog<void>(
79 context: context,
80 builder: (BuildContext context) {
81 return AlertDialog(
lib/src/screens/show_keys/show_keys_page.dart
+4 -1
@@ -9,7 +9,10 @@ import 'package:cake_wallet/src/stores/wallet/wallet_keys_store.dart';
9 import 'package:cake_wallet/src/screens/base_page.dart';
10
11 class ShowKeysPage extends BasePage {
12 + @override
13 bool get isModalBackButton => true;
14 +
15 + @override
16 String get title => S.current.wallet_keys;
17
18 @override
@@ -20,7 +23,7 @@ class ShowKeysPage extends BasePage {
23 padding: EdgeInsets.only(top: 20.0, bottom: 20.0, left: 20, right: 20),
24 child: Observer(
25 builder: (_) {
23 - Map<String, String> keysMap = {
26 + final keysMap = {
27 S.of(context).view_key_public: walletKeysStore.publicViewKey,
28 S.of(context).view_key_private: walletKeysStore.privateViewKey,
29 S.of(context).spend_key_public: walletKeysStore.publicSpendKey,
lib/src/screens/subaddress/new_subaddress_page.dart
+4 -3
@@ -11,6 +11,7 @@ import 'package:cake_wallet/src/screens/base_page.dart';
11 import 'package:cake_wallet/palette.dart';
12
13 class NewSubaddressPage extends BasePage {
14 + @override
15 String get title => S.current.new_subaddress_title;
16
17 @override
@@ -21,7 +22,7 @@ class NewSubaddressPage extends BasePage {
22 final subaddressCreationStore =
23 Provider.of<SubadrressCreationStore>(context);
24
24 - reaction((_) => subaddressCreationStore.state, (state) {
25 + reaction((_) => subaddressCreationStore.state, (SubaddressCreationState state) {
26 if (state is SubaddressCreatedSuccessfully) {
27 WidgetsBinding.instance
28 .addPostFrameCallback((_) => Navigator.of(context).pop());
@@ -58,8 +59,8 @@ class NewSubaddressFormState extends State<NewSubaddressForm> {
59 hintStyle: TextStyle(color: Theme.of(context).hintColor),
60 hintText: S.of(context).new_subaddress_label_name,
61 focusedBorder: UnderlineInputBorder(
61 - borderSide: BorderSide(
62 - color: Palette.cakeGreen, width: 2.0)),
62 + borderSide:
63 + BorderSide(color: Palette.cakeGreen, width: 2.0)),
64 enabledBorder: UnderlineInputBorder(
65 borderSide: BorderSide(
66 color: Theme.of(context).focusColor,
lib/src/screens/subaddress/subaddress_list_page.dart
+7 -2
@@ -8,11 +8,16 @@ import 'package:cake_wallet/src/stores/wallet/wallet_store.dart';
8 import 'package:cake_wallet/src/screens/base_page.dart';
9
10 class SubaddressListPage extends BasePage {
11 + SubaddressListPage();
12 +
13 + @override
14 bool get isModalBackButton => true;
15 +
16 + @override
17 String get title => S.current.subaddress_title;
13 - AppBarStyle get appBarStyle => AppBarStyle.withShadow;
18
15 - SubaddressListPage();
19 + @override
20 + AppBarStyle get appBarStyle => AppBarStyle.withShadow;
21
22 @override
23 Widget body(BuildContext context) {
lib/src/screens/trade_details/trade_details_page.dart
+5 -1
@@ -10,7 +10,10 @@ import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.d
10 import 'package:cake_wallet/src/screens/transaction_details/standart_list_row.dart';
11
12 class TradeDetailsPage extends BasePage {
13 + @override
14 String get title => S.current.trade_details_title;
15 +
16 + @override
17 bool get isModalBackButton => true;
18
19 @override
@@ -54,7 +57,8 @@ class TradeDetailsPage extends BasePage {
57 color: Theme.of(context).dividerTheme.color,
58 height: 1.0,
59 ),
57 - padding: EdgeInsets.only(left: 25, top: 10, right: 25, bottom: 15),
60 + padding:
61 + EdgeInsets.only(left: 25, top: 10, right: 25, bottom: 15),
62 itemCount: items.length,
63 itemBuilder: (BuildContext context, int index) {
64 final item = items[index];
lib/src/screens/transaction_details/standart_list_item.dart
+3 -3
@@ -1,6 +1,6 @@
1 class StandartListItem {
2 + StandartListItem({this.title, this.value});
3 +
4 final String title;
5 final String value;
4 -
5 - StandartListItem({this.title, this.value});
6 -}
\ No newline at end of file
6 +}
lib/src/screens/transaction_details/standart_list_row.dart
+3 -6
@@ -2,14 +2,13 @@ import 'package:flutter/material.dart';
2 import 'package:cake_wallet/palette.dart';
3
4 class StandartListRow extends StatelessWidget {
5 + StandartListRow({this.title, this.value});
6 +
7 final String title;
8 final String value;
9
8 - StandartListRow({this.title, this.value});
9 -
10 @override
11 Widget build(BuildContext context) {
12 -
12 return Padding(
13 padding: const EdgeInsets.only(top: 10, bottom: 10),
14 child: Column(
@@ -23,9 +22,7 @@ class StandartListRow extends StatelessWidget {
22 Padding(
23 padding: const EdgeInsets.only(top: 5),
24 child: Text(value,
26 - style: TextStyle(
27 - fontSize: 14,
28 - color: Palette.wildDarkBlue)),
25 + style: TextStyle(fontSize: 14, color: Palette.wildDarkBlue)),
26 )
27 ]),
28 );
lib/src/screens/transaction_details/transaction_details_page.dart
+16 -12
@@ -11,12 +11,15 @@ import 'package:cake_wallet/src/screens/transaction_details/standart_list_row.da
11 import 'package:cake_wallet/src/screens/base_page.dart';
12
13 class TransactionDetailsPage extends BasePage {
14 - bool get isModalBackButton => true;
15 - String get title => S.current.transaction_details_title;
14 + TransactionDetailsPage({this.transactionInfo});
15
16 final TransactionInfo transactionInfo;
17
19 - TransactionDetailsPage({this.transactionInfo});
18 + @override
19 + bool get isModalBackButton => true;
20 +
21 + @override
22 + String get title => S.current.transaction_details_title;
23
24 @override
25 Widget body(BuildContext context) {
@@ -28,23 +31,23 @@ class TransactionDetailsPage extends BasePage {
31 }
32
33 class TransactionDetailsForm extends StatefulWidget {
31 - final TransactionInfo transactionInfo;
32 - final SettingsStore settingsStore;
33 -
34 TransactionDetailsForm(
35 {@required this.transactionInfo, @required this.settingsStore});
36
37 + final TransactionInfo transactionInfo;
38 + final SettingsStore settingsStore;
39 +
40 @override
38 - createState() => TransactionDetailsFormState();
41 + TransactionDetailsFormState createState() => TransactionDetailsFormState();
42 }
43
44 class TransactionDetailsFormState extends State<TransactionDetailsForm> {
45 final DateFormat _dateFormat = DateFormat('dd.MM.yyyy, HH:mm');
43 - List<StandartListItem> _items = List<StandartListItem>();
46 + final _items = List<StandartListItem>();
47
48 @override
49 void initState() {
47 - List<StandartListItem> items = [
50 + final items = [
51 StandartListItem(
52 title: S.current.transaction_details_transaction_id,
53 value: widget.transactionInfo.id),
@@ -59,10 +62,11 @@ class TransactionDetailsFormState extends State<TransactionDetailsForm> {
62 value: widget.transactionInfo.amountFormatted())
63 ];
64
62 - if (widget.settingsStore.shouldSaveRecipientAddress && widget.transactionInfo.recipientAddress != null) {
65 + if (widget.settingsStore.shouldSaveRecipientAddress &&
66 + widget.transactionInfo.recipientAddress != null) {
67 items.add(StandartListItem(
64 - title: S.current.transaction_details_recipient_address,
65 - value: widget.transactionInfo.recipientAddress));
68 + title: S.current.transaction_details_recipient_address,
69 + value: widget.transactionInfo.recipientAddress));
70 }
71
72 _items.addAll(items);
lib/src/screens/wallet_list/wallet_list_page.dart
+9 -3
@@ -14,8 +14,13 @@ import 'package:cake_wallet/src/screens/wallet_list/wallet_menu.dart';
14 import 'package:cake_wallet/src/widgets/picker.dart';
15
16 class WalletListPage extends BasePage {
17 + @override
18 bool get isModalBackButton => true;
19 +
20 + @override
21 String get title => S.current.wallet_list_title;
22 +
23 + @override
24 AppBarStyle get appBarStyle => AppBarStyle.withShadow;
25
26 @override
@@ -23,6 +28,7 @@ class WalletListPage extends BasePage {
28 }
29
30 class WalletListBody extends StatefulWidget {
31 + @override
32 WalletListBodyState createState() => WalletListBodyState();
33 }
34
@@ -32,15 +38,15 @@ class WalletListBodyState extends State<WalletListBody> {
38 void presetMenuForWallet(WalletDescription wallet, bool isCurrentWallet,
39 BuildContext bodyContext) {
40 final walletMenu = WalletMenu(bodyContext);
35 - List<String> items = walletMenu.generateItemsForWalletMenu(isCurrentWallet);
41 + final items = walletMenu.generateItemsForWalletMenu(isCurrentWallet);
42
37 - showDialog(
43 + showDialog<void>(
44 context: bodyContext,
45 builder: (_) => Picker(
46 items: items,
47 selectedAtIndex: -1,
48 title: S.of(context).wallet_menu,
43 - onItemSelected: (item) => walletMenu.action(
49 + onItemSelected: (String item) => walletMenu.action(
50 walletMenu.listItems.indexOf(item), wallet, isCurrentWallet)),
51 );
52 }
lib/src/screens/wallet_list/wallet_menu.dart
+47 -43
@@ -1,13 +1,16 @@
1 -import 'package:cake_wallet/src/domain/common/wallet_description.dart';
1 import 'package:flutter/material.dart';
2 import 'package:cake_wallet/routes.dart';
3 import 'package:provider/provider.dart';
5 -import 'package:cake_wallet/src/stores/wallet_list/wallet_list_store.dart';
4 import 'package:cake_wallet/generated/i18n.dart';
5 +import 'package:cake_wallet/src/stores/wallet_list/wallet_list_store.dart';
6 +import 'package:cake_wallet/src/domain/common/wallet_description.dart';
7 +import 'package:cake_wallet/src/screens/auth/auth_page.dart';
8
9 class WalletMenu {
10 + WalletMenu(this.context);
11
12 final BuildContext context;
13 +
14 final List<String> listItems = [
15 S.current.wallet_list_load_wallet,
16 S.current.show_seed,
@@ -15,10 +18,8 @@ class WalletMenu {
18 S.current.rescan
19 ];
20
18 - WalletMenu(this.context);
19 -
20 - List<String>generateItemsForWalletMenu(bool isCurrentWallet) {
21 - List<String> items = new List<String>();
21 + List<String> generateItemsForWalletMenu(bool isCurrentWallet) {
22 + final items = List<String>();
23
24 if (!isCurrentWallet) items.add(listItems[0]);
25 if (isCurrentWallet) items.add(listItems[1]);
@@ -29,52 +30,56 @@ class WalletMenu {
30 }
31
32 void action(int index, WalletDescription wallet, bool isCurrentWallet) {
32 - WalletListStore _walletListStore = Provider.of<WalletListStore>(context);
33 + final _walletListStore = Provider.of<WalletListStore>(context);
34
35 switch (index) {
36 case 0:
36 - Navigator.of(context).pushNamed(Routes.auth,
37 - arguments: (isAuthenticatedSuccessfully, auth) async {
38 - if (!isAuthenticatedSuccessfully) {
39 - return;
40 - }
37 + Navigator.of(context).pushNamed(Routes.auth, arguments:
38 + (bool isAuthenticatedSuccessfully, AuthPageState auth) async {
39 + if (!isAuthenticatedSuccessfully) {
40 + return;
41 + }
42
42 - try {
43 - auth.changeProcessText(S.of(context).wallet_list_loading_wallet(wallet.name));
44 - await _walletListStore.loadWallet(wallet);
45 - auth.close();
46 - Navigator.of(context).pop();
47 - } catch (e) {
48 - auth.changeProcessText(
49 - S.of(context).wallet_list_failed_to_load(wallet.name, e.toString()));
50 - }
43 + try {
44 + auth.changeProcessText(
45 + S.of(context).wallet_list_loading_wallet(wallet.name));
46 + await _walletListStore.loadWallet(wallet);
47 + auth.close();
48 + Navigator.of(context).pop();
49 + } catch (e) {
50 + auth.changeProcessText(S
51 + .of(context)
52 + .wallet_list_failed_to_load(wallet.name, e.toString()));
53 + }
54 });
55 break;
56 case 1:
54 - Navigator.of(context).pushNamed(Routes.auth,
55 - arguments: (isAuthenticatedSuccessfully, auth) async {
56 - if (!isAuthenticatedSuccessfully) {
57 - return;
58 - }
59 - auth.close();
60 - Navigator.of(context).pushNamed(Routes.seed);
57 + Navigator.of(context).pushNamed(Routes.auth, arguments:
58 + (bool isAuthenticatedSuccessfully, AuthPageState auth) async {
59 + if (!isAuthenticatedSuccessfully) {
60 + return;
61 + }
62 + auth.close();
63 + await Navigator.of(context).pushNamed(Routes.seed);
64 });
65 break;
66 case 2:
64 - Navigator.of(context).pushNamed(Routes.auth,
65 - arguments: (isAuthenticatedSuccessfully, auth) async {
66 - if (!isAuthenticatedSuccessfully) {
67 - return;
68 - }
67 + Navigator.of(context).pushNamed(Routes.auth, arguments:
68 + (bool isAuthenticatedSuccessfully, AuthPageState auth) async {
69 + if (!isAuthenticatedSuccessfully) {
70 + return;
71 + }
72
70 - try {
71 - auth.changeProcessText(S.of(context).wallet_list_removing_wallet(wallet.name));
72 - await _walletListStore.remove(wallet);
73 - auth.close();
74 - } catch (e) {
75 - auth.changeProcessText(
76 - S.of(context).wallet_list_failed_to_remove(wallet.name, e.toString()));
77 - }
73 + try {
74 + auth.changeProcessText(
75 + S.of(context).wallet_list_removing_wallet(wallet.name));
76 + await _walletListStore.remove(wallet);
77 + auth.close();
78 + } catch (e) {
79 + auth.changeProcessText(S
80 + .of(context)
81 + .wallet_list_failed_to_remove(wallet.name, e.toString()));
82 + }
83 });
84 break;
85 case 3:
@@ -84,5 +89,4 @@ class WalletMenu {
89 break;
90 }
91 }
87 -
88 -}
\ No newline at end of file
92 +}
lib/src/screens/welcome/welcome_page.dart
+3 -11
@@ -1,11 +1,8 @@
1 import 'package:flutter/material.dart';
2 -import 'package:provider/provider.dart';
2 import 'package:cake_wallet/palette.dart';
3 import 'package:cake_wallet/routes.dart';
4 import 'package:cake_wallet/src/widgets/primary_button.dart';
5 import 'package:cake_wallet/src/screens/base_page.dart';
7 -import 'package:cake_wallet/theme_changer.dart';
8 -import 'package:cake_wallet/themes.dart';
6 import 'package:cake_wallet/generated/i18n.dart';
7
8 class WelcomePage extends BasePage {
@@ -16,15 +13,10 @@ class WelcomePage extends BasePage {
13
14 @override
15 Widget build(BuildContext context) {
19 - ThemeChanger _themeChanger = Provider.of<ThemeChanger>(context);
20 - bool _isDarkTheme = (_themeChanger.getTheme() == Themes.darkTheme);
21 -
16 return Scaffold(
23 - backgroundColor:
24 - _isDarkTheme ? Theme.of(context).backgroundColor : backgroundColor,
25 - resizeToAvoidBottomPadding: false,
26 - body: SafeArea(child: body(context)),
27 - );
17 + backgroundColor: Theme.of(context).backgroundColor,
18 + resizeToAvoidBottomPadding: false,
19 + body: SafeArea(child: body(context)));
20 }
21
22 @override
lib/src/start_updating_price.dart
+9 -6
@@ -1,4 +1,5 @@
1 import 'dart:async';
2 +import 'package:cake_wallet/src/domain/common/fiat_currency.dart';
3 import 'package:flutter/foundation.dart';
4 import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
5 import 'package:cake_wallet/src/domain/common/fetch_price.dart';
@@ -7,12 +8,14 @@ import 'package:cake_wallet/src/stores/settings/settings_store.dart';
8
9 bool _startedUpdatingPrice = false;
10
10 -_updatePrice(Map args) async =>
11 - await fetchPriceFor(fiat: args['fiat'], crypto: args['crypto']);
11 +Future<double> _updatePrice(Map args) async => await fetchPriceFor(
12 + fiat: args['fiat'] as FiatCurrency,
13 + crypto: args['crypto'] as CryptoCurrency);
14
13 -updatePrice(Map args) async => compute(_updatePrice, args);
15 +Future<double> updatePrice(Map args) async => compute(_updatePrice, args);
16
15 -startUpdatingPrice({SettingsStore settingsStore, PriceStore priceStore}) async {
17 +Future<void> startUpdatingPrice(
18 + {SettingsStore settingsStore, PriceStore priceStore}) async {
19 if (_startedUpdatingPrice) {
20 return;
21 }
@@ -21,13 +24,13 @@ startUpdatingPrice({SettingsStore settingsStore, PriceStore priceStore}) async {
24 _startedUpdatingPrice = true;
25
26 final price = await updatePrice(
24 - {'fiat': settingsStore.fiatCurrency, 'crypto': currentCrypto});
27 + <String, dynamic>{'fiat': settingsStore.fiatCurrency, 'crypto': currentCrypto});
28 priceStore.changePriceForPair(
29 fiat: settingsStore.fiatCurrency, crypto: currentCrypto, price: price);
30
31 Timer.periodic(Duration(seconds: 30), (_) async {
32 final price = await updatePrice(
30 - {'fiat': settingsStore.fiatCurrency, 'crypto': currentCrypto});
33 + <String, dynamic>{'fiat': settingsStore.fiatCurrency, 'crypto': currentCrypto});
34 priceStore.changePriceForPair(
35 fiat: settingsStore.fiatCurrency, crypto: currentCrypto, price: price);
36 });
lib/src/stores/account_list/account_list_store.dart
+20 -20
@@ -13,6 +13,18 @@ part 'account_list_store.g.dart';
13 class AccountListStore = AcountListStoreBase with _$AccountListStore;
14
15 abstract class AcountListStoreBase with Store {
16 + AcountListStoreBase({@required WalletService walletService}) {
17 + accounts = [];
18 + isAccountCreating = false;
19 +
20 + if (walletService.currentWallet != null) {
21 + _onWalletChanged(walletService.currentWallet);
22 + }
23 +
24 + _onWalletChangeSubscription =
25 + walletService.onWalletChange.listen(_onWalletChanged);
26 + }
27 +
28 @observable
29 List<Account> accounts;
30
@@ -29,18 +41,6 @@ abstract class AcountListStoreBase with Store {
41 StreamSubscription<Wallet> _onWalletChangeSubscription;
42 StreamSubscription<List<Account>> _onAccountsChangeSubscription;
43
32 - AcountListStoreBase({@required WalletService walletService}) {
33 - accounts = [];
34 - isAccountCreating = false;
35 -
36 - if (walletService.currentWallet != null) {
37 - _onWalletChanged(walletService.currentWallet);
38 - }
39 -
40 - _onWalletChangeSubscription =
41 - walletService.onWalletChange.listen(_onWalletChanged);
42 - }
43 -
44 @override
45 void dispose() {
46 _onWalletChangeSubscription.cancel();
@@ -52,8 +52,8 @@ abstract class AcountListStoreBase with Store {
52 super.dispose();
53 }
54
55 - Future updateAccountList() async {
56 - await _accountList.refresh();
55 + void updateAccountList() {
56 + _accountList.refresh();
57 accounts = _accountList.getAll();
58 }
59
@@ -61,7 +61,7 @@ abstract class AcountListStoreBase with Store {
61 try {
62 isAccountCreating = true;
63 await _accountList.addAccount(label: label);
64 - await updateAccountList();
64 + updateAccountList();
65 isAccountCreating = false;
66 } catch (e) {
67 isAccountCreating = false;
@@ -70,19 +70,19 @@ abstract class AcountListStoreBase with Store {
70
71 Future renameAccount({int index, String label}) async {
72 await _accountList.setLabelSubaddress(accountIndex: index, label: label);
73 - await updateAccountList();
73 + updateAccountList();
74 }
75
76 Future _onWalletChanged(Wallet wallet) async {
77 if (_onAccountsChangeSubscription != null) {
78 - _onAccountsChangeSubscription.cancel();
78 + await _onAccountsChangeSubscription.cancel();
79 }
80
81 if (wallet is MoneroWallet) {
82 _accountList = wallet.getAccountList();
83 _onAccountsChangeSubscription =
84 _accountList.accounts.listen((accounts) => this.accounts = accounts);
85 - await updateAccountList();
85 + updateAccountList();
86
87 return;
88 }
@@ -91,8 +91,8 @@ abstract class AcountListStoreBase with Store {
91 }
92
93 void validateAccountName(String value) {
94 - String p = '^[a-zA-Z0-9_]{1,15}\$';
95 - RegExp regExp = new RegExp(p);
94 + const pattern = '^[a-zA-Z0-9_]{1,15}\$';
95 + final regExp = RegExp(pattern);
96 isValid = regExp.hasMatch(value);
97 errorMessage = isValid ? null : S.current.error_text_account_name;
98 }
lib/src/stores/action_list/action_list_display_mode.dart
+1 -1
@@ -18,7 +18,7 @@ int serializeActionlistDisplayModes(List<ActionListDisplayMode> modes) {
18 }
19
20 List<ActionListDisplayMode> deserializeActionlistDisplayModes(int raw) {
21 - List<ActionListDisplayMode> modes = [];
21 + final modes = List<ActionListDisplayMode>();
22
23 if (raw == 1 || raw - 10 == 1) {
24 modes.add(ActionListDisplayMode.trades);
lib/src/stores/action_list/action_list_store.dart
+33 -33
@@ -28,8 +28,36 @@ part 'action_list_store.g.dart';
28 class ActionListStore = ActionListBase with _$ActionListStore;
29
30 abstract class ActionListBase with Store {
31 + ActionListBase(
32 + {@required WalletService walletService,
33 + @required SettingsStore settingsStore,
34 + @required PriceStore priceStore,
35 + @required this.transactionFilterStore,
36 + @required this.tradeFilterStore,
37 + @required this.transactionDescriptions,
38 + @required this.tradesSource}) {
39 + trades = List<TradeListItem>();
40 + _transactions = List<TransactionListItem>();
41 + _walletService = walletService;
42 + _settingsStore = settingsStore;
43 + _priceStore = priceStore;
44 +
45 + if (walletService.currentWallet != null) {
46 + _onWalletChanged(walletService.currentWallet);
47 + }
48 +
49 + _onWalletChangeSubscription =
50 + walletService.onWalletChange.listen(_onWalletChanged);
51 +
52 + _onTransactionDescriptions = transactionDescriptions
53 + .watch()
54 + .listen((_) async => await _updateTransactionsList());
55 +
56 + updateTradeList();
57 + }
58 +
59 static List<ActionListItem> formattedItemsList(List<ActionListItem> items) {
32 - var formattedList = List<ActionListItem>();
60 + final formattedList = List<ActionListItem>();
61 DateTime lastDate;
62 items.sort((a, b) => b.date.compareTo(a.date));
63
@@ -84,7 +112,7 @@ abstract class ActionListBase with Store {
112
113 @computed
114 List<ActionListItem> get items {
87 - var _items = List<ActionListItem>();
115 + final _items = List<ActionListItem>();
116
117 if (_settingsStore.actionlistDisplayMode
118 .contains(ActionListDisplayMode.transactions)) {
@@ -118,34 +146,6 @@ abstract class ActionListBase with Store {
146 StreamSubscription<Account> _onAccountChangeSubscription;
147 StreamSubscription<BoxEvent> _onTransactionDescriptions;
148
121 - ActionListBase(
122 - {@required WalletService walletService,
123 - @required SettingsStore settingsStore,
124 - @required PriceStore priceStore,
125 - @required this.transactionFilterStore,
126 - @required this.tradeFilterStore,
127 - @required this.transactionDescriptions,
128 - @required this.tradesSource}) {
129 - trades = List<TradeListItem>();
130 - _transactions = List<TransactionListItem>();
131 - _walletService = walletService;
132 - _settingsStore = settingsStore;
133 - _priceStore = priceStore;
134 -
135 - if (walletService.currentWallet != null) {
136 - _onWalletChanged(walletService.currentWallet);
137 - }
138 -
139 - _onWalletChangeSubscription =
140 - walletService.onWalletChange.listen(_onWalletChanged);
141 -
142 - _onTransactionDescriptions = transactionDescriptions
143 - .watch()
144 - .listen((_) async => await _updateTransactionsList());
145 -
146 - updateTradeList();
147 - }
148 -
149 @override
150 void dispose() {
151 if (_onTransactionsChangeSubscription != null) {
@@ -174,11 +174,11 @@ abstract class ActionListBase with Store {
174
175 Future _onWalletChanged(Wallet wallet) async {
176 if (_onTransactionsChangeSubscription != null) {
177 - _onTransactionsChangeSubscription.cancel();
177 + await _onTransactionsChangeSubscription.cancel();
178 }
179
180 if (_onAccountChangeSubscription != null) {
181 - _onAccountChangeSubscription.cancel();
181 + await _onAccountChangeSubscription.cancel();
182 }
183
184 _history = wallet.getHistory();
@@ -199,7 +199,7 @@ abstract class ActionListBase with Store {
199 Future _setTransactions(List<TransactionInfo> transactions) async {
200 final wallet = _walletService.currentWallet;
201 List<TransactionInfo> sortedTransactions = transactions.map((transaction) {
202 - if (transactionDescriptions.values.length > 0) {
202 + if (transactionDescriptions.values.isNotEmpty) {
203 final description = transactionDescriptions.values.firstWhere(
204 (desc) => desc.id == transaction.id,
205 orElse: () => null);
lib/src/stores/action_list/date_section_item.dart
+3 -2
@@ -1,7 +1,8 @@
1 import 'package:cake_wallet/src/stores/action_list/action_list_item.dart';
2
3 class DateSectionItem extends ActionListItem {
4 - final DateTime date;
5 -
4 DateSectionItem(this.date);
5 +
6 + @override
7 + final DateTime date;
8 }
\ No newline at end of file
lib/src/stores/action_list/trade_filter_store.dart
+6 -7
@@ -8,6 +8,11 @@ part 'trade_filter_store.g.dart';
8 class TradeFilterStore = TradeFilterStoreBase with _$TradeFilterStore;
9
10 abstract class TradeFilterStoreBase with Store {
11 + TradeFilterStoreBase(
12 + {this.displayXMRTO = true,
13 + this.displayChangeNow = true,
14 + this.walletStore});
15 +
16 @observable
17 bool displayXMRTO;
18
@@ -16,11 +21,6 @@ abstract class TradeFilterStoreBase with Store {
21
22 WalletStore walletStore;
23
19 - TradeFilterStoreBase(
20 - {this.displayXMRTO = true,
21 - this.displayChangeNow = true,
22 - this.walletStore});
23 -
24 @action
25 void toggleDisplayExchange(ExchangeProviderDescription provider) {
26 switch (provider) {
@@ -34,9 +34,8 @@ abstract class TradeFilterStoreBase with Store {
34 }
35
36 List<TradeListItem> filtered({List<TradeListItem> trades}) {
37 - List<TradeListItem> _trades =
37 + final _trades =
38 trades.where((item) => item.trade.walletId == walletStore.id).toList();
39 -
39 final needToFilter = !displayChangeNow || !displayXMRTO;
40
41 return needToFilter
lib/src/stores/action_list/trade_list_item.dart
+4 -3
@@ -2,9 +2,10 @@ import 'package:cake_wallet/src/domain/exchange/trade.dart';
2 import 'package:cake_wallet/src/stores/action_list/action_list_item.dart';
3
4 class TradeListItem extends ActionListItem {
5 + TradeListItem({this.trade});
6 +
7 final Trade trade;
8
9 + @override
10 DateTime get date => trade.createdAt;
8 -
9 - TradeListItem({this.trade});
10 -}
\ No newline at end of file
11 +}
lib/src/stores/action_list/transaction_filter_store.dart
+3 -3
@@ -8,6 +8,9 @@ class TransactionFilterStore = TransactionFilterStoreBase
8 with _$TransactionFilterStore;
9
10 abstract class TransactionFilterStoreBase with Store {
11 + TransactionFilterStoreBase(
12 + {this.displayIncoming = true, this.displayOutgoing = true});
13 +
14 @observable
15 bool displayIncoming;
16
@@ -20,9 +23,6 @@ abstract class TransactionFilterStoreBase with Store {
23 @observable
24 DateTime endDate;
25
23 - TransactionFilterStoreBase(
24 - {this.displayIncoming = true, this.displayOutgoing = true});
25 -
26 @action
27 void toggleIncoming() => displayIncoming = !displayIncoming;
28
lib/src/stores/action_list/transaction_list_item.dart
+3 -2
@@ -2,9 +2,10 @@ import 'package:cake_wallet/src/domain/common/transaction_info.dart';
2 import 'package:cake_wallet/src/stores/action_list/action_list_item.dart';
3
4 class TransactionListItem extends ActionListItem {
5 + TransactionListItem({this.transaction});
6 +
7 final TransactionInfo transaction;
8
9 + @override
10 DateTime get date => transaction.date;
8 -
9 - TransactionListItem({this.transaction});
11 }
\ No newline at end of file
lib/src/stores/address_book/address_book_store.dart
+10 -8
@@ -10,6 +10,10 @@ part 'address_book_store.g.dart';
10 class AddressBookStore = AddressBookStoreBase with _$AddressBookStore;
11
12 abstract class AddressBookStoreBase with Store {
13 + AddressBookStoreBase({@required this.contacts}) {
14 + updateContactList();
15 + }
16 +
17 @observable
18 List<Contact> contactList;
19
@@ -21,10 +25,6 @@ abstract class AddressBookStoreBase with Store {
25
26 Box<Contact> contacts;
27
24 - AddressBookStoreBase({@required this.contacts}) {
25 - updateContactList();
26 - }
27 -
28 @action
29 Future add({Contact contact}) async => contacts.add(contact);
30
@@ -38,17 +38,18 @@ abstract class AddressBookStoreBase with Store {
38 Future delete({Contact contact}) async => await contact.delete();
39
40 void validateContactName(String value) {
41 - String p = '''^[^`,'"]{1,32}\$''';
42 - RegExp regExp = new RegExp(p);
41 + const pattern = '''^[^`,'"]{1,32}\$''';
42 + final regExp = RegExp(pattern);
43 isValid = regExp.hasMatch(value);
44 errorMessage = isValid ? null : S.current.error_text_contact_name;
45 }
46
47 void validateAddress(String value, {CryptoCurrency cryptoCurrency}) {
48 // XMR (95), BTC (34), ETH (42), LTC (34), BCH (42), DASH (34)
49 - String p = '^[0-9a-zA-Z]{95}\$|^[0-9a-zA-Z]{34}\$|^[0-9a-zA-Z]{42}\$';
50 - RegExp regExp = new RegExp(p);
49 + const pattern = '^[0-9a-zA-Z]{95}\$|^[0-9a-zA-Z]{34}\$|^[0-9a-zA-Z]{42}\$';
50 + final regExp = RegExp(pattern);
51 isValid = regExp.hasMatch(value);
52 +
53 if (isValid && cryptoCurrency != null) {
54 switch (cryptoCurrency.toString()) {
55 case 'XMR':
@@ -70,6 +71,7 @@ abstract class AddressBookStoreBase with Store {
71 isValid = (value.length == 34);
72 }
73 }
74 +
75 errorMessage = isValid ? null : S.current.error_text_address;
76 }
77 }
lib/src/stores/auth/auth_state.dart
+4 -4
@@ -7,14 +7,14 @@ class AuthenticationInProgress extends AuthState {}
7 class AuthenticatedSuccessfully extends AuthState {}
8
9 class AuthenticationFailure extends AuthState {
10 - final String error;
11 -
10 AuthenticationFailure({this.error});
13 -}
11
15 -class AuthenticationBanned extends AuthState {
12 final String error;
13 +}
14
15 +class AuthenticationBanned extends AuthState {
16 AuthenticationBanned({this.error});
17 +
18 + final String error;
19 }
20
lib/src/stores/auth/auth_store.dart
+8 -8
@@ -12,6 +12,14 @@ part 'auth_store.g.dart';
12 class AuthStore = AuthStoreBase with _$AuthStore;
13
14 abstract class AuthStoreBase with Store {
15 + AuthStoreBase(
16 + {@required this.userService,
17 + @required this.walletService,
18 + @required this.sharedPreferences}) {
19 + state = AuthenticationStateInitial();
20 + _failureCounter = 0;
21 + }
22 +
23 static const maxFailedLogins = 3;
24 static const banTimeout = 180; // 3 mins
25 final banTimeoutKey = S.current.auth_store_ban_timeout;
@@ -27,14 +35,6 @@ abstract class AuthStoreBase with Store {
35 @observable
36 int _failureCounter;
37
30 - AuthStoreBase(
31 - {@required this.userService,
32 - @required this.walletService,
33 - @required this.sharedPreferences}) {
34 - state = AuthenticationStateInitial();
35 - _failureCounter = 0;
36 - }
37 -
38 @action
39 Future auth({String password}) async {
40 state = AuthenticationStateInitial();
lib/src/stores/authentication/authentication_store.dart
+4 -4
@@ -21,6 +21,10 @@ enum AuthenticationState {
21 }
22
23 abstract class AuthenticationStoreBase with Store {
24 + AuthenticationStoreBase({@required this.userService}) {
25 + state = AuthenticationState.uninitialized;
26 + }
27 +
28 final UserService userService;
29
30 @observable
@@ -29,10 +33,6 @@ abstract class AuthenticationStoreBase with Store {
33 @observable
34 String errorMessage;
35
32 - AuthenticationStoreBase({@required this.userService}) {
33 - state = AuthenticationState.uninitialized;
34 - }
35 -
36 Future started() async {
37 final canAuth = await userService.canAuthenticate();
38 state = canAuth ? AuthenticationState.allowed : AuthenticationState.denied;
lib/src/stores/balance/balance_store.dart
+22 -22
@@ -15,6 +15,27 @@ part 'balance_store.g.dart';
15 class BalanceStore = BalanceStoreBase with _$BalanceStore;
16
17 abstract class BalanceStoreBase with Store {
18 + BalanceStoreBase(
19 + {String fullBalance = '0.0',
20 + String unlockedBalance = '0.0',
21 + @required WalletService walletService,
22 + @required SettingsStore settingsStore,
23 + @required PriceStore priceStore}) {
24 + fullBalance = fullBalance;
25 + unlockedBalance = unlockedBalance;
26 + isReversing = false;
27 + _walletService = walletService;
28 + _settingsStore = settingsStore;
29 + _priceStore = priceStore;
30 +
31 + if (_walletService.currentWallet != null) {
32 + _onWalletChanged(_walletService.currentWallet);
33 + }
34 +
35 + _onWalletChangeSubscription = _walletService.onWalletChange
36 + .listen((wallet) => _onWalletChanged(wallet));
37 + }
38 +
39 @observable
40 String fullBalance;
41
@@ -54,27 +75,6 @@ abstract class BalanceStoreBase with Store {
75 SettingsStore _settingsStore;
76 PriceStore _priceStore;
77
57 - BalanceStoreBase(
58 - {String fullBalance = '0.0',
59 - String unlockedBalance = '0.0',
60 - @required WalletService walletService,
61 - @required SettingsStore settingsStore,
62 - @required PriceStore priceStore}) {
63 - fullBalance = fullBalance;
64 - unlockedBalance = unlockedBalance;
65 - isReversing = false;
66 - _walletService = walletService;
67 - _settingsStore = settingsStore;
68 - _priceStore = priceStore;
69 -
70 - if (_walletService.currentWallet != null) {
71 - _onWalletChanged(_walletService.currentWallet);
72 - }
73 -
74 - _onWalletChangeSubscription = _walletService.onWalletChange
75 - .listen((wallet) => _onWalletChanged(wallet));
76 - }
77 -
78 @override
79 void dispose() {
80 _onWalletChangeSubscription.cancel();
@@ -100,7 +100,7 @@ abstract class BalanceStoreBase with Store {
100
101 Future _onWalletChanged(Wallet wallet) async {
102 if (_onBalanceChangeSubscription != null) {
103 - _onBalanceChangeSubscription.cancel();
103 + await _onBalanceChangeSubscription.cancel();
104 }
105
106 _onBalanceChangeSubscription = _walletService.onBalanceChange
lib/src/stores/exchange/exchange_store.dart
+29 -30
@@ -19,6 +19,21 @@ part 'exchange_store.g.dart';
19 class ExchangeStore = ExchangeStoreBase with _$ExchangeStore;
20
21 abstract class ExchangeStoreBase with Store {
22 + ExchangeStoreBase(
23 + {@required ExchangeProvider initialProvider,
24 + @required CryptoCurrency initialDepositCurrency,
25 + @required CryptoCurrency initialReceiveCurrency,
26 + @required this.providerList,
27 + @required this.trades,
28 + @required this.walletStore}) {
29 + provider = initialProvider;
30 + depositCurrency = initialDepositCurrency;
31 + receiveCurrency = initialReceiveCurrency;
32 + limitsState = LimitsInitialState();
33 + tradeState = ExchangeTradeStateInitial();
34 + loadLimits();
35 + }
36 +
37 @observable
38 ExchangeProvider provider;
39
@@ -57,21 +72,6 @@ abstract class ExchangeStoreBase with Store {
72
73 WalletStore walletStore;
74
60 - ExchangeStoreBase(
61 - {@required ExchangeProvider initialProvider,
62 - @required CryptoCurrency initialDepositCurrency,
63 - @required CryptoCurrency initialReceiveCurrency,
64 - @required this.providerList,
65 - @required this.trades,
66 - @required this.walletStore}) {
67 - provider = initialProvider;
68 - depositCurrency = initialDepositCurrency;
69 - receiveCurrency = initialReceiveCurrency;
70 - limitsState = LimitsInitialState();
71 - tradeState = ExchangeTradeStateInitial();
72 - loadLimits();
73 - }
74 -
75 @action
76 void changeProvider({ExchangeProvider provider}) {
77 this.provider = provider;
@@ -190,12 +190,10 @@ abstract class ExchangeStoreBase with Store {
190 List<ExchangeProvider> _providersForPair(
191 {CryptoCurrency from, CryptoCurrency to}) {
192 final providers = providerList
193 - .where((provider) =>
194 - provider.pairList
195 - .where((pair) =>
196 - pair.from == depositCurrency && pair.to == receiveCurrency)
197 - .length >
198 - 0)
193 + .where((provider) => provider.pairList
194 + .where((pair) =>
195 + pair.from == depositCurrency && pair.to == receiveCurrency)
196 + .isNotEmpty)
197 .toList();
198
199 return providers;
@@ -203,10 +201,9 @@ abstract class ExchangeStoreBase with Store {
201
202 void _onPairChange() {
203 final isPairExist = provider.pairList
206 - .where((pair) =>
207 - pair.from == depositCurrency && pair.to == receiveCurrency)
208 - .length >
209 - 0;
204 + .where((pair) =>
205 + pair.from == depositCurrency && pair.to == receiveCurrency)
206 + .isNotEmpty;
207
208 if (!isPairExist) {
209 final provider =
@@ -225,14 +222,15 @@ abstract class ExchangeStoreBase with Store {
222
223 ExchangeProvider _providerForPair({CryptoCurrency from, CryptoCurrency to}) {
224 final providers = _providersForPair(from: from, to: to);
228 - return providers.length > 0 ? providers[0] : null;
225 + return providers.isNotEmpty ? providers[0] : null;
226 }
227
228 void validateAddress(String value, {CryptoCurrency cryptoCurrency}) {
229 // XMR (95), BTC (34), ETH (42), LTC (34), BCH (42), DASH (34)
233 - String p = '^[0-9a-zA-Z]{95}\$|^[0-9a-zA-Z]{34}\$|^[0-9a-zA-Z]{42}\$';
234 - RegExp regExp = new RegExp(p);
230 + const pattern = '^[0-9a-zA-Z]{95}\$|^[0-9a-zA-Z]{34}\$|^[0-9a-zA-Z]{42}\$';
231 + final regExp = RegExp(pattern);
232 isValid = regExp.hasMatch(value);
233 +
234 if (isValid && cryptoCurrency != null) {
235 switch (cryptoCurrency.toString()) {
236 case 'XMR':
@@ -254,12 +252,13 @@ abstract class ExchangeStoreBase with Store {
252 isValid = (value.length == 34);
253 }
254 }
255 +
256 errorMessage = isValid ? null : S.current.error_text_address;
257 }
258
259 void validateCryptoCurrency(String value) {
261 - String p = '^([0-9]+([.][0-9]{0,12})?|[.][0-9]{1,12})\$';
262 - RegExp regExp = new RegExp(p);
260 + const pattern = '^([0-9]+([.][0-9]{0,12})?|[.][0-9]{1,12})\$';
261 + final regExp = RegExp(pattern);
262 isValid = regExp.hasMatch(value);
263 errorMessage = isValid ? null : S.current.error_text_crypto_currency;
264 }
lib/src/stores/exchange/exchange_trade_state.dart
+4 -4
@@ -8,13 +8,13 @@ class ExchangeTradeStateInitial extends ExchangeTradeState {}
8 class TradeIsCreating extends ExchangeTradeState {}
9
10 class TradeIsCreatedSuccessfully extends ExchangeTradeState {
11 - final Trade trade;
12 -
11 TradeIsCreatedSuccessfully({@required this.trade});
12 +
13 + final Trade trade;
14 }
15
16 class TradeIsCreatedFailure extends ExchangeTradeState {
17 - final String error;
18 -
17 TradeIsCreatedFailure({@required this.error});
18 +
19 + final String error;
20 }
\ No newline at end of file
lib/src/stores/exchange/limits_state.dart
+4 -4
@@ -8,13 +8,13 @@ class LimitsInitialState extends LimitsState {}
8 class LimitsIsLoading extends LimitsState {}
9
10 class LimitsLoadedSuccessfully extends LimitsState {
11 - final Limits limits;
12 -
11 LimitsLoadedSuccessfully({@required this.limits});
12 +
13 + final Limits limits;
14 }
15
16 class LimitsLoadedFailure extends LimitsState {
17 - final String error;
18 -
17 LimitsLoadedFailure({@required this.error});
18 +
19 + final String error;
20 }
lib/src/stores/exchange_trade/exchange_trade_store.dart
+18 -16
@@ -13,18 +13,10 @@ part 'exchange_trade_store.g.dart';
13 class ExchangeTradeStore = ExchangeTradeStoreBase with _$ExchangeTradeStore;
14
15 abstract class ExchangeTradeStoreBase with Store {
16 - @observable
17 - Trade trade;
18 -
19 - @observable
20 - bool isSendable;
21 -
22 - ExchangeProvider _provider;
23 -
24 - Timer _timer;
25 -
26 - ExchangeTradeStoreBase({@required this.trade, @required WalletStore walletStore}) {
27 - isSendable = trade.from == walletStore.type || trade.provider == ExchangeProviderDescription.xmrto;
16 + ExchangeTradeStoreBase(
17 + {@required this.trade, @required WalletStore walletStore}) {
18 + isSendable = trade.from == walletStore.type ||
19 + trade.provider == ExchangeProviderDescription.xmrto;
20
21 switch (trade.provider) {
22 case ExchangeProviderDescription.xmrto:
@@ -34,25 +26,35 @@ abstract class ExchangeTradeStoreBase with Store {
26 _provider = ChangeNowExchangeProvider();
27 break;
28 }
37 -
29 +
30 _updateTrade();
31 _timer = Timer.periodic(Duration(seconds: 20), (_) async => _updateTrade());
32 }
33
34 + @observable
35 + Trade trade;
36 +
37 + @observable
38 + bool isSendable;
39 +
40 + ExchangeProvider _provider;
41 +
42 + Timer _timer;
43 +
44 @override
45 void dispose() {
46 super.dispose();
45 -
47 +
48 if (_timer != null) {
49 _timer.cancel();
50 }
51 }
52
53 @action
52 - Future _updateTrade() async {
54 + Future<void> _updateTrade() async {
55 try {
56 final updatedTrade = await _provider.findTradeById(id: trade.id);
55 -
57 +
58 if (updatedTrade.createdAt == null && trade.createdAt != null) {
59 updatedTrade.createdAt = trade.createdAt;
60 }
lib/src/stores/login/login_store.dart
+7 -7
@@ -14,25 +14,25 @@ class LoadingCurrentWallet extends LoginState {}
14 class LoadedCurrentWalletSuccessfully extends LoginState {}
15
16 class LoadedCurrentWalletFailure extends LoginState {
17 - final String errorMessage;
18 -
17 LoadedCurrentWalletFailure({this.errorMessage});
18 +
19 + final String errorMessage;
20 }
21
22 class LoginStore = LoginStoreBase with _$LoginStore;
23
24 abstract class LoginStoreBase with Store {
25 + LoginStoreBase(
26 + {@required this.sharedPreferences, @required this.walletsService}) {
27 + state = InitialLoginState();
28 + }
29 +
30 final SharedPreferences sharedPreferences;
31 final WalletListService walletsService;
32
33 @observable
34 LoginState state;
35
31 - LoginStoreBase(
32 - {@required this.sharedPreferences, @required this.walletsService}) {
33 - state = InitialLoginState();
34 - }
35 -
36 @action
37 Future loadCurrentWallet() async {
38 state = InitialLoginState();
lib/src/stores/node_list/node_list_store.dart
+16 -13
@@ -10,6 +10,12 @@ part 'node_list_store.g.dart';
10 class NodeListStore = NodeListBase with _$NodeListStore;
11
12 abstract class NodeListBase with Store {
13 + NodeListBase({this.nodesSource}) {
14 + nodes = ObservableList<Node>();
15 + _onNodesChangeSubscription = nodesSource.watch().listen((e) => update());
16 + update();
17 + }
18 +
19 @observable
20 ObservableList<Node> nodes;
21
@@ -23,12 +29,6 @@ abstract class NodeListBase with Store {
29
30 StreamSubscription<BoxEvent> _onNodesChangeSubscription;
31
26 - NodeListBase({this.nodesSource}) {
27 - nodes = ObservableList<Node>();
28 - _onNodesChangeSubscription = nodesSource.watch().listen((e) => update());
29 - update();
30 - }
31 -
32 @override
33 void dispose() {
34 super.dispose();
@@ -39,7 +39,7 @@ abstract class NodeListBase with Store {
39 }
40
41 @action
42 - update() async =>
42 + void update() =>
43 nodes.replaceRange(0, nodes.length, nodesSource.values.toList());
44
45 @action
@@ -71,25 +71,28 @@ abstract class NodeListBase with Store {
71 }
72
73 void validateNodeAddress(String value) {
74 - String p =
74 + const pattern =
75 '^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\$';
76 - RegExp regExp = new RegExp(p);
76 + final regExp = RegExp(pattern);
77 isValid = regExp.hasMatch(value);
78 errorMessage = isValid ? null : S.current.error_text_node_address;
79 }
80
81 void validateNodePort(String value) {
82 - String p = '^[0-9]{1,5}';
83 - RegExp regExp = new RegExp(p);
82 + const pattern = '^[0-9]{1,5}';
83 + final regExp = RegExp(pattern);
84 +
85 if (regExp.hasMatch(value)) {
86 try {
86 - int intValue = int.parse(value);
87 + final intValue = int.parse(value);
88 isValid = (intValue >= 0 && intValue <= 65535);
89 } catch (e) {
90 isValid = false;
91 }
91 - } else
92 + } else {
93 isValid = false;
94 + }
95 +
96 errorMessage = isValid ? null : S.current.error_text_node_port;
97 }
98 }
lib/src/stores/price/price_store.dart
+4 -3
@@ -8,6 +8,8 @@ part 'price_store.g.dart';
8 class PriceStore = PriceStoreBase with _$PriceStore;
9
10 abstract class PriceStoreBase with Store {
11 + PriceStoreBase() : prices = ObservableMap();
12 +
13 static String generateSymbolForPair(
14 {FiatCurrency fiat, CryptoCurrency crypto}) =>
15 crypto.toString().toUpperCase() + fiat.toString().toUpperCase();
@@ -15,8 +17,6 @@ abstract class PriceStoreBase with Store {
17 @observable
18 ObservableMap<String, double> prices;
19
18 - PriceStoreBase() : prices = ObservableMap();
19 -
20 @action
21 Future updatePrice({FiatCurrency fiat, CryptoCurrency crypto}) async {
22 final symbol = generateSymbolForPair(fiat: fiat, crypto: crypto);
@@ -25,7 +25,8 @@ abstract class PriceStoreBase with Store {
25 }
26
27 @action
28 - changePriceForPair({FiatCurrency fiat, CryptoCurrency crypto, double price}) {
28 + void changePriceForPair(
29 + {FiatCurrency fiat, CryptoCurrency crypto, double price}) {
30 final symbol = generateSymbolForPair(fiat: fiat, crypto: crypto);
31 prices[symbol] = price;
32 }
lib/src/stores/rescan/rescan_wallet_store.dart
+6 -8
@@ -6,21 +6,19 @@ part 'rescan_wallet_store.g.dart';
6
7 class RescanWalletStore = RescanWalletStoreBase with _$RescanWalletStore;
8
9 -enum RescanWalletState {
10 - rescaning, none
11 -}
9 +enum RescanWalletState { rescaning, none }
10
11 abstract class RescanWalletStoreBase with Store {
14 - @observable
15 - RescanWalletState state;
16 -
17 - WalletService _walletService;
18 -
12 RescanWalletStoreBase({@required WalletService walletService}) {
13 _walletService = walletService;
14 state = RescanWalletState.none;
15 }
16
17 + @observable
18 + RescanWalletState state;
19 +
20 + WalletService _walletService;
21 +
22 @action
23 Future rescanCurrentWallet({int restoreHeight}) async {
24 state = RescanWalletState.rescaning;
lib/src/stores/send/send_store.dart
+44 -34
@@ -17,6 +17,23 @@ part 'send_store.g.dart';
17 class SendStore = SendStoreBase with _$SendStore;
18
19 abstract class SendStoreBase with Store {
20 + SendStoreBase(
21 + {@required this.walletService,
22 + this.settingsStore,
23 + this.transactionDescriptions,
24 + this.priceStore}) {
25 + state = SendingStateInitial();
26 + _pendingTransaction = null;
27 + _cryptoNumberFormat = NumberFormat()..maximumFractionDigits = 12;
28 + _fiatNumberFormat = NumberFormat()..maximumFractionDigits = 2;
29 +
30 + reaction((_) => this.state, (SendingState state) async {
31 + if (state is TransactionCreatedSuccessfully) {
32 + await commitTransaction();
33 + }
34 + });
35 + }
36 +
37 WalletService walletService;
38 SettingsStore settingsStore;
39 PriceStore priceStore;
@@ -43,23 +60,6 @@ abstract class SendStoreBase with Store {
60 NumberFormat _fiatNumberFormat;
61 String _lastRecipientAddress;
62
46 - SendStoreBase(
47 - {@required this.walletService,
48 - this.settingsStore,
49 - this.transactionDescriptions,
50 - this.priceStore}) {
51 - state = SendingStateInitial();
52 - _pendingTransaction = null;
53 - _cryptoNumberFormat = NumberFormat()..maximumFractionDigits = 12;
54 - _fiatNumberFormat = NumberFormat()..maximumFractionDigits = 2;
55 -
56 - reaction((_) => this.state, (state) async {
57 - if (state is TransactionCreatedSuccessfully) {
58 - commitTransaction();
59 - }
60 - });
61 - }
62 -
63 @action
64 Future createTransaction(
65 {String address, String paymentId, String amount}) async {
@@ -160,9 +160,10 @@ abstract class SendStoreBase with Store {
160
161 void validateAddress(String value, {CryptoCurrency cryptoCurrency}) {
162 // XMR (95), BTC (34), ETH (42), LTC (34), BCH (42), DASH (34)
163 - String p = '^[0-9a-zA-Z]{95}\$|^[0-9a-zA-Z]{34}\$|^[0-9a-zA-Z]{42}\$';
164 - RegExp regExp = new RegExp(p);
163 + const pattern = '^[0-9a-zA-Z]{95}\$|^[0-9a-zA-Z]{34}\$|^[0-9a-zA-Z]{42}\$';
164 + final regExp = RegExp(pattern);
165 isValid = value == null ? false : regExp.hasMatch(value);
166 +
167 if (isValid && cryptoCurrency != null) {
168 switch (cryptoCurrency.toString()) {
169 case 'XMR':
@@ -184,6 +185,7 @@ abstract class SendStoreBase with Store {
185 isValid = (value.length == 34);
186 }
187 }
188 +
189 errorMessage = isValid ? null : S.current.error_text_address;
190 }
191
@@ -191,52 +193,60 @@ abstract class SendStoreBase with Store {
193 if (value.isEmpty) {
194 isValid = true;
195 } else {
194 - String p = '^[A-Fa-f0-9]{16,64}\$';
195 - RegExp regExp = new RegExp(p);
196 + const pattern = '^[A-Fa-f0-9]{16,64}\$';
197 + final regExp = RegExp(pattern);
198 isValid = regExp.hasMatch(value);
199 }
200 +
201 errorMessage = isValid ? null : S.current.error_text_payment_id;
202 }
203
204 void validateXMR(String value, String availableBalance) {
205 const double maxValue = 18446744.073709551616;
203 - String p = '^([0-9]+([.][0-9]{0,12})?|[.][0-9]{1,12})\$|ALL';
204 - RegExp regExp = new RegExp(p);
206 + const pattern = '^([0-9]+([.][0-9]{0,12})?|[.][0-9]{1,12})\$|ALL';
207 + final regExp = RegExp(pattern);
208 +
209 if (regExp.hasMatch(value)) {
206 - if (value == 'ALL')
210 + if (value == 'ALL') {
211 isValid = true;
208 - else {
212 + } else {
213 try {
210 - double dValue = double.parse(value);
211 - double maxAvailable = double.parse(availableBalance);
214 + final dValue = double.parse(value);
215 + final maxAvailable = double.parse(availableBalance);
216 isValid =
217 (dValue <= maxAvailable && dValue <= maxValue && dValue > 0);
218 } catch (e) {
219 isValid = false;
220 }
221 }
218 - } else
222 + } else {
223 isValid = false;
224 + }
225 +
226 errorMessage = isValid ? null : S.current.error_text_xmr;
227 }
228
229 void validateFiat(String value, {double maxValue}) {
230 const double minValue = 0.01;
225 - if (value.isEmpty && cryptoAmount == 'ALL')
231 +
232 + if (value.isEmpty && cryptoAmount == 'ALL') {
233 isValid = true;
227 - else {
228 - String p = '^([0-9]+([.][0-9]{0,2})?|[.][0-9]{1,2})\$';
229 - RegExp regExp = new RegExp(p);
234 + } else {
235 + const pattern = '^([0-9]+([.][0-9]{0,2})?|[.][0-9]{1,2})\$';
236 + final regExp = RegExp(pattern);
237 +
238 if (regExp.hasMatch(value)) {
239 try {
232 - double dValue = double.parse(value);
240 + final dValue = double.parse(value);
241 isValid = (dValue >= minValue && dValue <= maxValue);
242 } catch (e) {
243 isValid = false;
244 }
237 - } else
245 + } else {
246 isValid = false;
247 + }
248 }
249 +
250 errorMessage = isValid
251 ? null
252 : "Value of amount can't exceed available balance.\n"
lib/src/stores/send/sending_state.dart
+2 -2
@@ -13,7 +13,7 @@ class TransactionCommiting extends SendingState {}
13 class TransactionCommitted extends SendingState {}
14
15 class SendingFailed extends SendingState {
16 - String error;
17 -
16 SendingFailed({@required this.error});
17 +
18 + String error;
19 }
lib/src/stores/settings/settings_store.dart
+33 -33
@@ -17,6 +17,36 @@ part 'settings_store.g.dart';
17 class SettingsStore = SettingsStoreBase with _$SettingsStore;
18
19 abstract class SettingsStoreBase with Store {
20 + SettingsStoreBase(
21 + {@required SharedPreferences sharedPreferences,
22 + @required Box<Node> nodes,
23 + @required FiatCurrency initialFiatCurrency,
24 + @required TransactionPriority initialTransactionPriority,
25 + @required BalanceDisplayMode initialBalanceDisplayMode,
26 + @required bool initialSaveRecipientAddress,
27 + @required bool initialAllowBiometricalAuthentication,
28 + @required bool initialDarkTheme,
29 + this.actionlistDisplayMode,
30 + @required int initialPinLength,
31 + @required String initialLanguageCode}) {
32 + fiatCurrency = initialFiatCurrency;
33 + transactionPriority = initialTransactionPriority;
34 + balanceDisplayMode = initialBalanceDisplayMode;
35 + shouldSaveRecipientAddress = initialSaveRecipientAddress;
36 + _sharedPreferences = sharedPreferences;
37 + _nodes = nodes;
38 + allowBiometricalAuthentication = initialAllowBiometricalAuthentication;
39 + isDarkTheme = initialDarkTheme;
40 + defaultPinLength = initialPinLength;
41 + languageCode = initialLanguageCode;
42 + itemHeaders = Map();
43 +
44 + actionlistDisplayMode.observe(
45 + (dynamic _) => _sharedPreferences.setInt(displayActionListModeKey,
46 + serializeActionlistDisplayModes(actionlistDisplayMode)),
47 + fireImmediately: false);
48 + }
49 +
50 static const currentNodeIdKey = 'current_node_id';
51 static const currentFiatCurrencyKey = 'current_fiat_currency';
52 static const currentTransactionPriorityKey = 'current_fee_priority';
@@ -113,36 +143,6 @@ abstract class SettingsStoreBase with Store {
143 SharedPreferences _sharedPreferences;
144 Box<Node> _nodes;
145
116 - SettingsStoreBase(
117 - {@required SharedPreferences sharedPreferences,
118 - @required Box<Node> nodes,
119 - @required FiatCurrency initialFiatCurrency,
120 - @required TransactionPriority initialTransactionPriority,
121 - @required BalanceDisplayMode initialBalanceDisplayMode,
122 - @required bool initialSaveRecipientAddress,
123 - @required bool initialAllowBiometricalAuthentication,
124 - @required bool initialDarkTheme,
125 - this.actionlistDisplayMode,
126 - @required int initialPinLength,
127 - @required String initialLanguageCode}) {
128 - fiatCurrency = initialFiatCurrency;
129 - transactionPriority = initialTransactionPriority;
130 - balanceDisplayMode = initialBalanceDisplayMode;
131 - shouldSaveRecipientAddress = initialSaveRecipientAddress;
132 - _sharedPreferences = sharedPreferences;
133 - _nodes = nodes;
134 - allowBiometricalAuthentication = initialAllowBiometricalAuthentication;
135 - isDarkTheme = initialDarkTheme;
136 - defaultPinLength = initialPinLength;
137 - languageCode = initialLanguageCode;
138 - itemHeaders = Map();
139 -
140 - actionlistDisplayMode.observe(
141 - (dynamic _) => _sharedPreferences.setInt(displayActionListModeKey,
142 - serializeActionlistDisplayModes(actionlistDisplayMode)),
143 - fireImmediately: false);
144 - }
145 -
146 @action
147 Future setAllowBiometricalAuthentication(
148 {@required bool allowBiometricalAuthentication}) async {
@@ -168,7 +168,7 @@ abstract class SettingsStoreBase with Store {
168 @action
169 Future setCurrentNode({@required Node node}) async {
170 this.node = node;
171 - await _sharedPreferences.setInt(currentNodeIdKey, node.key);
171 + await _sharedPreferences.setInt(currentNodeIdKey, node.key as int);
172 }
173
174 @action
@@ -203,7 +203,7 @@ abstract class SettingsStoreBase with Store {
203 }
204
205 Future loadSettings() async => node = await _fetchCurrentNode();
206 -
206 +
207 @action
208 void toggleTransactionsDisplay() =>
209 actionlistDisplayMode.contains(ActionListDisplayMode.transactions)
@@ -239,7 +239,7 @@ abstract class SettingsStoreBase with Store {
239
240 Future<Node> _fetchCurrentNode() async {
241 final id = _sharedPreferences.getInt(currentNodeIdKey);
242 -
242 +
243 return _nodes.get(id);
244 }
245
lib/src/stores/subaddress_creation/subaddress_creation_state.dart
+2 -2
@@ -7,7 +7,7 @@ class SubaddressIsCreating extends SubaddressCreationState {}
7 class SubaddressCreatedSuccessfully extends SubaddressCreationState {}
8
9 class SubaddressCreationFailure extends SubaddressCreationState {
10 - String error;
11 -
10 SubaddressCreationFailure({this.error});
11 +
12 + String error;
13 }
\ No newline at end of file
lib/src/stores/subaddress_creation/subaddress_creation_store.dart
+18 -17
@@ -15,6 +15,17 @@ class SubadrressCreationStore = SubadrressCreationStoreBase
15 with _$SubadrressCreationStore;
16
17 abstract class SubadrressCreationStoreBase with Store {
18 + SubadrressCreationStoreBase({@required WalletService walletService}) {
19 + state = SubaddressCreationStateInitial();
20 +
21 + if (walletService.currentWallet != null) {
22 + _onWalletChanged(walletService.currentWallet);
23 + }
24 +
25 + _onWalletChangeSubscription =
26 + walletService.onWalletChange.listen(_onWalletChanged);
27 + }
28 +
29 SubaddressCreationState state;
30
31 @observable
@@ -28,17 +39,6 @@ abstract class SubadrressCreationStoreBase with Store {
39 StreamSubscription<Account> _onAccountChangeSubscription;
40 Account _account;
41
31 - SubadrressCreationStoreBase({@required WalletService walletService}) {
32 - state = SubaddressCreationStateInitial();
33 -
34 - if (walletService.currentWallet != null) {
35 - _onWalletChanged(walletService.currentWallet);
36 - }
37 -
38 - _onWalletChangeSubscription =
39 - walletService.onWalletChange.listen(_onWalletChanged);
40 - }
41 -
42 @override
43 void dispose() {
44 _onWalletChangeSubscription.cancel();
@@ -50,7 +50,7 @@ abstract class SubadrressCreationStoreBase with Store {
50 super.dispose();
51 }
52
53 - Future add({String label}) async {
53 + Future<void> add({String label}) async {
54 try {
55 state = SubaddressIsCreating();
56 await _subaddressList.addSubaddress(
@@ -61,14 +61,15 @@ abstract class SubadrressCreationStoreBase with Store {
61 }
62 }
63
64 - Future _onWalletChanged(Wallet wallet) async {
64 + Future<void> _onWalletChanged(Wallet wallet) async {
65 if (wallet is MoneroWallet) {
66 _account = wallet.account;
67 _subaddressList = wallet.getSubaddress();
68
69 - _onAccountChangeSubscription = wallet.onAccountChange.listen((account) async {
69 + _onAccountChangeSubscription =
70 + wallet.onAccountChange.listen((account) async {
71 _account = account;
71 - _subaddressList.update(accountIndex: account.id);
72 + await _subaddressList.update(accountIndex: account.id);
73 });
74 return;
75 }
@@ -77,8 +78,8 @@ abstract class SubadrressCreationStoreBase with Store {
78 }
79
80 void validateSubaddressName(String value) {
80 - String p = '''^[^`,'"]{1,20}\$''';
81 - RegExp regExp = new RegExp(p);
81 + const pattern = '''^[^`,'"]{1,20}\$''';
82 + final regExp = RegExp(pattern);
83 isValid = regExp.hasMatch(value);
84 errorMessage = isValid ? null : S.current.error_text_subaddress_name;
85 }
lib/src/stores/subaddress_list/subaddress_list_store.dart
+14 -13
@@ -13,15 +13,6 @@ part 'subaddress_list_store.g.dart';
13 class SubaddressListStore = SubaddressListStoreBase with _$SubaddressListStore;
14
15 abstract class SubaddressListStoreBase with Store {
16 - @observable
17 - ObservableList<Subaddress> subaddresses;
18 -
19 - SubaddressList _subaddressList;
20 - StreamSubscription<Wallet> _onWalletChangeSubscription;
21 - StreamSubscription<List<Subaddress>> _onSubaddressesChangeSubscription;
22 - StreamSubscription<Account> _onAccountChangeSubscription;
23 - Account _account;
24 -
16 SubaddressListStoreBase({@required WalletService walletService}) {
17 subaddresses = ObservableList<Subaddress>();
18
@@ -33,6 +24,15 @@ abstract class SubaddressListStoreBase with Store {
24 walletService.onWalletChange.listen(_onWalletChanged);
25 }
26
27 + @observable
28 + ObservableList<Subaddress> subaddresses;
29 +
30 + SubaddressList _subaddressList;
31 + StreamSubscription<Wallet> _onWalletChangeSubscription;
32 + StreamSubscription<List<Subaddress>> _onSubaddressesChangeSubscription;
33 + StreamSubscription<Account> _onAccountChangeSubscription;
34 + Account _account;
35 +
36 @override
37 void dispose() {
38 if (_onSubaddressesChangeSubscription != null) {
@@ -47,14 +47,14 @@ abstract class SubaddressListStoreBase with Store {
47 super.dispose();
48 }
49
50 - Future _updateSubaddressList({int accountIndex}) async {
50 + Future<void> _updateSubaddressList({int accountIndex}) async {
51 await _subaddressList.refresh(accountIndex: accountIndex);
52 subaddresses = ObservableList.of(_subaddressList.getAll());
53 }
54
55 - Future _onWalletChanged(Wallet wallet) async {
55 + Future<void> _onWalletChanged(Wallet wallet) async {
56 if (_onSubaddressesChangeSubscription != null) {
57 - _onSubaddressesChangeSubscription.cancel();
57 + await _onSubaddressesChangeSubscription.cancel();
58 }
59
60 if (wallet is MoneroWallet) {
@@ -64,7 +64,8 @@ abstract class SubaddressListStoreBase with Store {
64 .listen((subaddress) => subaddresses = ObservableList.of(subaddress));
65 await _updateSubaddressList(accountIndex: _account.id);
66
67 - _onAccountChangeSubscription = wallet.onAccountChange.listen((account) async {
67 + _onAccountChangeSubscription =
68 + wallet.onAccountChange.listen((account) async {
69 _account = account;
70 await _updateSubaddressList(accountIndex: account.id);
71 });
lib/src/stores/sync/sync_store.dart
+6 -6
@@ -10,12 +10,6 @@ part 'sync_store.g.dart';
10 class SyncStore = SyncStoreBase with _$SyncStore;
11
12 abstract class SyncStoreBase with Store {
13 - @observable
14 - SyncStatus status;
15 -
16 - StreamSubscription<Wallet> _onWalletChangeSubscription;
17 - StreamSubscription<SyncStatus> _onSyncStatusChangeSubscription;
18 -
13 SyncStoreBase(
14 {SyncStatus syncStatus = const NotConnectedSyncStatus(),
15 @required WalletService walletService}) {
@@ -29,6 +23,12 @@ abstract class SyncStoreBase with Store {
23 walletService.onWalletChange.listen(_onWalletChanged);
24 }
25
26 + @observable
27 + SyncStatus status;
28 +
29 + StreamSubscription<Wallet> _onWalletChangeSubscription;
30 + StreamSubscription<SyncStatus> _onSyncStatusChangeSubscription;
31 +
32 @override
33 void dispose() {
34 if (_onSyncStatusChangeSubscription != null) {
lib/src/stores/user/user_store.dart
+7 -7
@@ -8,6 +8,8 @@ part 'user_store.g.dart';
8 class UserStore = UserStoreBase with _$UserStore;
9
10 abstract class UserStoreBase with Store {
11 + UserStoreBase({@required this.accountService});
12 +
13 UserService accountService;
14
15 @observable
@@ -16,17 +18,15 @@ abstract class UserStoreBase with Store {
18 @observable
19 String errorMessage;
20
19 - UserStoreBase({@required this.accountService});
20 -
21 @action
22 Future set({String password}) async {
23 state = UserStoreStateInitial();
24
25 try {
26 - await accountService.setPassword(password);
27 - state = PinCodeSetSuccesfully();
28 - } catch(e) {
29 - state = PinCodeSetFailed(error: e.toString());
30 - }
26 + await accountService.setPassword(password);
27 + state = PinCodeSetSuccesfully();
28 + } catch (e) {
29 + state = PinCodeSetFailed(error: e.toString());
30 + }
31 }
32 }
lib/src/stores/user/user_store_state.dart
+2 -2
@@ -7,7 +7,7 @@ class UserStoreStateInitial extends UserStoreState {}
7 class PinCodeSetSuccesfully extends UserStoreState {}
8
9 class PinCodeSetFailed extends UserStoreState {
10 - String error;
11 -
10 PinCodeSetFailed({@required this.error});
11 +
12 + String error;
13 }
lib/src/stores/wallet/wallet_keys_store.dart
+12 -12
@@ -7,18 +7,6 @@ part 'wallet_keys_store.g.dart';
7 class WalletKeysStore = WalletKeysStoreBase with _$WalletKeysStore;
8
9 abstract class WalletKeysStoreBase with Store {
10 - @observable
11 - String publicViewKey;
12 -
13 - @observable
14 - String privateViewKey;
15 -
16 - @observable
17 - String publicSpendKey;
18 -
19 - @observable
20 - String privateSpendKey;
21 -
10 WalletKeysStoreBase({@required WalletService walletService}) {
11 publicViewKey = '';
12 privateViewKey = '';
@@ -34,4 +22,16 @@ abstract class WalletKeysStoreBase with Store {
22 });
23 }
24 }
25 +
26 + @observable
27 + String publicViewKey;
28 +
29 + @observable
30 + String privateViewKey;
31 +
32 + @observable
33 + String publicSpendKey;
34 +
35 + @observable
36 + String privateSpendKey;
37 }
lib/src/stores/wallet/wallet_store.dart
+30 -26
@@ -15,6 +15,21 @@ part 'wallet_store.g.dart';
15 class WalletStore = WalletStoreBase with _$WalletStore;
16
17 abstract class WalletStoreBase with Store {
18 + WalletStoreBase({WalletService walletService, SettingsStore settingsStore}) {
19 + _walletService = walletService;
20 + _settingsStore = settingsStore;
21 + name = '';
22 + type = CryptoCurrency.xmr;
23 + amountValue = '';
24 +
25 + if (_walletService.currentWallet != null) {
26 + _onWalletChanged(_walletService.currentWallet);
27 + }
28 +
29 + _onWalletChangeSubscription = _walletService.onWalletChange
30 + .listen((wallet) async => await _onWalletChanged(wallet));
31 + }
32 +
33 @observable
34 String address;
35
@@ -47,22 +62,6 @@ abstract class WalletStoreBase with Store {
62 StreamSubscription<Account> _onAccountChangeSubscription;
63 StreamSubscription<Subaddress> _onSubaddressChangeSubscription;
64
50 -
51 - WalletStoreBase({WalletService walletService, SettingsStore settingsStore}) {
52 - _walletService = walletService;
53 - _settingsStore = settingsStore;
54 - name = '';
55 - type = CryptoCurrency.xmr;
56 - amountValue = '';
57 -
58 - if (_walletService.currentWallet != null) {
59 - _onWalletChanged(_walletService.currentWallet);
60 - }
61 -
62 - _onWalletChangeSubscription = _walletService.onWalletChange
63 - .listen((wallet) async => await _onWalletChanged(wallet));
64 - }
65 -
65 @override
66 void dispose() {
67 if (_onWalletChangeSubscription != null) {
@@ -112,7 +111,8 @@ abstract class WalletStoreBase with Store {
111 Future startSync() async => await _walletService.startSync();
112
113 @action
115 - Future connectToNode({Node node}) async => await _walletService.connectToNode(node: node);
114 + Future connectToNode({Node node}) async =>
115 + await _walletService.connectToNode(node: node);
116
117 Future _onWalletChanged(Wallet wallet) async {
118 if (this == null) {
@@ -123,15 +123,16 @@ abstract class WalletStoreBase with Store {
123 wallet.onAddressChange.listen((address) => this.address = address);
124
125 if (wallet is MoneroWallet) {
126 - _onAccountChangeSubscription = wallet.onAccountChange.listen((account) => this.account = account);
127 - _onSubaddressChangeSubscription = wallet.subaddress.listen((subaddress) => this.subaddress = subaddress);
126 + _onAccountChangeSubscription =
127 + wallet.onAccountChange.listen((account) => this.account = account);
128 + _onSubaddressChangeSubscription = wallet.subaddress
129 + .listen((subaddress) => this.subaddress = subaddress);
130 }
131 }
132
133 @action
132 - onChangedAmountValue(String value) {
133 - amountValue = value.isNotEmpty ? '?tx_amount=' + value : '';
134 - }
134 + void onChangedAmountValue(String value) =>
135 + amountValue = value.isNotEmpty ? '?tx_amount=' + value : '';
136
137 @action
138 void validateAmount(String value) {
@@ -140,16 +141,19 @@ abstract class WalletStoreBase with Store {
141 if (value.isEmpty) {
142 isValid = true;
143 } else {
143 - String p = '^([0-9]+([.][0-9]{0,12})?|[.][0-9]{1,12})\$';
144 - RegExp regExp = new RegExp(p);
144 + const pattern = '^([0-9]+([.][0-9]{0,12})?|[.][0-9]{1,12})\$';
145 + final regExp = RegExp(pattern);
146 +
147 if (regExp.hasMatch(value)) {
148 try {
147 - double dValue = double.parse(value);
149 + final dValue = double.parse(value);
150 isValid = dValue <= maxValue;
151 } catch (e) {
152 isValid = false;
153 }
152 - } else isValid = false;
154 + } else {
155 + isValid = false;
156 + }
157 }
158
159 errorMessage = isValid ? null : S.current.error_text_amount;
lib/src/stores/wallet_creation/wallet_creation_state.dart
+2 -1
@@ -9,6 +9,7 @@ class WalletIsCreating extends WalletCreationState {}
9 class WalletCreatedSuccessfully extends WalletCreationState {}
10
11 class WalletCreationFailure extends WalletCreationState {
12 - String error;
12 WalletCreationFailure({@required this.error});
13 +
14 + String error;
15 }
\ No newline at end of file
lib/src/stores/wallet_creation/wallet_creation_store.dart
+9 -9
@@ -11,6 +11,13 @@ part 'wallet_creation_store.g.dart';
11 class WalletCreationStore = WalletCreationStoreBase with _$WalletCreationStore;
12
13 abstract class WalletCreationStoreBase with Store {
14 + WalletCreationStoreBase(
15 + {@required this.authStore,
16 + @required this.walletListService,
17 + @required this.sharedPreferences}) {
18 + state = WalletCreationStateInitial();
19 + }
20 +
21 final AuthenticationStore authStore;
22 final WalletListService walletListService;
23 final SharedPreferences sharedPreferences;
@@ -24,13 +31,6 @@ abstract class WalletCreationStoreBase with Store {
31 @observable
32 bool isValid;
33
27 - WalletCreationStoreBase(
28 - {@required this.authStore,
29 - @required this.walletListService,
30 - @required this.sharedPreferences}) {
31 - state = WalletCreationStateInitial();
32 - }
33 -
34 @action
35 Future create({String name}) async {
36 state = WalletCreationStateInitial();
@@ -46,8 +46,8 @@ abstract class WalletCreationStoreBase with Store {
46 }
47
48 void validateWalletName(String value) {
49 - String p = '^[a-zA-Z0-9_]{1,15}\$';
50 - RegExp regExp = new RegExp(p);
49 + const pattern = '^[a-zA-Z0-9_]{1,15}\$';
50 + final regExp = RegExp(pattern);
51 isValid = regExp.hasMatch(value);
52 errorMessage = isValid ? null : S.current.error_text_wallet_name;
53 }
lib/src/stores/wallet_list/wallet_list_store.dart
+11 -12
@@ -9,12 +9,6 @@ part 'wallet_list_store.g.dart';
9 class WalletListStore = WalletListStoreBase with _$WalletListStore;
10
11 abstract class WalletListStoreBase with Store {
12 - @observable
13 - List<WalletDescription> wallets;
14 -
15 - WalletListService _walletListService;
16 - WalletService _walletService;
17 -
12 WalletListStoreBase(
13 {@required WalletListService walletListService,
14 @required WalletService walletService}) {
@@ -24,22 +18,27 @@ abstract class WalletListStoreBase with Store {
18 walletListService.getAll().then((walletList) => wallets = walletList);
19 }
20
27 - bool isCurrentWallet(WalletDescription wallet) {
28 - return _walletService.description?.name == wallet.name;
29 - }
21 + @observable
22 + List<WalletDescription> wallets;
23 +
24 + WalletListService _walletListService;
25 + WalletService _walletService;
26 +
27 + bool isCurrentWallet(WalletDescription wallet) =>
28 + _walletService.description?.name == wallet.name;
29
30 @action
32 - Future updateWalletList() async {
31 + Future<void> updateWalletList() async {
32 wallets = await _walletListService.getAll();
33 }
34
35 @action
37 - Future loadWallet(WalletDescription wallet) async {
36 + Future<void> loadWallet(WalletDescription wallet) async {
37 await _walletListService.openWallet(wallet.name);
38 }
39
40 @action
42 - Future remove(WalletDescription wallet) async {
41 + Future<void> remove(WalletDescription wallet) async {
42 await _walletListService.remove(wallet);
43 await updateWalletList();
44 }
lib/src/stores/wallet_restoration/wallet_restoration_state.dart
+3 -2
@@ -9,6 +9,7 @@ class WalletIsRestoring extends WalletRestorationState {}
9 class WalletRestoredSuccessfully extends WalletRestorationState {}
10
11 class WalletRestorationFailure extends WalletRestorationState {
12 - String error;
12 WalletRestorationFailure({@required this.error});
14 -}
\ No newline at end of file
13 +
14 + String error;
15 +}
lib/src/stores/wallet_restoration/wallet_restoration_store.dart
+16 -14
@@ -14,6 +14,14 @@ class WalletRestorationStore = WalleRestorationStoreBase
14 with _$WalletRestorationStore;
15
16 abstract class WalleRestorationStoreBase with Store {
17 + WalleRestorationStoreBase(
18 + {this.seed,
19 + @required this.authStore,
20 + @required this.walletListService,
21 + @required this.sharedPreferences}) {
22 + state = WalletRestorationStateInitial();
23 + }
24 +
25 final AuthenticationStore authStore;
26 final WalletListService walletListService;
27 final SharedPreferences sharedPreferences;
@@ -30,14 +38,6 @@ abstract class WalleRestorationStoreBase with Store {
38 @observable
39 List<MnemoticItem> seed;
40
33 - WalleRestorationStoreBase(
34 - {this.seed,
35 - @required this.authStore,
36 - @required this.walletListService,
37 - @required this.sharedPreferences}) {
38 - state = WalletRestorationStateInitial();
39 - }
40 -
41 @action
42 Future restoreFromSeed({String name, String seed, int restoreHeight}) async {
43 state = WalletRestorationStateInitial();
@@ -110,17 +110,18 @@ abstract class WalleRestorationStoreBase with Store {
110 }
111
112 void validateWalletName(String value) {
113 - String p = '^[a-zA-Z0-9_]{1,15}\$';
114 - RegExp regExp = new RegExp(p);
113 + const pattern = '^[a-zA-Z0-9_]{1,15}\$';
114 + final regExp = RegExp(pattern);
115 isValid = regExp.hasMatch(value);
116 errorMessage = isValid ? null : S.current.error_text_wallet_name;
117 }
118
119 void validateAddress(String value, {CryptoCurrency cryptoCurrency}) {
120 // XMR (95), BTC (34), ETH (42), LTC (34), BCH (42), DASH (34)
121 - String p = '^[0-9a-zA-Z]{95}\$|^[0-9a-zA-Z]{34}\$|^[0-9a-zA-Z]{42}\$';
122 - RegExp regExp = new RegExp(p);
121 + const pattern = '^[0-9a-zA-Z]{95}\$|^[0-9a-zA-Z]{34}\$|^[0-9a-zA-Z]{42}\$';
122 + final regExp = RegExp(pattern);
123 isValid = regExp.hasMatch(value);
124 +
125 if (isValid && cryptoCurrency != null) {
126 switch (cryptoCurrency.toString()) {
127 case 'XMR':
@@ -142,12 +143,13 @@ abstract class WalleRestorationStoreBase with Store {
143 isValid = (value.length == 34);
144 }
145 }
146 +
147 errorMessage = isValid ? null : S.current.error_text_address;
148 }
149
150 void validateKeys(String value) {
149 - String p = '^[A-Fa-f0-9]{64}\$';
150 - RegExp regExp = new RegExp(p);
151 + const pattern = '^[A-Fa-f0-9]{64}\$';
152 + final regExp = RegExp(pattern);
153 isValid = regExp.hasMatch(value);
154 errorMessage = isValid ? null : S.current.error_text_keys;
155 }
lib/src/stores/wallet_seed/wallet_seed_store.dart
+6 -6
@@ -7,12 +7,6 @@ part 'wallet_seed_store.g.dart';
7 class WalletSeedStore = WalletSeedStoreBase with _$WalletSeedStore;
8
9 abstract class WalletSeedStoreBase with Store {
10 - @observable
11 - String name;
12 -
13 - @observable
14 - String seed;
15 -
10 WalletSeedStoreBase({@required WalletService walletService}) {
11 seed = '';
12
@@ -21,4 +15,10 @@ abstract class WalletSeedStoreBase with Store {
15 walletService.getName().then((name) => this.name = name);
16 }
17 }
18 +
19 + @observable
20 + String name;
21 +
22 + @observable
23 + String seed;
24 }
lib/src/widgets/address_text_field.dart
+17 -18
@@ -9,17 +9,6 @@ import 'package:cake_wallet/src/domain/common/qr_scanner.dart';
9 enum AddressTextFieldOption { qrCode, addressBook, subaddressList }
10
11 class AddressTextField extends StatelessWidget {
12 - static const prefixIconWidth = 34.0;
13 - static const prefixIconHeight = 34.0;
14 - static const spaceBetweenPrefixIcons = 10.0;
15 -
16 - final TextEditingController controller;
17 - final bool isActive;
18 - final String placeholder;
19 - final Function(Uri) onURIScanned;
20 - final List<AddressTextFieldOption> options;
21 - final FormFieldValidator<String> validator;
22 -
12 AddressTextField(
13 {@required this.controller,
14 this.isActive = true,
@@ -31,6 +20,17 @@ class AddressTextField extends StatelessWidget {
20 this.onURIScanned,
21 this.validator});
22
23 + static const prefixIconWidth = 34.0;
24 + static const prefixIconHeight = 34.0;
25 + static const spaceBetweenPrefixIcons = 10.0;
26 +
27 + final TextEditingController controller;
28 + final bool isActive;
29 + final String placeholder;
30 + final Function(Uri) onURIScanned;
31 + final List<AddressTextFieldOption> options;
32 + final FormFieldValidator<String> validator;
33 +
34 @override
35 Widget build(BuildContext context) {
36 return TextFormField(
@@ -105,8 +105,7 @@ class AddressTextField extends StatelessWidget {
105 hintStyle: TextStyle(color: Theme.of(context).hintColor),
106 hintText: placeholder ?? S.current.widgets_address,
107 focusedBorder: UnderlineInputBorder(
108 - borderSide:
109 - BorderSide(color: Palette.cakeGreen, width: 2.0)),
108 + borderSide: BorderSide(color: Palette.cakeGreen, width: 2.0)),
109 enabledBorder: UnderlineInputBorder(
110 borderSide:
111 BorderSide(color: Theme.of(context).focusColor, width: 1.0)),
@@ -115,10 +114,10 @@ class AddressTextField extends StatelessWidget {
114 );
115 }
116
118 - Future _presentQRScanner(BuildContext context) async {
117 + Future<void> _presentQRScanner(BuildContext context) async {
118 try {
120 - String code = await presentQRScanner();
121 - var uri = Uri.parse(code);
119 + final code = await presentQRScanner();
120 + final uri = Uri.parse(code);
121 var address = '';
122
123 if (uri == null) {
@@ -137,7 +136,7 @@ class AddressTextField extends StatelessWidget {
136 }
137 }
138
140 - Future _presetAddressBookPicker(BuildContext context) async {
139 + Future<void> _presetAddressBookPicker(BuildContext context) async {
140 final contact = await Navigator.of(context, rootNavigator: true)
141 .pushNamed(Routes.pickerAddressBook);
142
@@ -146,7 +145,7 @@ class AddressTextField extends StatelessWidget {
145 }
146 }
147
149 - Future _presetSubaddressListPicker(BuildContext context) async {
148 + Future<void> _presetSubaddressListPicker(BuildContext context) async {
149 final subaddress = await Navigator.of(context, rootNavigator: true)
150 .pushNamed(Routes.subaddressList);
151
lib/src/widgets/nav_bar.dart
+26 -26
@@ -5,8 +5,23 @@ import 'package:flutter/material.dart';
5 import 'package:provider/provider.dart';
6
7 class NavBar extends StatelessWidget implements ObstructingPreferredSizeWidget {
8 - static const _originalHeight = 44.0; // iOS nav bar height
9 - static const _height = 60.0;
8 + factory NavBar(
9 + {BuildContext context,
10 + Widget leading,
11 + Widget middle,
12 + Widget trailing,
13 + Color backgroundColor}) {
14 + final _themeChanger = Provider.of<ThemeChanger>(context);
15 + final _isDarkTheme = _themeChanger.getTheme() == Themes.darkTheme;
16 +
17 + return NavBar._internal(
18 + leading: leading,
19 + middle: middle,
20 + trailing: trailing,
21 + height: _height,
22 + backgroundColor:
23 + _isDarkTheme ? Theme.of(context).backgroundColor : backgroundColor);
24 + }
25
26 factory NavBar.withShadow(
27 {BuildContext context,
@@ -37,23 +52,16 @@ class NavBar extends StatelessWidget implements ObstructingPreferredSizeWidget {
52 );
53 }
54
40 - factory NavBar(
41 - {BuildContext context,
42 - Widget leading,
43 - Widget middle,
44 - Widget trailing,
45 - Color backgroundColor}) {
46 - final _themeChanger = Provider.of<ThemeChanger>(context);
47 - final _isDarkTheme = _themeChanger.getTheme() == Themes.darkTheme;
55 + NavBar._internal(
56 + {this.leading,
57 + this.middle,
58 + this.trailing,
59 + this.backgroundColor,
60 + this.decoration,
61 + this.height = _height});
62
49 - return NavBar._internal(
50 - leading: leading,
51 - middle: middle,
52 - trailing: trailing,
53 - height: _height,
54 - backgroundColor:
55 - _isDarkTheme ? Theme.of(context).backgroundColor : backgroundColor);
56 - }
63 + static const _originalHeight = 44.0; // iOS nav bar height
64 + static const _height = 60.0;
65
66 final Widget leading;
67 final Widget middle;
@@ -62,14 +70,6 @@ class NavBar extends StatelessWidget implements ObstructingPreferredSizeWidget {
70 final BoxDecoration decoration;
71 final double height;
72
65 - NavBar._internal(
66 - {this.leading,
67 - this.middle,
68 - this.trailing,
69 - this.backgroundColor,
70 - this.decoration,
71 - this.height = _height});
72 -
73 @override
74 Widget build(BuildContext context) {
75 final pad = height - _originalHeight;
lib/src/widgets/picker.dart
+14 -10
@@ -2,12 +2,6 @@ import 'dart:ui';
2 import 'package:flutter/material.dart';
3
4 class Picker<Item extends Object> extends StatelessWidget {
5 - final int selectedAtIndex;
6 - final List<Item> items;
7 - final String title;
8 - final double pickerHeight;
9 - final Function(Item) onItemSelected;
10 -
5 Picker(
6 {@required this.selectedAtIndex,
7 @required this.items,
@@ -15,9 +9,14 @@ class Picker<Item extends Object> extends StatelessWidget {
9 this.pickerHeight = 300,
10 this.onItemSelected});
11
12 + final int selectedAtIndex;
13 + final List<Item> items;
14 + final String title;
15 + final double pickerHeight;
16 + final Function(Item) onItemSelected;
17 +
18 @override
19 Widget build(BuildContext context) {
20 -
20 return GestureDetector(
21 onTap: () => Navigator.of(context).pop(),
22 child: Container(
@@ -57,8 +56,10 @@ class Picker<Item extends Object> extends StatelessWidget {
56 fontWeight: FontWeight.w600,
57 fontFamily: 'Lato',
58 decoration: TextDecoration.none,
60 - color: Theme.of(context).primaryTextTheme.caption.color
61 - ),
59 + color: Theme.of(context)
60 + .primaryTextTheme
61 + .caption
62 + .color),
63 ),
64 ),
65 );
@@ -88,7 +89,10 @@ class Picker<Item extends Object> extends StatelessWidget {
89 fontFamily: 'Lato',
90 color: index == selectedAtIndex
91 ? Color.fromRGBO(138, 80, 255, 1)
91 - : Theme.of(context).primaryTextTheme.caption.color),
92 + : Theme.of(context)
93 + .primaryTextTheme
94 + .caption
95 + .color),
96 )),
97 ),
98 );
lib/src/widgets/primary_button.dart
+36 -34
@@ -3,20 +3,19 @@ import 'package:flutter/material.dart';
3 import 'package:cake_wallet/palette.dart';
4
5 class PrimaryButton extends StatelessWidget {
6 - final VoidCallback onPressed;
7 - final Color color;
8 - final Color borderColor;
9 - final String text;
10 -
6 const PrimaryButton(
7 {@required this.onPressed,
8 @required this.text,
9 @required this.color,
10 @required this.borderColor});
11
12 + final VoidCallback onPressed;
13 + final Color color;
14 + final Color borderColor;
15 + final String text;
16 +
17 @override
18 Widget build(BuildContext context) {
19 -
19 return ButtonTheme(
20 minWidth: double.infinity,
21 height: 56.0,
@@ -35,13 +34,6 @@ class PrimaryButton extends StatelessWidget {
34 }
35
36 class LoadingPrimaryButton extends StatelessWidget {
38 - final VoidCallback onPressed;
39 - final Color color;
40 - final Color borderColor;
41 - final bool isLoading;
42 - final bool isDisabled;
43 - final String text;
44 -
37 const LoadingPrimaryButton(
38 {@required this.onPressed,
39 @required this.text,
@@ -50,9 +42,15 @@ class LoadingPrimaryButton extends StatelessWidget {
42 this.isDisabled = false,
43 this.isLoading = false});
44
45 + final VoidCallback onPressed;
46 + final Color color;
47 + final Color borderColor;
48 + final bool isLoading;
49 + final bool isDisabled;
50 + final String text;
51 +
52 @override
53 Widget build(BuildContext context) {
55 -
54 return ButtonTheme(
55 minWidth: double.infinity,
56 height: 56.0,
@@ -73,14 +71,6 @@ class LoadingPrimaryButton extends StatelessWidget {
71 }
72
73 class PrimaryIconButton extends StatelessWidget {
76 - final VoidCallback onPressed;
77 - final IconData iconData;
78 - final Color color;
79 - final Color borderColor;
80 - final Color iconColor;
81 - final Color iconBackgroundColor;
82 - final String text;
83 -
74 const PrimaryIconButton({
75 @required this.onPressed,
76 @required this.iconData,
@@ -91,9 +81,16 @@ class PrimaryIconButton extends StatelessWidget {
81 @required this.iconBackgroundColor,
82 });
83
84 + final VoidCallback onPressed;
85 + final IconData iconData;
86 + final Color color;
87 + final Color borderColor;
88 + final Color iconColor;
89 + final Color iconBackgroundColor;
90 + final String text;
91 +
92 @override
93 Widget build(BuildContext context) {
96 -
94 return ButtonTheme(
95 minWidth: double.infinity,
96 height: 56.0,
@@ -123,7 +120,8 @@ class PrimaryIconButton extends StatelessWidget {
120 child: Text(text,
121 style: TextStyle(
122 fontSize: 16.0,
126 - color: Theme.of(context).primaryTextTheme.button.color)),
123 + color:
124 + Theme.of(context).primaryTextTheme.button.color)),
125 ),
126 )
127 ],
@@ -133,13 +131,6 @@ class PrimaryIconButton extends StatelessWidget {
131 }
132
133 class PrimaryImageButton extends StatelessWidget {
136 - final VoidCallback onPressed;
137 - final Image image;
138 - final Color color;
139 - final Color borderColor;
140 - final Color iconColor;
141 - final String text;
142 -
134 const PrimaryImageButton(
135 {@required this.onPressed,
136 @required this.image,
@@ -148,6 +139,13 @@ class PrimaryImageButton extends StatelessWidget {
139 this.borderColor = Palette.deepPink,
140 this.iconColor = Colors.black});
141
142 + final VoidCallback onPressed;
143 + final Image image;
144 + final Color color;
145 + final Color borderColor;
146 + final Color iconColor;
147 + final String text;
148 +
149 @override
150 Widget build(BuildContext context) {
151 return ButtonTheme(
@@ -175,9 +173,13 @@ class PrimaryImageButton extends StatelessWidget {
173 Container(
174 height: 56.0,
175 child: Center(
178 - child: Text(text, style: TextStyle(fontSize: 18.0,
179 - color: Theme.of(context).primaryTextTheme.button.color
180 - )),
176 + child: Text(text,
177 + style: TextStyle(
178 + fontSize: 18.0,
179 + color: Theme.of(context)
180 + .primaryTextTheme
181 + .button
182 + .color)),
183 ),
184 )
185 ]))
lib/src/widgets/scollable_with_bottom_section.dart
+5 -5
@@ -2,17 +2,17 @@ import 'package:flutter/cupertino.dart';
2 import 'package:flutter/material.dart';
3
4 class ScrollableWithBottomSection extends StatefulWidget {
5 - final Widget content;
6 - final Widget bottomSection;
7 - final EdgeInsets contentPadding;
8 - final EdgeInsets bottomSectionPadding;
9 -
5 ScrollableWithBottomSection(
6 {this.content,
7 this.bottomSection,
8 this.contentPadding,
9 this.bottomSectionPadding});
10
11 + final Widget content;
12 + final Widget bottomSection;
13 + final EdgeInsets contentPadding;
14 + final EdgeInsets bottomSectionPadding;
15 +
16 @override
17 ScrollableWithBottomSectionState createState() =>
18 ScrollableWithBottomSectionState();
lib/src/widgets/seed_widget.dart
+4 -4
@@ -7,10 +7,11 @@ import 'package:cake_wallet/src/domain/common/mnemotic_item.dart';
7 import 'package:cake_wallet/generated/i18n.dart';
8
9 class SeedWidget extends StatefulWidget {
10 - final Function(List<MnemoticItem>) onMnemoticChange;
11 -
10 SeedWidget({Key key, this.onMnemoticChange}) : super(key: key);
11
12 + final Function(List<MnemoticItem>) onMnemoticChange;
13 +
14 + @override
15 SeedWidgetState createState() => SeedWidgetState();
16 }
17
@@ -188,8 +189,7 @@ class SeedWidgetState extends State<SeedWidget> {
189 hintStyle: TextStyle(color: Theme.of(context).hintColor),
190 hintText: S.of(context).widgets_seed,
191 focusedBorder: UnderlineInputBorder(
191 - borderSide: BorderSide(
192 - color: Palette.cakeGreen, width: 2.0)),
192 + borderSide: BorderSide(color: Palette.cakeGreen, width: 2.0)),
193 enabledBorder: UnderlineInputBorder(
194 borderSide: BorderSide(
195 color:
lib/src/widgets/standart_switch.dart
+9 -22
@@ -1,41 +1,31 @@
1 import 'package:flutter/material.dart';
2
3 class StandartSwitch extends StatefulWidget {
4 + const StandartSwitch({@required this.value, @required this.onTaped});
5
6 final bool value;
7 final VoidCallback onTaped;
8
8 - const StandartSwitch({
9 - @required this.value,
10 - @required this.onTaped});
11 -
9 @override
13 - createState() => StandartSwitchState();
14 -
10 + StandartSwitchState createState() => StandartSwitchState();
11 }
12
13 class StandartSwitchState extends State<StandartSwitch> {
18 -
14 @override
15 Widget build(BuildContext context) {
21 -
16 return GestureDetector(
17 onTap: widget.onTaped,
18 child: AnimatedContainer(
19 padding: EdgeInsets.only(left: 4.0, right: 4.0),
26 - alignment: widget.value
27 - ? Alignment.centerRight
28 - : Alignment.centerLeft,
20 + alignment: widget.value ? Alignment.centerRight : Alignment.centerLeft,
21 duration: Duration(milliseconds: 250),
22 width: 55.0,
23 height: 33.0,
24 decoration: BoxDecoration(
25 color: Theme.of(context).toggleButtonsTheme.color,
26 border: Border.all(
35 - color: Theme.of(context).toggleButtonsTheme.borderColor
36 - ),
37 - borderRadius:
38 - BorderRadius.all(Radius.circular(10.0))),
27 + color: Theme.of(context).toggleButtonsTheme.borderColor),
28 + borderRadius: BorderRadius.all(Radius.circular(10.0))),
29 child: Container(
30 width: 25.0,
31 height: 25.0,
@@ -43,11 +33,9 @@ class StandartSwitchState extends State<StandartSwitch> {
33 color: widget.value
34 ? Theme.of(context).toggleButtonsTheme.selectedColor
35 : Theme.of(context).toggleButtonsTheme.disabledColor,
46 - borderRadius:
47 - BorderRadius.all(Radius.circular(8.0))),
48 - child: Icon(widget.value
49 - ? Icons.check
50 - : Icons.close,
36 + borderRadius: BorderRadius.all(Radius.circular(8.0))),
37 + child: Icon(
38 + widget.value ? Icons.check : Icons.close,
39 color: Colors.white,
40 size: 16.0,
41 ),
@@ -55,5 +43,4 @@ class StandartSwitchState extends State<StandartSwitch> {
43 ),
44 );
45 }
58 -
59 -}
\ No newline at end of file
46 +}
lib/theme_changer.dart
+4 -5
@@ -1,17 +1,16 @@
1 import 'package:flutter/material.dart';
2
3 class ThemeChanger with ChangeNotifier {
4 +
5 + ThemeChanger(this._themeData);
6
7 ThemeData _themeData;
8
7 - ThemeChanger(this._themeData);
8 -
9 - getTheme() => _themeData;
9 + ThemeData getTheme() => _themeData;
10
11 - setTheme(ThemeData theme){
11 + void setTheme(ThemeData theme){
12 _themeData = theme;
13
14 notifyListeners();
15 }
16 -
16 }
\ No newline at end of file
pubspec.lock
+1 -1
@@ -498,7 +498,7 @@ packages:
498 source: hosted
499 version: "1.5.1"
500 pedantic:
501 - dependency: transitive
501 + dependency: "direct dev"
502 description:
503 name: pedantic
504 url: "https://pub.dartlang.org"
pubspec.yaml
+1
@@ -59,6 +59,7 @@ dev_dependencies:
59 mobx_codegen: 0.3.3+1
60 hive_generator: ^0.6.0
61 flutter_launcher_icons: ^0.7.4
62 + pedantic: ^1.8.0
63
64 flutter_icons:
65 image_path: "assets/images/app_logo.png"
tool/secrets.dart
+2 -2
@@ -12,9 +12,9 @@ Future<void> main() async {
12 : secretsTestPath;
13
14 final inoutContent = File(inputPath).readAsStringSync();
15 - final config = json.decode(inoutContent);
15 + final config = json.decode(inoutContent) as Map<String, String>;
16 final output =
17 'const salt = \'${config["salt"]}\';\nconst key = \'${config["key"]}\';\nconst walletSalt = \'${config["walletSalt"]}\';\nconst shortKey = \'${config["shortKey"]}\';\nconst change_now_api_key = \'${config["change_now_api_key"]}\';';
18
19 - File(outputPath).writeAsString(output);
19 + await File(outputPath).writeAsString(output);
20 }