Line data Source code
1 : import 'dart:async';
2 : import 'package:get/src/get_main.dart';
3 : import 'rx_callbacks.dart';
4 : import 'rx_interface.dart';
5 : import 'rx_model.dart';
6 :
7 : class _StoredValue<T> implements RxInterface<T> {
8 : StreamController<Change<T>> subject = StreamController<Change<T>>.broadcast();
9 : StreamController<Change<T>> _changeCtl =
10 : StreamController<Change<T>>.broadcast();
11 : Map<Stream<Change<T>>, StreamSubscription> _subscriptions = Map();
12 :
13 : T _value;
14 4 : T get v {
15 4 : if (Get.obs != null) {
16 12 : Get.obs.addListener(subject.stream);
17 : }
18 4 : return _value;
19 : }
20 :
21 8 : T get value => v;
22 8 : set value(T va) => v = va;
23 :
24 0 : String get string => v.toString();
25 :
26 1 : close() {
27 3 : _subscriptions.forEach((observable, subscription) {
28 1 : subscription.cancel();
29 : });
30 2 : _subscriptions.clear();
31 2 : _changeCtl.close();
32 : }
33 :
34 1 : addListener(Stream<Change<T>> rxGetx) {
35 2 : if (_subscriptions.containsKey(rxGetx)) {
36 : return;
37 : }
38 :
39 4 : _subscriptions[rxGetx] = rxGetx.listen((data) {
40 2 : subject.add(data);
41 : });
42 : }
43 :
44 4 : set v(T val) {
45 8 : if (_value == val) return;
46 4 : T old = _value;
47 4 : _value = val;
48 16 : subject.add(Change<T>($new: val, $old: old, batch: _cb));
49 : }
50 :
51 : int _cb = 0;
52 :
53 4 : _StoredValue([T initial]) : _value = initial {
54 16 : _onChange = subject.stream.asBroadcastStream();
55 : }
56 :
57 0 : void setCast(dynamic /* T */ val) => v = val;
58 :
59 : Stream<Change<T>> _onChange;
60 :
61 0 : Stream<Change<T>> get onChange {
62 0 : _cb++;
63 :
64 0 : _changeCtl.add(Change<T>($new: v, $old: null, batch: _cb));
65 0 : _changeCtl.addStream(_onChange.skipWhile((v) => v.batch < _cb));
66 0 : return _changeCtl.stream.asBroadcastStream();
67 : }
68 :
69 0 : Stream<T> get stream => onChange.map((c) => c.$new);
70 :
71 0 : void bind(RxInterface<T> reactive) {
72 0 : v = reactive.v;
73 0 : reactive.stream.listen((va) => v = va);
74 : }
75 :
76 0 : void bindStream(Stream<T> stream) => stream.listen((va) => v = va);
77 :
78 0 : void bindOrSet(/* T | Stream<T> | Reactive<T> */ other) {
79 0 : if (other is RxInterface<T>) {
80 0 : bind(other);
81 0 : } else if (other is Stream<T>) {
82 0 : bindStream(other.cast<T>());
83 : } else {
84 0 : v = other;
85 : }
86 : }
87 :
88 0 : StreamSubscription<T> listen(ValueCallback<T> callback) =>
89 0 : stream.listen(callback);
90 :
91 0 : Stream<R> map<R>(R mapper(T data)) => stream.map(mapper);
92 : }
93 :
94 : class StringX<String> extends _StoredValue<String> {
95 3 : StringX([String initial]) {
96 3 : _value = initial;
97 12 : _onChange = subject.stream.asBroadcastStream();
98 : }
99 : }
100 :
101 : class IntX<int> extends _StoredValue<int> {
102 4 : IntX([int initial]) {
103 4 : _value = initial;
104 16 : _onChange = subject.stream.asBroadcastStream();
105 : }
106 : }
107 :
108 : class MapX<Map> extends _StoredValue<Map> {
109 3 : MapX([Map initial]) {
110 3 : _value = initial;
111 12 : _onChange = subject.stream.asBroadcastStream();
112 : }
113 : }
114 :
115 : // class ListX<List> extends _StoredValue<List> {
116 : // ListX([List initial]) {
117 : // _value = initial;
118 : // _onChange = subject.stream.asBroadcastStream();
119 : // }
120 : // }
121 :
122 : class ListX<E> extends Iterable<E> implements RxInterface<E> {
123 : /// Create a list similar to `List<T>`
124 :
125 3 : ListX([List<E> initial]) {
126 3 : _list = initial;
127 12 : _onChange = subject.stream.asBroadcastStream();
128 : }
129 :
130 0 : @override
131 0 : Iterator<E> get iterator => _list.iterator;
132 :
133 0 : @override
134 0 : bool get isEmpty => _list.isEmpty;
135 :
136 0 : @override
137 0 : bool get isNotEmpty => _list.isNotEmpty;
138 :
139 : Map<Stream<Change<E>>, StreamSubscription> _subscriptions = Map();
140 :
141 : // StreamSubscription _changectl = StreamSubscription();
142 :
143 : StreamController<Change<E>> _changeCtl =
144 : StreamController<Change<E>>.broadcast();
145 :
146 : @override
147 : StreamController<Change<E>> subject = StreamController<Change<E>>.broadcast();
148 :
149 : /// Adds [item] only if [condition] resolves to true.
150 0 : void addIf(condition, E item) {
151 0 : if (condition is Condition) condition = condition();
152 0 : if (condition is bool && condition) add(item);
153 : }
154 :
155 : /// Adds all [items] only if [condition] resolves to true.
156 0 : void addAllIf(condition, Iterable<E> items) {
157 0 : if (condition is Condition) condition = condition();
158 0 : if (condition is bool && condition) addAll(items);
159 : }
160 :
161 0 : operator []=(int index, E val) {
162 0 : _list[index] = val;
163 0 : subject.add(Change<E>.set($new: val, item: val, pos: index));
164 : }
165 :
166 0 : E operator [](int index) {
167 0 : return value[index];
168 : }
169 :
170 0 : void add(E item) {
171 0 : _list.add(item);
172 0 : subject
173 0 : .add(Change<E>.insert($new: item, item: item, pos: _list.length - 1));
174 : }
175 :
176 3 : void addAll(List<E> item) {
177 6 : _list.addAll(item);
178 21 : subject.add(Change<E>.insert(item: _list, pos: _list.length - 1));
179 : }
180 :
181 : /// Adds only if [item] is not null.
182 0 : void addNonNull(E item) {
183 0 : if (item != null) add(item);
184 : }
185 :
186 : /// Adds only if [item] is not null.
187 3 : void addAllNonNull(Iterable<E> item) {
188 3 : if (item != null) addAll(item);
189 : }
190 :
191 0 : void insert(int index, E item) {
192 0 : _list.insert(index, item);
193 0 : subject.add(Change<E>.insert(item: item, pos: index));
194 : }
195 :
196 0 : void insertAll(int index, Iterable<E> iterable) {
197 0 : _list.insertAll(index, iterable);
198 0 : subject.add(Change<E>.insert(item: iterable.last, pos: index));
199 : }
200 :
201 9 : int get length => value.length;
202 :
203 : /// Removes an item from the list.
204 : ///
205 : /// This is O(N) in the number of items in the list.
206 : ///
207 : /// Returns whether the item was present in the list.
208 0 : bool remove(Object item) {
209 0 : int pos = _list.indexOf(item);
210 0 : bool hasRemoved = _list.remove(item);
211 : if (hasRemoved) {
212 0 : subject.add(Change<E>.remove(item: item, pos: pos));
213 : }
214 : return hasRemoved;
215 : }
216 :
217 0 : E removeAt(int index) {
218 0 : E item = _list.removeAt(index);
219 0 : subject.add(Change<E>.remove(item: item, pos: index));
220 : return item;
221 : }
222 :
223 0 : E removeLast() {
224 0 : int pos = _list.indexOf(_list.last);
225 0 : E item = _list.removeLast();
226 0 : subject.add(Change<E>.remove(item: item, pos: pos));
227 : return item;
228 : }
229 :
230 0 : void removeRange(int start, int end) {
231 0 : _list.removeRange(start, end);
232 0 : subject.add(Change<E>.remove(item: null, pos: null));
233 : }
234 :
235 0 : void removeWhere(bool Function(E) test) {
236 0 : _list.removeWhere(test);
237 0 : subject.add(Change<E>.remove(item: null, pos: null));
238 : }
239 :
240 0 : void clear() {
241 0 : _list.clear();
242 0 : subject.add(Change<E>.clear());
243 : }
244 :
245 2 : close() {
246 6 : _subscriptions.forEach((observable, subscription) {
247 2 : subscription.cancel();
248 : });
249 4 : _subscriptions.clear();
250 4 : subject.close();
251 4 : _changeCtl.close();
252 : }
253 :
254 : /// Replaces all existing items of this list with [item]
255 0 : void assign(E item) {
256 0 : clear();
257 0 : add(item);
258 : }
259 :
260 : /// Replaces all existing items of this list with [items]
261 0 : void assignAll(Iterable<E> items) {
262 0 : clear();
263 0 : addAll(items);
264 : }
265 :
266 : /// A stream of record of changes to this list
267 0 : Stream<Change<E>> get onChange {
268 0 : final now = DateTime.now();
269 :
270 0 : _onChange.skipWhile((m) => m.time.isBefore(now));
271 0 : return _changeCtl.stream.asBroadcastStream();
272 : }
273 :
274 : Stream<Change<E>> _onChange;
275 :
276 2 : addListener(Stream<Change<E>> rxGetx) {
277 4 : if (_subscriptions.containsKey(rxGetx)) {
278 : return;
279 : }
280 8 : _subscriptions[rxGetx] = rxGetx.listen((data) {
281 4 : subject.add(data);
282 : });
283 : }
284 :
285 6 : List<E> get value => v as List<E>;
286 :
287 0 : set value(List<E> va) => assignAll(va);
288 :
289 3 : @override
290 : get v {
291 3 : if (Get.obs != null) {
292 12 : Get.obs.addListener(subject.stream);
293 : }
294 3 : return _list;
295 : }
296 :
297 0 : set v(E val) {
298 0 : assign(val);
299 : }
300 :
301 0 : @override
302 0 : Stream<E> get stream => onChange.map((c) => c.item);
303 :
304 0 : @override
305 : void bind(RxInterface<E> reactive) {
306 0 : v = reactive.v;
307 0 : reactive.stream.listen((va) => v = va);
308 : }
309 :
310 0 : void bindStream(Stream<E> stream) => stream.listen((va) => v = va);
311 :
312 0 : @override
313 : void bindOrSet(/* T | Stream<T> or Rx<T> */ other) {
314 0 : if (other is RxInterface<E>) {
315 0 : bind(other);
316 0 : } else if (other is Stream<E>) {
317 0 : bindStream(other.cast<E>());
318 : } else {
319 0 : v = other;
320 : }
321 : }
322 :
323 0 : @override
324 : StreamSubscription<E> listen(ValueCallback<E> callback) =>
325 0 : stream.listen(callback);
326 :
327 0 : @override
328 0 : void setCast(dynamic val) => v = val;
329 :
330 : List<E> _list = <E>[];
331 : }
332 :
333 : // class ListX<E> extends DelegatingList<E> implements List<E>, RxInterface<E> {
334 : // /// Create a list similar to `List<T>`
335 : // ListX([int length]) : super(length != null ? List<E>(length) : List<E>()) {
336 : // _onChange = subject.stream.asBroadcastStream();
337 : // }
338 :
339 : // ListX.filled(int length, E fill, {bool growable: false})
340 : // : super(List<E>.filled(length, fill, growable: growable)) {
341 : // _onChange = subject.stream.asBroadcastStream();
342 : // }
343 :
344 : // ListX.from(Iterable<E> items, {bool growable: true})
345 : // : super(List<E>.from(items, growable: growable)) {
346 : // _onChange = subject.stream.asBroadcastStream();
347 : // }
348 :
349 : // ListX.union(Iterable<E> items, [E item]) : super(items?.toList() ?? <E>[]) {
350 : // if (item != null) add(item);
351 : // _onChange = subject.stream.asBroadcastStream();
352 : // }
353 :
354 : // ListX.of(Iterable<E> items, {bool growable: true})
355 : // : super(List<E>.of(items, growable: growable));
356 :
357 : // ListX.generate(int length, E generator(int index), {bool growable: true})
358 : // : super(List<E>.generate(length, generator, growable: growable));
359 :
360 : // Map<Stream<Change<E>>, StreamSubscription> _subscriptions = Map();
361 :
362 : // // StreamSubscription _changectl = StreamSubscription();
363 :
364 : // StreamController<Change<E>> _changeCtl =
365 : // StreamController<Change<E>>.broadcast();
366 :
367 : // @override
368 : // StreamController<Change<E>> subject = StreamController<Change<E>>.broadcast();
369 :
370 : // /// Adds [item] only if [condition] resolves to true.
371 : // void addIf(condition, E item) {
372 : // if (condition is Condition) condition = condition();
373 : // if (condition is bool && condition) add(item);
374 : // }
375 :
376 : // /// Adds all [items] only if [condition] resolves to true.
377 : // void addAllIf(condition, Iterable<E> items) {
378 : // if (condition is Condition) condition = condition();
379 : // if (condition is bool && condition) addAll(items);
380 : // }
381 :
382 : // operator []=(int index, E value) {
383 : // super[index] = value;
384 : // if (Get.obs != null) {
385 : // Get.obs.addListener(subject.stream);
386 : // }
387 : // subject.add(Change<E>.set(item: value, pos: index));
388 : // }
389 :
390 : // void _add(E item) => super.add(item);
391 :
392 : // void add(E item) {
393 : // super.add(item);
394 : // subject.add(Change<E>.insert(item: item, pos: length - 1));
395 : // }
396 :
397 : // /// Adds only if [item] is not null.
398 : // void addNonNull(E item) {
399 : // if (item != null) add(item);
400 : // }
401 :
402 : // void insert(int index, E item) {
403 : // super.insert(index, item);
404 : // subject.add(Change<E>.insert(item: item, pos: index));
405 : // }
406 :
407 : // bool remove(Object item) {
408 : // int pos = indexOf(item);
409 : // bool hasRemoved = super.remove(item);
410 : // if (hasRemoved) {
411 : // subject.add(Change<E>.remove(item: item, pos: pos));
412 : // }
413 : // return hasRemoved;
414 : // }
415 :
416 : // void clear() {
417 : // super.clear();
418 : // subject.add(Change<E>.clear());
419 : // }
420 :
421 : // close() {
422 : // clear();
423 : // _subscriptions.forEach((observable, subscription) {
424 : // subscription.cancel();
425 : // });
426 : // _subscriptions.clear();
427 : // subject.close();
428 : // _changeCtl.close();
429 : // }
430 :
431 : // /// Replaces all existing items of this list with [item]
432 : // void assign(E item) {
433 : // clear();
434 : // add(item);
435 : // }
436 :
437 : // /// Replaces all existing items of this list with [items]
438 : // void assignAll(Iterable<E> items) {
439 : // clear();
440 : // addAll(items);
441 : // }
442 :
443 : // /// A stream of record of changes to this list
444 : // Stream<Change<E>> get onChange {
445 : // final now = DateTime.now();
446 :
447 : // _onChange.skipWhile((m) => m.time.isBefore(now));
448 : // return _changeCtl.stream.asBroadcastStream();
449 : // }
450 :
451 : // Stream<Change<E>> _onChange;
452 :
453 : // addListener(Stream<Change<E>> rxGetx) {
454 : // if (_subscriptions.containsKey(rxGetx)) {
455 : // return;
456 : // }
457 : // _subscriptions[rxGetx] = rxGetx.listen((data) {
458 : // subject.add(data);
459 : // });
460 : // }
461 :
462 : // List<E> get value => v as List<E>;
463 :
464 : // set value(List<E> va) => assignAll(va);
465 :
466 : // @override
467 : // get v {
468 : // if (Get.obs != null) {
469 : // Get.obs.addListener(subject.stream);
470 : // }
471 : // return this;
472 : // }
473 :
474 : // set v(E val) {
475 : // assign(val);
476 : // }
477 :
478 : // @override
479 : // Stream<E> get stream => onChange.map((c) => c.item);
480 :
481 : // @override
482 : // void bind(RxInterface<E> reactive) {
483 : // v = reactive.v;
484 : // reactive.stream.listen((va) => v = va);
485 : // }
486 :
487 : // void bindStream(Stream<E> stream) => stream.listen((va) => v = va);
488 :
489 : // @override
490 : // void bindOrSet(/* T | Stream<T> or Rx<T> */ other) {
491 : // if (other is RxInterface<E>) {
492 : // bind(other);
493 : // } else if (other is Stream<E>) {
494 : // bindStream(other.cast<E>());
495 : // } else {
496 : // v = other;
497 : // }
498 : // }
499 :
500 : // @override
501 : // StreamSubscription<E> listen(ValueCallback<E> callback) =>
502 : // stream.listen(callback);
503 :
504 : // @override
505 : // void setCast(dynamic val) => v = val;
506 : // }
507 :
508 : typedef bool Condition();
509 :
510 : typedef E ChildrenListComposer<S, E>(S value);
511 :
512 : // /// An observable list that is bound to another list [binding]
513 : // class BindingList<S, E> extends ListX<E> {
514 : // final ListX<S> binding;
515 :
516 : // final ChildrenListComposer<S, E> composer;
517 :
518 : // BindingList(this.binding, this.composer) {
519 : // for (S v in binding) _add(composer(v));
520 : // binding.onChange.listen((Change<S> n) {
521 : // if (n.op == ListChangeOp.add) {
522 : // insert(n.pos, composer(n.item));
523 : // } else if (n.op == ListChangeOp.remove) {
524 : // removeAt(n.pos);
525 : // } else if (n.op == ListChangeOp.clear) {
526 : // clear();
527 : // }
528 : // });
529 : // }
530 : // }
531 :
532 : class BoolX<bool> extends _StoredValue<bool> {
533 3 : BoolX([bool initial]) {
534 3 : _value = initial;
535 12 : _onChange = subject.stream.asBroadcastStream();
536 : }
537 : }
538 :
539 : class DoubleX<double> extends _StoredValue<double> {
540 3 : DoubleX([double initial]) {
541 3 : _value = initial;
542 12 : _onChange = subject.stream.asBroadcastStream();
543 : }
544 : }
545 :
546 : class NumX<num> extends _StoredValue<num> {
547 0 : NumX([num initial]) {
548 0 : _value = initial;
549 0 : _onChange = subject.stream.asBroadcastStream();
550 : }
551 : }
552 :
553 : class Rx<T> extends _StoredValue<T> {
554 1 : Rx([T initial]) {
555 1 : _value = initial;
556 4 : _onChange = subject.stream.asBroadcastStream();
557 : }
558 : }
559 :
560 : extension StringExtension on String {
561 3 : StringX<String> get obs {
562 : if (this != null)
563 3 : return StringX(this);
564 : else
565 0 : return StringX(null);
566 : }
567 : }
568 :
569 : extension IntExtension on int {
570 4 : IntX<int> get obs {
571 : if (this != null)
572 4 : return IntX(this);
573 : else
574 0 : return IntX(null);
575 : }
576 : }
577 :
578 : extension DoubleExtension on double {
579 3 : DoubleX<double> get obs {
580 : if (this != null)
581 3 : return DoubleX(this);
582 : else
583 0 : return DoubleX(null);
584 : }
585 : }
586 :
587 : extension MapExtension on Map {
588 3 : MapX<Map> get obs {
589 : if (this != null)
590 3 : return MapX(this);
591 : else
592 0 : return MapX(null);
593 : }
594 : }
595 :
596 : extension ListExtension<E> on List<E> {
597 3 : ListX<E> get obs {
598 : if (this != null)
599 9 : return ListX<E>([])..addAllNonNull(this);
600 : else
601 0 : return ListX<E>(null);
602 : }
603 : }
604 :
605 : extension BoolExtension on bool {
606 3 : BoolX<bool> get obs {
607 : if (this != null)
608 3 : return BoolX(this);
609 : else
610 0 : return BoolX(null);
611 : }
612 : }
613 :
614 : extension ObjectExtension on Object {
615 0 : Rx<Object> get obs {
616 : if (this != null)
617 0 : return Rx(this);
618 : else
619 0 : return Rx(null);
620 : }
621 : }
|