Merge redesign part 3.

This commit is contained in:
M 2020-09-07 18:13:39 +03:00
parent 42ed4faf73
commit 70ff011fc6
13 changed files with 156 additions and 76 deletions

View file

@ -87,7 +87,7 @@ class ElectrumClient {
Future<void> ping() async {
try {
await callWithTimeout(method: 'server.ping');
// await callWithTimeout(method: 'server.ping');
_setIsConnected(true);
} on RequestFailedTimeoutException catch (_) {
_setIsConnected(false);

View file

@ -12,7 +12,7 @@ class ContactService {
Future add(Contact contact) async {
await contactSource.add(contact);
contactListStore.contacts.add(contact);
// contactListStore.contacts.add(contact);
}
Future update(Contact contact) async {

View file

@ -294,11 +294,13 @@ Future setup(
getIt.registerFactoryParam<ContactViewModel, Contact, void>(
(Contact contact, _) => ContactViewModel(
getIt.get<ContactService>(), getIt.get<AppStore>().wallet,
contactSource, getIt.get<AppStore>().wallet,
contact: contact));
getIt.registerFactory(() => ContactListViewModel(
getIt.get<AppStore>().contactListStore, getIt.get<ContactService>()));
getIt.get<AppStore>().contactListStore,
getIt.get<ContactService>(),
contactSource));
getIt.registerFactory(
() => ContactListPage(getIt.get<ContactListViewModel>()));

View file

@ -1,11 +1,12 @@
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
import 'package:cake_wallet/utils/mobx.dart';
part 'contact.g.dart';
@HiveType(typeId: 0)
class Contact extends HiveObject {
class Contact extends HiveObject with Keyable {
Contact({@required this.name, @required this.address, CryptoCurrency type})
: raw = type?.raw;
@ -22,6 +23,9 @@ class Contact extends HiveObject {
CryptoCurrency get type => CryptoCurrency.deserialize(raw: raw);
@override
dynamic get keyIndex => key;
@override
bool operator ==(Object o) => o is Contact && o.key == key;

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/utils/mobx.dart';
import 'package:flutter/foundation.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
@ -8,7 +9,7 @@ import 'package:cake_wallet/src/domain/common/digest_request.dart';
part 'node.g.dart';
@HiveType(typeId: 1)
class Node extends HiveObject {
class Node extends HiveObject with Keyable {
Node(
{@required this.uri,
@required WalletType type,

View file

@ -108,7 +108,7 @@ class NodeListPage extends BasePage {
});
final dismissibleRow = Dismissible(
key: Key('${node.value.key}'),
key: Key('${node.keyIndex}'),
confirmDismiss: (direction) async {
return await showDialog(
context: context,

View file

@ -44,9 +44,9 @@ abstract class SettingsStoreBase with Store {
languageCode = initialLanguageCode;
currentLocale = initialCurrentLocale;
itemHeaders = {};
this.nodes = ObservableMap<WalletType, Node>.of(nodes);
_sharedPreferences = sharedPreferences;
_nodeSource = nodeSource;
_nodes = nodes;
}
static const currentNodeIdKey = 'current_node_id';
@ -101,9 +101,9 @@ abstract class SettingsStoreBase with Store {
SharedPreferences _sharedPreferences;
Box<Node> _nodeSource;
Map<WalletType, Node> _nodes;
ObservableMap<WalletType, Node> nodes;
Node getCurrentNode(WalletType walletType) => _nodes[walletType];
Node getCurrentNode(WalletType walletType) => nodes[walletType];
Future<void> setCurrentNode(Node node, WalletType walletType) async {
switch (walletType) {
@ -118,7 +118,7 @@ abstract class SettingsStoreBase with Store {
break;
}
_nodes[walletType] = node;
nodes[walletType] = node;
}
static Future<SettingsStore> load(

11
lib/utils/item_cell.dart Normal file
View file

@ -0,0 +1,11 @@
import 'package:flutter/foundation.dart';
import 'package:cake_wallet/utils/mobx.dart';
class ItemCell<Item> with Keyable {
ItemCell(this.value, {@required this.isSelected, @required dynamic key}) {
keyIndex = key;
}
final Item value;
final bool isSelected;
}

View file

@ -1,46 +1,90 @@
import 'dart:async';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
void connectDifferent<T, Y>(
mixin Keyable {
dynamic keyIndex;
}
void connectDifferent<T extends Keyable, Y extends Keyable>(
ObservableList<T> source, ObservableList<Y> dest, Y Function(T) transform,
{bool Function(T) filter}) {
source.observe((ListChange<T> change) {
// switch (change.type) {
// case OperationType.add:
// final _values = change.added;
// Iterable<T> values;
change.elementChanges.forEach((change) {
switch (change.type) {
case OperationType.add:
if (filter?.call(change.newValue as T) ?? true) {
dest.add(transform(change.newValue as T));
}
break;
case OperationType.remove:
// Hive could has equal index and key
dest.removeWhere(
(elem) => elem.keyIndex == (change.oldValue.key ?? change.index));
break;
case OperationType.update:
for (var i = 0; i < dest.length; i++) {
final item = dest[i];
// if (filter != null) {
// values = _values.where(filter);
// }
// dest.addAll(values.map((e) => transform(e)));
// break;
// case OperationType.remove:
// change.removed.forEach((element) {
// dest.remove(element);
// });
// // dest.removeAt(change.index);
// break;
// case OperationType.update:
// // change.index
// break;
// }
if (item.keyIndex == change.newValue.key) {
dest[i] = transform(change.newValue as T);
}
}
break;
}
});
});
}
void connect<T>(ObservableList<T> source, ObservableList<T> dest) {
void connect<T extends Keyable>(
ObservableList<T> source, ObservableList<T> dest) {
source.observe((ListChange<T> change) {
// switch (change.type) {
// case OperationType.add:
// dest.addAll(change.added);
// break;
// case OperationType.remove:
// dest.removeAt(change.index);
// break;
// case OperationType.update:
// // change.index
// break;
// }
source.observe((ListChange<T> change) {
change.elementChanges.forEach((change) {
switch (change.type) {
case OperationType.add:
// if (filter?.call(change.newValue as T) ?? true) {
dest.add(change.newValue as T);
// }
break;
case OperationType.remove:
// Hive could has equal index and key
dest.removeWhere((elem) =>
elem.keyIndex == (change.oldValue.key ?? change.index));
break;
case OperationType.update:
for (var i = 0; i < dest.length; i++) {
final item = dest[i];
if (item.keyIndex == change.newValue.key) {
dest[i] = change.newValue as T;
}
}
break;
}
});
});
});
}
StreamSubscription<BoxEvent> bindBox<T extends Keyable>(
Box<T> source, ObservableList<T> dest) {
return source.watch().listen((event) {
if (event.deleted) {
dest.removeWhere((el) => el.keyIndex == event.key);
}
final dynamic value = event.value;
if (value is T) {
final elIndex = dest.indexWhere((el) => el.keyIndex == value.keyIndex);
if (elIndex > -1) {
dest[elIndex] = value;
} else {
dest.add(value);
}
}
});
}

View file

@ -1,20 +1,34 @@
import 'dart:async';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/core/contact_service.dart';
import 'package:cake_wallet/store/contact_list_store.dart';
import 'package:cake_wallet/src/domain/common/contact.dart';
import 'package:cake_wallet/utils/mobx.dart';
part 'contact_list_view_model.g.dart';
class ContactListViewModel = ContactListViewModelBase with _$ContactListViewModel;
class ContactListViewModel = ContactListViewModelBase
with _$ContactListViewModel;
abstract class ContactListViewModelBase with Store {
ContactListViewModelBase(this.addressBookStore, this.contactService);
ContactListViewModelBase(
this.addressBookStore, this.contactService, this.contactSource) {
_subscription = bindBox(contactSource, addressBookStore.contacts);
}
final ContactListStore addressBookStore;
final ContactService contactService;
final Box<Contact> contactSource;
@computed
ObservableList<Contact> get contacts => addressBookStore.contacts;
StreamSubscription<BoxEvent> _subscription;
void dispose() {
_subscription.cancel();
}
Future<void> delete(Contact contact) async => contactService.delete(contact);
}
}

View file

@ -1,3 +1,4 @@
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
import 'package:cake_wallet/core/wallet_base.dart';
import 'package:cake_wallet/core/contact_service.dart';
@ -10,7 +11,7 @@ part 'contact_view_model.g.dart';
class ContactViewModel = ContactViewModelBase with _$ContactViewModel;
abstract class ContactViewModelBase with Store {
ContactViewModelBase(this._contactService, this._wallet, {Contact contact})
ContactViewModelBase(this._contacts, this._wallet, {Contact contact})
: state = InitialContactViewModelState(),
currencies = CryptoCurrency.all,
_contact = contact {
@ -33,12 +34,14 @@ abstract class ContactViewModelBase with Store {
@computed
bool get isReady =>
(name?.isNotEmpty ?? false) && (currency?.toString()?.isNotEmpty ?? false)
&& (address?.isNotEmpty ?? false);
(name?.isNotEmpty ?? false) &&
(currency?.toString()?.isNotEmpty ?? false) &&
(address?.isNotEmpty ?? false);
final List<CryptoCurrency> currencies;
final ContactService _contactService;
// final ContactService _contactService;
final WalletBase _wallet;
final Box<Contact> _contacts;
final Contact _contact;
@action
@ -57,10 +60,13 @@ abstract class ContactViewModelBase with Store {
_contact.name = name;
_contact.address = address;
_contact.updateCryptoCurrency(currency: currency);
await _contactService.update(_contact);
await _contacts.put(_contact.key, _contact);
// await _contactService.update(_contact);
} else {
await _contactService
await _contacts
.add(Contact(name: name, address: address, type: currency));
// await _contactService
// .add(Contact(name: name, address: address, type: currency));
}
state = ContactSavingSuccessfully();

View file

@ -1,3 +1,4 @@
import 'package:cake_wallet/utils/item_cell.dart';
import 'package:flutter/foundation.dart';
import 'package:hive/hive.dart';
import 'package:mobx/mobx.dart';
@ -14,13 +15,6 @@ part 'node_list_view_model.g.dart';
class NodeListViewModel = NodeListViewModelBase with _$NodeListViewModel;
class ItemCell<Item> {
ItemCell(this.value, {@required this.isSelected});
final Item value;
final bool isSelected;
}
abstract class NodeListViewModelBase with Store {
NodeListViewModelBase(
this._nodeListStore, this._nodeSource, this._wallet, this._settingsStore)
@ -29,16 +23,16 @@ abstract class NodeListViewModelBase with Store {
final values = _nodeListStore.nodes;
nodes.clear();
nodes.addAll(values.where((Node node) => node.type == _wallet.type).map(
(Node val) =>
ItemCell<Node>(val, isSelected: val.key == currentNode.key)));
(Node val) => ItemCell<Node>(val,
isSelected: val.key == currentNode.key, key: val.key)));
connectDifferent(
_nodeListStore.nodes,
nodes,
(Node val) =>
ItemCell<Node>(val, isSelected: val.key == currentNode.key),
filter: (Node val) {
return val.type == _wallet.type;
});
(Node val) => ItemCell<Node>(val,
isSelected: val.key == currentNode.key, key: val.key),
filter: (Node val) => val.type == _wallet.type);
reaction((_) => _settingsStore.nodes[_wallet.type],
(Node _) => _updateCurrentNode());
}
ObservableList<ItemCell<Node>> nodes;
@ -66,17 +60,18 @@ abstract class NodeListViewModelBase with Store {
break;
}
await _wallet.connectToNode(node: node);
await setAsCurrent(node);
}
Future<void> delete(Node node) async => _nodeSource.delete(node.key);
Future<void> setAsCurrent(Node node) async {
await _wallet.connectToNode(node: node);
await _settingsStore.setCurrentNode(node, _wallet.type);
_updateCurrentNode();
await _wallet.connectToNode(node: node);
}
@action
void _updateCurrentNode() {
final currentNode = _settingsStore.getCurrentNode(_wallet.type);
@ -85,7 +80,8 @@ abstract class NodeListViewModelBase with Store {
final isSelected = item.value.key == currentNode.key;
if (item.isSelected != isSelected) {
nodes[i] = ItemCell<Node>(item.value, isSelected: isSelected);
nodes[i] = ItemCell<Node>(item.value,
isSelected: isSelected, key: item.keyIndex);
}
}
}

View file

@ -67,7 +67,8 @@ abstract class WalletAddressListViewModelBase with Store {
WalletType get type => _wallet.type;
@computed
WalletAddressListItem get address => WalletAddressListItem(address: _wallet.address);
WalletAddressListItem get address =>
WalletAddressListItem(address: _wallet.address);
@computed
PaymentURI get uri {
@ -100,15 +101,16 @@ abstract class WalletAddressListViewModelBase with Store {
}
if (wallet is BitcoinWallet) {
final bitcoinAddresses = wallet.addresses.map(
(addr) => WalletAddressListItem(name: addr.label, address: addr.address));
final bitcoinAddresses = wallet.addresses.map((addr) =>
WalletAddressListItem(name: addr.label, address: addr.address));
addressList.addAll(bitcoinAddresses);
}
return addressList;
}
set address(WalletAddressListItem address) => _wallet.address = address.address;
set address(WalletAddressListItem address) =>
_wallet.address = address.address;
bool hasAccounts;