Merge redesign part 3.
M committed
Sep 7, 2020 at 18:13 UTC
70ff011fc6943693dc699b8309578488eb0d57cf
13 files changed
+157
-77
lib/bitcoin/electrum.dart
+1
-1
@@ -87,7 +87,7 @@ class ElectrumClient {
87
88
Future<void> ping() async {
89
try {
90
- await callWithTimeout(method: 'server.ping');
90
+ // await callWithTimeout(method: 'server.ping');
91
_setIsConnected(true);
92
} on RequestFailedTimeoutException catch (_) {
93
_setIsConnected(false);
lib/core/contact_service.dart
+1
-1
@@ -12,7 +12,7 @@ class ContactService {
12
13
Future add(Contact contact) async {
14
await contactSource.add(contact);
15
- contactListStore.contacts.add(contact);
15
+ // contactListStore.contacts.add(contact);
16
}
17
18
Future update(Contact contact) async {
lib/di.dart
+4
-2
@@ -294,11 +294,13 @@ Future setup(
294
295
getIt.registerFactoryParam<ContactViewModel, Contact, void>(
296
(Contact contact, _) => ContactViewModel(
297
- getIt.get<ContactService>(), getIt.get<AppStore>().wallet,
297
+ contactSource, getIt.get<AppStore>().wallet,
298
contact: contact));
299
300
getIt.registerFactory(() => ContactListViewModel(
301
- getIt.get<AppStore>().contactListStore, getIt.get<ContactService>()));
301
+ getIt.get<AppStore>().contactListStore,
302
+ getIt.get<ContactService>(),
303
+ contactSource));
304
305
getIt.registerFactory(
306
() => ContactListPage(getIt.get<ContactListViewModel>()));
lib/src/domain/common/contact.dart
+5
-1
@@ -1,11 +1,12 @@
1
import 'package:flutter/foundation.dart';
2
import 'package:hive/hive.dart';
3
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
4
+import 'package:cake_wallet/utils/mobx.dart';
5
6
part 'contact.g.dart';
7
8
@HiveType(typeId: 0)
8
-class Contact extends HiveObject {
9
+class Contact extends HiveObject with Keyable {
10
Contact({@required this.name, @required this.address, CryptoCurrency type})
11
: raw = type?.raw;
12
@@ -22,6 +23,9 @@ class Contact extends HiveObject {
23
24
CryptoCurrency get type => CryptoCurrency.deserialize(raw: raw);
25
26
+ @override
27
+ dynamic get keyIndex => key;
28
+
29
@override
30
bool operator ==(Object o) => o is Contact && o.key == key;
31
lib/src/domain/common/node.dart
+2
-1
@@ -1,3 +1,4 @@
1
+import 'package:cake_wallet/utils/mobx.dart';
2
import 'package:flutter/foundation.dart';
3
import 'dart:convert';
4
import 'package:http/http.dart' as http;
@@ -8,7 +9,7 @@ import 'package:cake_wallet/src/domain/common/digest_request.dart';
9
part 'node.g.dart';
10
11
@HiveType(typeId: 1)
11
-class Node extends HiveObject {
12
+class Node extends HiveObject with Keyable {
13
Node(
14
{@required this.uri,
15
@required WalletType type,
lib/src/screens/nodes/nodes_list_page.dart
+1
-1
@@ -108,7 +108,7 @@ class NodeListPage extends BasePage {
108
});
109
110
final dismissibleRow = Dismissible(
111
- key: Key('${node.value.key}'),
111
+ key: Key('${node.keyIndex}'),
112
confirmDismiss: (direction) async {
113
return await showDialog(
114
context: context,
lib/store/settings_store.dart
+4
-4
@@ -44,9 +44,9 @@ abstract class SettingsStoreBase with Store {
44
languageCode = initialLanguageCode;
45
currentLocale = initialCurrentLocale;
46
itemHeaders = {};
47
+ this.nodes = ObservableMap<WalletType, Node>.of(nodes);
48
_sharedPreferences = sharedPreferences;
49
_nodeSource = nodeSource;
49
- _nodes = nodes;
50
}
51
52
static const currentNodeIdKey = 'current_node_id';
@@ -101,9 +101,9 @@ abstract class SettingsStoreBase with Store {
101
SharedPreferences _sharedPreferences;
102
Box<Node> _nodeSource;
103
104
- Map<WalletType, Node> _nodes;
104
+ ObservableMap<WalletType, Node> nodes;
105
106
- Node getCurrentNode(WalletType walletType) => _nodes[walletType];
106
+ Node getCurrentNode(WalletType walletType) => nodes[walletType];
107
108
Future<void> setCurrentNode(Node node, WalletType walletType) async {
109
switch (walletType) {
@@ -118,7 +118,7 @@ abstract class SettingsStoreBase with Store {
118
break;
119
}
120
121
- _nodes[walletType] = node;
121
+ nodes[walletType] = node;
122
}
123
124
static Future<SettingsStore> load(
lib/utils/item_cell.dart
new
+11
@@ -0,0 +1,11 @@
1
+import 'package:flutter/foundation.dart';
2
+import 'package:cake_wallet/utils/mobx.dart';
3
+
4
+class ItemCell<Item> with Keyable {
5
+ ItemCell(this.value, {@required this.isSelected, @required dynamic key}) {
6
+ keyIndex = key;
7
+ }
8
+
9
+ final Item value;
10
+ final bool isSelected;
11
+}
lib/utils/mobx.dart
+79
-35
@@ -1,46 +1,90 @@
1
+import 'dart:async';
2
+
3
+import 'package:hive/hive.dart';
4
import 'package:mobx/mobx.dart';
5
3
-void connectDifferent<T, Y>(
6
+mixin Keyable {
7
+ dynamic keyIndex;
8
+}
9
+
10
+void connectDifferent<T extends Keyable, Y extends Keyable>(
11
ObservableList<T> source, ObservableList<Y> dest, Y Function(T) transform,
12
{bool Function(T) filter}) {
13
source.observe((ListChange<T> change) {
7
-// switch (change.type) {
8
-// case OperationType.add:
9
-// final _values = change.added;
10
-// Iterable<T> values;
11
-
12
-// if (filter != null) {
13
-// values = _values.where(filter);
14
-// }
15
-
16
-// dest.addAll(values.map((e) => transform(e)));
17
-// break;
18
-// case OperationType.remove:
19
-// change.removed.forEach((element) {
20
-// dest.remove(element);
21
-// });
22
-
23
-// // dest.removeAt(change.index);
24
-// break;
25
-// case OperationType.update:
26
-// // change.index
27
-// break;
28
-// }
14
+ change.elementChanges.forEach((change) {
15
+ switch (change.type) {
16
+ case OperationType.add:
17
+ if (filter?.call(change.newValue as T) ?? true) {
18
+ dest.add(transform(change.newValue as T));
19
+ }
20
+ break;
21
+ case OperationType.remove:
22
+ // Hive could has equal index and key
23
+ dest.removeWhere(
24
+ (elem) => elem.keyIndex == (change.oldValue.key ?? change.index));
25
+ break;
26
+ case OperationType.update:
27
+ for (var i = 0; i < dest.length; i++) {
28
+ final item = dest[i];
29
+
30
+ if (item.keyIndex == change.newValue.key) {
31
+ dest[i] = transform(change.newValue as T);
32
+ }
33
+ }
34
+ break;
35
+ }
36
+ });
37
});
38
}
39
32
-void connect<T>(ObservableList<T> source, ObservableList<T> dest) {
40
+void connect<T extends Keyable>(
41
+ ObservableList<T> source, ObservableList<T> dest) {
42
source.observe((ListChange<T> change) {
34
-// switch (change.type) {
35
-// case OperationType.add:
36
-// dest.addAll(change.added);
37
-// break;
38
-// case OperationType.remove:
39
-// dest.removeAt(change.index);
40
-// break;
41
-// case OperationType.update:
42
-// // change.index
43
-// break;
44
-// }
43
+ source.observe((ListChange<T> change) {
44
+ change.elementChanges.forEach((change) {
45
+ switch (change.type) {
46
+ case OperationType.add:
47
+ // if (filter?.call(change.newValue as T) ?? true) {
48
+ dest.add(change.newValue as T);
49
+ // }
50
+ break;
51
+ case OperationType.remove:
52
+ // Hive could has equal index and key
53
+ dest.removeWhere((elem) =>
54
+ elem.keyIndex == (change.oldValue.key ?? change.index));
55
+ break;
56
+ case OperationType.update:
57
+ for (var i = 0; i < dest.length; i++) {
58
+ final item = dest[i];
59
+
60
+ if (item.keyIndex == change.newValue.key) {
61
+ dest[i] = change.newValue as T;
62
+ }
63
+ }
64
+ break;
65
+ }
66
+ });
67
+ });
68
+ });
69
+}
70
+
71
+StreamSubscription<BoxEvent> bindBox<T extends Keyable>(
72
+ Box<T> source, ObservableList<T> dest) {
73
+ return source.watch().listen((event) {
74
+ if (event.deleted) {
75
+ dest.removeWhere((el) => el.keyIndex == event.key);
76
+ }
77
+
78
+ final dynamic value = event.value;
79
+
80
+ if (value is T) {
81
+ final elIndex = dest.indexWhere((el) => el.keyIndex == value.keyIndex);
82
+
83
+ if (elIndex > -1) {
84
+ dest[elIndex] = value;
85
+ } else {
86
+ dest.add(value);
87
+ }
88
+ }
89
});
90
}
lib/view_model/contact_list/contact_list_view_model.dart
+18
-4
@@ -1,20 +1,34 @@
1
+import 'dart:async';
2
+
3
+import 'package:hive/hive.dart';
4
import 'package:mobx/mobx.dart';
5
import 'package:cake_wallet/core/contact_service.dart';
6
import 'package:cake_wallet/store/contact_list_store.dart';
7
import 'package:cake_wallet/src/domain/common/contact.dart';
8
+import 'package:cake_wallet/utils/mobx.dart';
9
10
part 'contact_list_view_model.g.dart';
11
8
-class ContactListViewModel = ContactListViewModelBase with _$ContactListViewModel;
12
+class ContactListViewModel = ContactListViewModelBase
13
+ with _$ContactListViewModel;
14
15
abstract class ContactListViewModelBase with Store {
11
- ContactListViewModelBase(this.addressBookStore, this.contactService);
16
+ ContactListViewModelBase(
17
+ this.addressBookStore, this.contactService, this.contactSource) {
18
+ _subscription = bindBox(contactSource, addressBookStore.contacts);
19
+ }
20
21
final ContactListStore addressBookStore;
22
final ContactService contactService;
23
+ final Box<Contact> contactSource;
24
16
- @computed
25
ObservableList<Contact> get contacts => addressBookStore.contacts;
26
27
+ StreamSubscription<BoxEvent> _subscription;
28
+
29
+ void dispose() {
30
+ _subscription.cancel();
31
+ }
32
+
33
Future<void> delete(Contact contact) async => contactService.delete(contact);
20
-}
\ No newline at end of file
34
+}
lib/view_model/contact_list/contact_view_model.dart
+12
-6
@@ -1,3 +1,4 @@
1
+import 'package:hive/hive.dart';
2
import 'package:mobx/mobx.dart';
3
import 'package:cake_wallet/core/wallet_base.dart';
4
import 'package:cake_wallet/core/contact_service.dart';
@@ -10,7 +11,7 @@ part 'contact_view_model.g.dart';
11
class ContactViewModel = ContactViewModelBase with _$ContactViewModel;
12
13
abstract class ContactViewModelBase with Store {
13
- ContactViewModelBase(this._contactService, this._wallet, {Contact contact})
14
+ ContactViewModelBase(this._contacts, this._wallet, {Contact contact})
15
: state = InitialContactViewModelState(),
16
currencies = CryptoCurrency.all,
17
_contact = contact {
@@ -33,12 +34,14 @@ abstract class ContactViewModelBase with Store {
34
35
@computed
36
bool get isReady =>
36
- (name?.isNotEmpty ?? false) && (currency?.toString()?.isNotEmpty ?? false)
37
- && (address?.isNotEmpty ?? false);
37
+ (name?.isNotEmpty ?? false) &&
38
+ (currency?.toString()?.isNotEmpty ?? false) &&
39
+ (address?.isNotEmpty ?? false);
40
41
final List<CryptoCurrency> currencies;
40
- final ContactService _contactService;
42
+ // final ContactService _contactService;
43
final WalletBase _wallet;
44
+ final Box<Contact> _contacts;
45
final Contact _contact;
46
47
@action
@@ -57,10 +60,13 @@ abstract class ContactViewModelBase with Store {
60
_contact.name = name;
61
_contact.address = address;
62
_contact.updateCryptoCurrency(currency: currency);
60
- await _contactService.update(_contact);
63
+ await _contacts.put(_contact.key, _contact);
64
+ // await _contactService.update(_contact);
65
} else {
62
- await _contactService
66
+ await _contacts
67
.add(Contact(name: name, address: address, type: currency));
68
+ // await _contactService
69
+ // .add(Contact(name: name, address: address, type: currency));
70
}
71
72
state = ContactSavingSuccessfully();
lib/view_model/node_list/node_list_view_model.dart
+13
-17
@@ -1,3 +1,4 @@
1
+import 'package:cake_wallet/utils/item_cell.dart';
2
import 'package:flutter/foundation.dart';
3
import 'package:hive/hive.dart';
4
import 'package:mobx/mobx.dart';
@@ -14,13 +15,6 @@ part 'node_list_view_model.g.dart';
15
16
class NodeListViewModel = NodeListViewModelBase with _$NodeListViewModel;
17
17
-class ItemCell<Item> {
18
- ItemCell(this.value, {@required this.isSelected});
19
-
20
- final Item value;
21
- final bool isSelected;
22
-}
23
-
18
abstract class NodeListViewModelBase with Store {
19
NodeListViewModelBase(
20
this._nodeListStore, this._nodeSource, this._wallet, this._settingsStore)
@@ -29,16 +23,16 @@ abstract class NodeListViewModelBase with Store {
23
final values = _nodeListStore.nodes;
24
nodes.clear();
25
nodes.addAll(values.where((Node node) => node.type == _wallet.type).map(
32
- (Node val) =>
33
- ItemCell<Node>(val, isSelected: val.key == currentNode.key)));
26
+ (Node val) => ItemCell<Node>(val,
27
+ isSelected: val.key == currentNode.key, key: val.key)));
28
connectDifferent(
29
_nodeListStore.nodes,
30
nodes,
37
- (Node val) =>
38
- ItemCell<Node>(val, isSelected: val.key == currentNode.key),
39
- filter: (Node val) {
40
- return val.type == _wallet.type;
41
- });
31
+ (Node val) => ItemCell<Node>(val,
32
+ isSelected: val.key == currentNode.key, key: val.key),
33
+ filter: (Node val) => val.type == _wallet.type);
34
+ reaction((_) => _settingsStore.nodes[_wallet.type],
35
+ (Node _) => _updateCurrentNode());
36
}
37
38
ObservableList<ItemCell<Node>> nodes;
@@ -66,17 +60,18 @@ abstract class NodeListViewModelBase with Store {
60
break;
61
}
62
69
- await _wallet.connectToNode(node: node);
63
+ await setAsCurrent(node);
64
}
65
66
Future<void> delete(Node node) async => _nodeSource.delete(node.key);
67
68
Future<void> setAsCurrent(Node node) async {
75
- await _wallet.connectToNode(node: node);
69
await _settingsStore.setCurrentNode(node, _wallet.type);
70
_updateCurrentNode();
71
+ await _wallet.connectToNode(node: node);
72
}
73
74
+ @action
75
void _updateCurrentNode() {
76
final currentNode = _settingsStore.getCurrentNode(_wallet.type);
77
@@ -85,7 +80,8 @@ abstract class NodeListViewModelBase with Store {
80
final isSelected = item.value.key == currentNode.key;
81
82
if (item.isSelected != isSelected) {
88
- nodes[i] = ItemCell<Node>(item.value, isSelected: isSelected);
83
+ nodes[i] = ItemCell<Node>(item.value,
84
+ isSelected: isSelected, key: item.keyIndex);
85
}
86
}
87
}
lib/view_model/wallet_address_list/wallet_address_list_view_model.dart
+6
-4
@@ -67,7 +67,8 @@ abstract class WalletAddressListViewModelBase with Store {
67
WalletType get type => _wallet.type;
68
69
@computed
70
- WalletAddressListItem get address => WalletAddressListItem(address: _wallet.address);
70
+ WalletAddressListItem get address =>
71
+ WalletAddressListItem(address: _wallet.address);
72
73
@computed
74
PaymentURI get uri {
@@ -100,15 +101,16 @@ abstract class WalletAddressListViewModelBase with Store {
101
}
102
103
if (wallet is BitcoinWallet) {
103
- final bitcoinAddresses = wallet.addresses.map(
104
- (addr) => WalletAddressListItem(name: addr.label, address: addr.address));
104
+ final bitcoinAddresses = wallet.addresses.map((addr) =>
105
+ WalletAddressListItem(name: addr.label, address: addr.address));
106
addressList.addAll(bitcoinAddresses);
107
}
108
109
return addressList;
110
}
111
111
- set address(WalletAddressListItem address) => _wallet.address = address.address;
112
+ set address(WalletAddressListItem address) =>
113
+ _wallet.address = address.address;
114
115
bool hasAccounts;
116