Rafael Ruiz Muñoz

Add a Reactive "Rx-type" holder that triggers the listeners when it receives the same value

@@ -379,6 +379,30 @@ class Rx<T> extends _RxImpl<T> { @@ -379,6 +379,30 @@ class Rx<T> extends _RxImpl<T> {
379 } 379 }
380 } 380 }
381 381
  382 +/// Similar class to Rx<T> but this also will refresh the listeners if the same
  383 +/// value has been provided. This is useful when maintaining a state with the
  384 +/// same user = User("foo").
  385 +/// For example, supposed we have a `int seconds = 2` and we want to animate
  386 +/// from invisible to visible a widget in two seconds:
  387 +/// RxEvent<int>.call(seconds);
  388 +/// then after a click happens, you want to call a RxEvent<int>.call(seconds).
  389 +/// This will refresh the listener of an AnimatedWidget and will keep the value
  390 +/// if the Rx is kept in memory.
  391 +///
  392 +class RxEvent<T> extends Rx<T> {
  393 + RxEvent([T initial]) : super(initial);
  394 +
  395 + void trigger([T v]) {
  396 + var firstRebuild = this.firstRebuild;
  397 + value = v;
  398 + // If it's not the first rebuild, the listeners have been called already
  399 + // So we won't call them again.
  400 + if (!firstRebuild) {
  401 + subject.add(v);
  402 + }
  403 + }
  404 +}
  405 +
382 extension StringExtension on String { 406 extension StringExtension on String {
383 /// Returns a `RxString` with [this] `String` as initial value. 407 /// Returns a `RxString` with [this] `String` as initial value.
384 RxString get obs => RxString(this); 408 RxString get obs => RxString(this);
@@ -95,4 +95,55 @@ void main() { @@ -95,4 +95,55 @@ 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', () 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('RxEvent same value will trigger the listener when trigger', () async {
  117 + var reactiveInteger = RxEvent<int>(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 + });
  132 +
  133 + test('RxEvent same value will not trigger the listener when call', () async {
  134 + var reactiveInteger = RxEvent<int>(2);
  135 + var timesCalled = 0;
  136 + reactiveInteger.listen((newInt) {
  137 + timesCalled++;
  138 + });
  139 +
  140 + // we call 3
  141 + reactiveInteger.call(3);
  142 + // then repeat twice
  143 + reactiveInteger.call(3);
  144 + reactiveInteger.call(3);
  145 +
  146 + await Future.delayed(Duration(milliseconds: 100));
  147 + expect(1, timesCalled);
  148 + });
98 } 149 }