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';
|
2021-12-24 12:37:24 +00:00
|
|
|
import 'package:cw_core/keyable.dart';
|
2020-09-07 15:13:39 +00:00
|
|
|
|
2020-09-22 13:35:23 +00:00
|
|
|
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));
|
2020-09-22 13:35:23 +00:00
|
|
|
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) {
|
2020-12-15 16:29:10 +00:00
|
|
|
final res = filter != null ? values.where(filter) : values;
|
|
|
|
dest.addAll(res);
|
2020-09-26 19:17:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
}
|