cake_wallet/lib/utils/mobx.dart

167 lines
4.1 KiB
Dart
Raw Normal View History

2020-09-07 15:13:39 +00:00
import 'dart:async';
import 'package:hive/hive.dart';
2020-08-27 16:54:34 +00:00
import 'package:mobx/mobx.dart';
2020-09-07 15:13:39 +00:00
mixin Keyable {
dynamic keyIndex;
}
void connectMapToListWithTransform<T extends Keyable, Y extends Keyable>(
ObservableMap<dynamic, T> source,
ObservableList<Y> dest,
Y Function(T) transform,
{bool Function(T) filter}) {
source.observe((MapChange<dynamic, T> change) {
switch (change.type) {
case OperationType.add:
if (filter?.call(change.newValue) ?? true) {
dest.add(transform(change.newValue));
}
break;
case OperationType.remove:
// Hive could has equal index and key
2020-09-26 19:17:31 +00:00
dest.removeWhere((elem) =>
elem.keyIndex == (change.key ?? change.newValue.keyIndex));
break;
case OperationType.update:
for (var i = 0; i < dest.length; i++) {
final item = dest[i];
if (item.keyIndex == change.key) {
dest[i] = transform(change.newValue);
}
}
break;
}
});
}
2020-09-26 19:17:31 +00:00
typedef Filter<T> = bool Function(T);
typedef Transform<T, Y> = Y Function(T);
enum ChangeType { update, delete, add }
class EntityChange<T extends Keyable> {
EntityChange(this.value, this.type, {dynamic key}) : _key = key;
dynamic get key => _key ?? value.keyIndex;
final T value;
final ChangeType type;
final dynamic _key;
}
extension MobxBindable<T extends Keyable> on Box<T> {
StreamSubscription<BoxEvent> bindToList(
ObservableList<T> dest, {
bool initialFire = false,
Filter<T> filter,
}) {
if (initialFire) {
dest.addAll(values);
}
return watch().listen((event) {
2020-10-02 17:28:29 +00:00
if (filter != null && event.value != null && !filter(event.value as T)) {
2020-09-26 19:17:31 +00:00
return;
}
dest.acceptBoxChange(event);
});
}
StreamSubscription<BoxEvent> bindToListWithTransform<Y extends Keyable>(
ObservableList<Y> dest,
Transform<T, Y> transform, {
bool initialFire = false,
Filter<T> filter,
}) {
if (initialFire) {
dest.addAll(values.map((value) => transform(value)));
}
return watch().listen((event) {
2020-10-02 17:28:29 +00:00
if (filter != null && event.value != null && !filter(event.value as T)) {
2020-09-26 19:17:31 +00:00
return;
}
2020-09-28 15:47:43 +00:00
dest.acceptBoxChange(event,
transformed: event.deleted ? null : transform(event.value as T));
2020-09-26 19:17:31 +00:00
});
}
}
extension HiveBindable<T extends Keyable> on ObservableList<T> {
Stream<EntityChange<T>> listen() {
// ignore: close_sinks
final controller = StreamController<EntityChange<T>>();
observe((ListChange<T> change) {
2020-09-07 15:13:39 +00:00
change.elementChanges.forEach((change) {
2020-09-26 19:17:31 +00:00
ChangeType type;
2020-09-07 15:13:39 +00:00
switch (change.type) {
case OperationType.add:
2020-09-26 19:17:31 +00:00
type = ChangeType.add;
2020-09-07 15:13:39 +00:00
break;
case OperationType.remove:
2020-09-26 19:17:31 +00:00
type = ChangeType.delete;
2020-09-07 15:13:39 +00:00
break;
case OperationType.update:
2020-09-26 19:17:31 +00:00
type = ChangeType.update;
2020-09-07 15:13:39 +00:00
break;
}
2020-09-26 19:17:31 +00:00
final value = change.newValue as T;
2020-09-28 15:47:43 +00:00
controller.add(EntityChange(value, type,
key: type == ChangeType.delete ? change.index : value.keyIndex));
2020-09-07 15:13:39 +00:00
});
});
2020-09-26 19:17:31 +00:00
return controller.stream;
}
StreamSubscription<EntityChange<T>> bindToList(ObservableList<T> dest) =>
listen().listen((event) => dest.acceptEntityChange(event));
void acceptBoxChange(BoxEvent event, {T transformed}) {
2020-09-07 15:13:39 +00:00
if (event.deleted) {
2020-09-30 18:23:15 +00:00
removeWhere((el) {
2020-10-02 17:28:29 +00:00
return el.keyIndex == event.key;
});
2020-09-26 19:17:31 +00:00
2020-10-02 17:28:29 +00:00
return;
}
2020-09-30 18:23:15 +00:00
2020-09-26 19:17:31 +00:00
final dynamic value = transformed ?? event.value;
if (value is T) {
final index = indexWhere((el) => el.keyIndex == value.keyIndex);
if (index > -1) {
this.setAll(index, [value]); // FIXME: fixme
} else {
add(value);
}
}
}
void acceptEntityChange(EntityChange<T> event) {
if (event.type == ChangeType.delete) {
removeWhere((el) => el.keyIndex == event.key);
2020-10-02 17:28:29 +00:00
return;
2020-09-07 15:13:39 +00:00
}
final dynamic value = event.value;
if (value is T) {
2020-09-26 19:17:31 +00:00
final index = indexWhere((el) => el.keyIndex == value.keyIndex);
2020-09-07 15:13:39 +00:00
2020-09-26 19:17:31 +00:00
if (index > -1) {
this.setAll(index, [value]); // FIXME: fixme
2020-09-07 15:13:39 +00:00
} else {
2020-09-26 19:17:31 +00:00
add(value);
2020-09-07 15:13:39 +00:00
}
}
2020-09-26 19:17:31 +00:00
}
2020-08-27 16:54:34 +00:00
}