Jonny Borges
Committed by GitHub

Merge pull request #1134 from RafaRuiz/master

Create an Event Rx holder to call listeners when the same value is passed
@@ -199,6 +199,41 @@ abstract class _RxImpl<T> extends RxNotifier<T> with RxObjectMixin<T> { @@ -199,6 +199,41 @@ abstract class _RxImpl<T> extends RxNotifier<T> with RxObjectMixin<T> {
199 fn(_value); 199 fn(_value);
200 subject.add(_value); 200 subject.add(_value);
201 } 201 }
  202 +
  203 + /// Following certain practices on Rx data, we might want to react to certain
  204 + /// listeners when a value has been provided, even if the value is the same.
  205 + /// At the moment, we ignore part of the process if we `.call(value)` with
  206 + /// the same value since it holds the value and there's no real
  207 + /// need triggering the entire process for the same value inside, but
  208 + /// there are other situations where we might be interested in
  209 + /// triggering this.
  210 + ///
  211 + /// For example, supposed we have a `int seconds = 2` and we want to animate
  212 + /// from invisible to visible a widget in two seconds:
  213 + /// RxEvent<int>.call(seconds);
  214 + /// then after a click happens, you want to call a RxEvent<int>.call(seconds).
  215 + /// By doing `call(seconds)`, if the value being held is the same,
  216 + /// the listeners won't trigger, hence we need this new `trigger` function.
  217 + /// This will refresh the listener of an AnimatedWidget and will keep
  218 + /// the value if the Rx is kept in memory.
  219 + /// Sample:
  220 + /// ```
  221 + /// Rx<Int> secondsRx = RxInt();
  222 + /// secondsRx.listen((value) => print("$value seconds set"));
  223 + ///
  224 + /// secondsRx.call(2); // This won't trigger any listener, since the value is the same
  225 + /// secondsRx.trigger(2); // This will trigger the listener independently from the value.
  226 + /// ```
  227 + ///
  228 + void trigger([T v]) {
  229 + var firstRebuild = this.firstRebuild;
  230 + value = v;
  231 + // If it's not the first rebuild, the listeners have been called already
  232 + // So we won't call them again.
  233 + if (!firstRebuild) {
  234 + subject.add(v);
  235 + }
  236 + }
202 } 237 }
203 238
204 /// Rx class for `bool` Type. 239 /// Rx class for `bool` Type.
@@ -95,4 +95,38 @@ void main() { @@ -95,4 +95,38 @@ void main() {
95 await Future.delayed(Duration.zero); 95 await Future.delayed(Duration.zero);
96 expect(count, 555); 96 expect(count, 555);
97 }); 97 });
  98 +
  99 + test('Rx same value will not call the same listener when `call`', () async {
  100 + var reactiveInteger = RxInt(2);
  101 + var timesCalled = 0;
  102 + reactiveInteger.listen((newInt) {
  103 + timesCalled++;
  104 + });
  105 +
  106 + // we call 3
  107 + reactiveInteger.call(3);
  108 + // then repeat twice
  109 + reactiveInteger.call(3);
  110 + reactiveInteger.call(3);
  111 +
  112 + await Future.delayed(Duration(milliseconds: 100));
  113 + expect(1, timesCalled);
  114 + });
  115 +
  116 + test('Rx same value will call the listener when `trigger`', () async {
  117 + var reactiveInteger = RxInt(2);
  118 + var timesCalled = 0;
  119 + reactiveInteger.listen((newInt) {
  120 + timesCalled++;
  121 + });
  122 +
  123 + // we call 3
  124 + reactiveInteger.trigger(3);
  125 + // then repeat twice
  126 + reactiveInteger.trigger(3);
  127 + reactiveInteger.trigger(3);
  128 +
  129 + await Future.delayed(Duration(milliseconds: 100));
  130 + expect(3, timesCalled);
  131 + });
98 } 132 }