Jonny Borges

change stream api to notifier

@@ -28,7 +28,7 @@ class Home extends ObxStatelessWidget { @@ -28,7 +28,7 @@ class Home extends ObxStatelessWidget {
28 child: Column( 28 child: Column(
29 mainAxisAlignment: MainAxisAlignment.center, 29 mainAxisAlignment: MainAxisAlignment.center,
30 children: [ 30 children: [
31 - SimpleBuilder(builder: (context) { 31 + Observer(builder: (context) {
32 print('builder'); 32 print('builder');
33 return Text( 33 return Text(
34 '${controller.count.value}', 34 '${controller.count.value}',
1 -part of rx_stream;  
2 -  
3 -/// [GetStream] is the lightest and most performative way of working  
4 -/// with events at Dart. You sintaxe is like StreamController, but it works  
5 -/// with simple callbacks. In this way, every event calls only one function.  
6 -/// There is no buffering, to very low memory consumption.  
7 -/// event [add] will add a object to stream. [addError] will add a error  
8 -/// to stream. [listen] is a very light StreamSubscription interface.  
9 -/// Is possible take the last value with [value] property.  
10 -class GetStream<T> {  
11 - void Function()? onListen;  
12 - void Function()? onPause;  
13 - void Function()? onResume;  
14 - FutureOr<void> Function()? onCancel;  
15 -  
16 - GetStream({this.onListen, this.onPause, this.onResume, this.onCancel});  
17 -  
18 - factory GetStream.fromValue(T value,  
19 - {Function()? onListen,  
20 - Function()? onPause,  
21 - Function()? onResume,  
22 - FutureOr<void> Function()? onCancel}) {  
23 - final valuedStream = GetStream<T>(  
24 - onListen: onListen,  
25 - onPause: onPause,  
26 - onResume: onResume,  
27 - onCancel: onCancel)  
28 - .._value = value;  
29 -  
30 - return valuedStream;  
31 - }  
32 -  
33 - List<LightSubscription<T>>? _onData = <LightSubscription<T>>[];  
34 -  
35 - bool? _isBusy = false;  
36 -  
37 - FutureOr<bool?> removeSubscription(LightSubscription<T> subs) async {  
38 - if (!_isBusy!) {  
39 - return _onData!.remove(subs);  
40 - } else {  
41 - await Future.delayed(Duration.zero);  
42 - return _onData?.remove(subs);  
43 - }  
44 - }  
45 -  
46 - FutureOr<void> addSubscription(LightSubscription<T> subs) async {  
47 - if (!_isBusy!) {  
48 - return _onData!.add(subs);  
49 - } else {  
50 - await Future.delayed(Duration.zero);  
51 - return _onData!.add(subs);  
52 - }  
53 - }  
54 -  
55 - int? get length => _onData?.length;  
56 -  
57 - bool get hasListeners => _onData!.isNotEmpty;  
58 -  
59 - void _notifyData(T data) {  
60 - _isBusy = true;  
61 - for (final item in _onData!) {  
62 - if (!item.isPaused) {  
63 - item._data?.call(data);  
64 - }  
65 - }  
66 - _isBusy = false;  
67 - }  
68 -  
69 - void _notifyError(Object error, [StackTrace? stackTrace]) {  
70 - assert(!isClosed, 'You cannot add errors to a closed stream.');  
71 - _isBusy = true;  
72 - var itemsToRemove = <LightSubscription<T>>[];  
73 - for (final item in _onData!) {  
74 - if (!item.isPaused) {  
75 - if (stackTrace != null) {  
76 - item._onError?.call(error, stackTrace);  
77 - } else {  
78 - item._onError?.call(error);  
79 - }  
80 -  
81 - if (item.cancelOnError ?? false) {  
82 - //item.cancel?.call();  
83 - itemsToRemove.add(item);  
84 - item.pause();  
85 - item._onDone?.call();  
86 - }  
87 - }  
88 - }  
89 - for (final item in itemsToRemove) {  
90 - _onData!.remove(item);  
91 - }  
92 - _isBusy = false;  
93 - }  
94 -  
95 - void _notifyDone() {  
96 - assert(!isClosed, 'You cannot close a closed stream.');  
97 - _isBusy = true;  
98 - for (final item in _onData!) {  
99 - if (!item.isPaused) {  
100 - item._onDone?.call();  
101 - }  
102 - }  
103 - _isBusy = false;  
104 - }  
105 -  
106 - late T _value;  
107 -  
108 - T get value {  
109 - // RxInterface.proxy?.addListener(this);  
110 - return _value;  
111 - }  
112 -  
113 - void add(T event) {  
114 - assert(!isClosed, 'You cannot add event to closed Stream');  
115 - _value = event;  
116 - _notifyData(event);  
117 - }  
118 -  
119 - bool get isClosed => _onData == null;  
120 -  
121 - void addError(Object error, [StackTrace? stackTrace]) {  
122 - assert(!isClosed, 'You cannot add error to closed Stream');  
123 - _notifyError(error, stackTrace);  
124 - }  
125 -  
126 - void close() {  
127 - assert(!isClosed, 'You cannot close a closed Stream');  
128 - _notifyDone();  
129 - _onData = null;  
130 - _isBusy = null;  
131 - // _value = null;  
132 - }  
133 -  
134 - LightSubscription<T> listen(void Function(T event) onData,  
135 - {Function? onError, void Function()? onDone, bool? cancelOnError}) {  
136 - final subs = LightSubscription<T>(  
137 - removeSubscription,  
138 - onPause: onPause,  
139 - onResume: onResume,  
140 - onCancel: onCancel,  
141 - )  
142 - ..onData(onData)  
143 - ..onError(onError)  
144 - ..onDone(onDone)  
145 - ..cancelOnError = cancelOnError;  
146 - addSubscription(subs);  
147 - onListen?.call();  
148 - return subs;  
149 - }  
150 -  
151 - Stream<T> get stream =>  
152 - GetStreamTransformation(addSubscription, removeSubscription);  
153 -}  
154 -  
155 -class LightSubscription<T> extends StreamSubscription<T> {  
156 - final RemoveSubscription<T> _removeSubscription;  
157 - LightSubscription(this._removeSubscription,  
158 - {this.onPause, this.onResume, this.onCancel});  
159 - final void Function()? onPause;  
160 - final void Function()? onResume;  
161 - final FutureOr<void> Function()? onCancel;  
162 -  
163 - bool? cancelOnError = false;  
164 -  
165 - @override  
166 - Future<void> cancel() {  
167 - _removeSubscription(this);  
168 - onCancel?.call();  
169 - return Future.value();  
170 - }  
171 -  
172 - OnData<T>? _data;  
173 -  
174 - Function? _onError;  
175 -  
176 - Callback? _onDone;  
177 -  
178 - bool _isPaused = false;  
179 -  
180 - @override  
181 - void onData(OnData<T>? handleData) => _data = handleData;  
182 -  
183 - @override  
184 - void onError(Function? handleError) => _onError = handleError;  
185 -  
186 - @override  
187 - void onDone(Callback? handleDone) => _onDone = handleDone;  
188 -  
189 - @override  
190 - void pause([Future<void>? resumeSignal]) {  
191 - _isPaused = true;  
192 - onPause?.call();  
193 - }  
194 -  
195 - @override  
196 - void resume() {  
197 - _isPaused = false;  
198 - onResume?.call();  
199 - }  
200 -  
201 - @override  
202 - bool get isPaused => _isPaused;  
203 -  
204 - @override  
205 - Future<E> asFuture<E>([E? futureValue]) => Future.value(futureValue);  
206 -}  
207 -  
208 -class GetStreamTransformation<T> extends Stream<T> {  
209 - final AddSubscription<T> _addSubscription;  
210 - final RemoveSubscription<T> _removeSubscription;  
211 - GetStreamTransformation(this._addSubscription, this._removeSubscription);  
212 -  
213 - @override  
214 - LightSubscription<T> listen(void Function(T event)? onData,  
215 - {Function? onError, void Function()? onDone, bool? cancelOnError}) {  
216 - final subs = LightSubscription<T>(_removeSubscription)  
217 - ..onData(onData)  
218 - ..onError(onError)  
219 - ..onDone(onDone);  
220 - _addSubscription(subs);  
221 - return subs;  
222 - }  
223 -}  
224 -  
225 -typedef RemoveSubscription<T> = FutureOr<bool?> Function(  
226 - LightSubscription<T> subs);  
227 -  
228 -typedef AddSubscription<T> = FutureOr<void> Function(LightSubscription<T> subs); 1 +// part of rx_stream;
  2 +
  3 +// /// [GetStream] is the lightest and most performative way of working
  4 +// /// with events at Dart. You sintaxe is like StreamController, but it works
  5 +// /// with simple callbacks. In this way, every event calls only one function.
  6 +// /// There is no buffering, to very low memory consumption.
  7 +// /// event [add] will add a object to stream. [addError] will add a error
  8 +// /// to stream. [listen] is a very light StreamSubscription interface.
  9 +// /// Is possible take the last value with [value] property.
  10 +// class GetStream<T> {
  11 +// void Function()? onListen;
  12 +// void Function()? onPause;
  13 +// void Function()? onResume;
  14 +// FutureOr<void> Function()? onCancel;
  15 +
  16 +// GetStream({this.onListen, this.onPause, this.onResume, this.onCancel});
  17 +
  18 +// factory GetStream.fromValue(T value,
  19 +// {Function()? onListen,
  20 +// Function()? onPause,
  21 +// Function()? onResume,
  22 +// FutureOr<void> Function()? onCancel}) {
  23 +// final valuedStream = GetStream<T>(
  24 +// onListen: onListen,
  25 +// onPause: onPause,
  26 +// onResume: onResume,
  27 +// onCancel: onCancel)
  28 +// .._value = value;
  29 +
  30 +// return valuedStream;
  31 +// }
  32 +
  33 +// List<LightSubscription<T>>? _onData = <LightSubscription<T>>[];
  34 +
  35 +// bool? _isBusy = false;
  36 +
  37 +// FutureOr<bool?> removeSubscription(LightSubscription<T> subs) async {
  38 +// if (!_isBusy!) {
  39 +// return _onData!.remove(subs);
  40 +// } else {
  41 +// await Future.delayed(Duration.zero);
  42 +// return _onData?.remove(subs);
  43 +// }
  44 +// }
  45 +
  46 +// FutureOr<void> addSubscription(LightSubscription<T> subs) async {
  47 +// if (!_isBusy!) {
  48 +// return _onData!.add(subs);
  49 +// } else {
  50 +// await Future.delayed(Duration.zero);
  51 +// return _onData!.add(subs);
  52 +// }
  53 +// }
  54 +
  55 +// int? get length => _onData?.length;
  56 +
  57 +// bool get hasListeners => _onData!.isNotEmpty;
  58 +
  59 +// void _notifyData(T data) {
  60 +// _isBusy = true;
  61 +// for (final item in _onData!) {
  62 +// if (!item.isPaused) {
  63 +// item._data?.call(data);
  64 +// }
  65 +// }
  66 +// _isBusy = false;
  67 +// }
  68 +
  69 +// void _notifyError(Object error, [StackTrace? stackTrace]) {
  70 +// assert(!isClosed, 'You cannot add errors to a closed stream.');
  71 +// _isBusy = true;
  72 +// var itemsToRemove = <LightSubscription<T>>[];
  73 +// for (final item in _onData!) {
  74 +// if (!item.isPaused) {
  75 +// if (stackTrace != null) {
  76 +// item._onError?.call(error, stackTrace);
  77 +// } else {
  78 +// item._onError?.call(error);
  79 +// }
  80 +
  81 +// if (item.cancelOnError ?? false) {
  82 +// //item.cancel?.call();
  83 +// itemsToRemove.add(item);
  84 +// item.pause();
  85 +// item._onDone?.call();
  86 +// }
  87 +// }
  88 +// }
  89 +// for (final item in itemsToRemove) {
  90 +// _onData!.remove(item);
  91 +// }
  92 +// _isBusy = false;
  93 +// }
  94 +
  95 +// void _notifyDone() {
  96 +// assert(!isClosed, 'You cannot close a closed stream.');
  97 +// _isBusy = true;
  98 +// for (final item in _onData!) {
  99 +// if (!item.isPaused) {
  100 +// item._onDone?.call();
  101 +// }
  102 +// }
  103 +// _isBusy = false;
  104 +// }
  105 +
  106 +// late T _value;
  107 +
  108 +// T get value {
  109 +// // RxInterface.proxy?.addListener(this);
  110 +// return _value;
  111 +// }
  112 +
  113 +// void add(T event) {
  114 +// assert(!isClosed, 'You cannot add event to closed Stream');
  115 +// _value = event;
  116 +// _notifyData(event);
  117 +// }
  118 +
  119 +// bool get isClosed => _onData == null;
  120 +
  121 +// void addError(Object error, [StackTrace? stackTrace]) {
  122 +// assert(!isClosed, 'You cannot add error to closed Stream');
  123 +// _notifyError(error, stackTrace);
  124 +// }
  125 +
  126 +// void close() {
  127 +// assert(!isClosed, 'You cannot close a closed Stream');
  128 +// _notifyDone();
  129 +// _onData = null;
  130 +// _isBusy = null;
  131 +// // _value = null;
  132 +// }
  133 +
  134 +// LightSubscription<T> listen(void Function(T event) onData,
  135 +// {Function? onError, void Function()? onDone, bool? cancelOnError}) {
  136 +// final subs = LightSubscription<T>(
  137 +// removeSubscription,
  138 +// onPause: onPause,
  139 +// onResume: onResume,
  140 +// onCancel: onCancel,
  141 +// )
  142 +// ..onData(onData)
  143 +// ..onError(onError)
  144 +// ..onDone(onDone)
  145 +// ..cancelOnError = cancelOnError;
  146 +// addSubscription(subs);
  147 +// onListen?.call();
  148 +// return subs;
  149 +// }
  150 +
  151 +// Stream<T> get stream =>
  152 +// GetStreamTransformation(addSubscription, removeSubscription);
  153 +// }
  154 +
  155 +// class LightSubscription<T> extends StreamSubscription<T> {
  156 +// final RemoveSubscription<T> _removeSubscription;
  157 +// LightSubscription(this._removeSubscription,
  158 +// {this.onPause, this.onResume, this.onCancel});
  159 +// final void Function()? onPause;
  160 +// final void Function()? onResume;
  161 +// final FutureOr<void> Function()? onCancel;
  162 +
  163 +// bool? cancelOnError = false;
  164 +
  165 +// @override
  166 +// Future<void> cancel() {
  167 +// _removeSubscription(this);
  168 +// onCancel?.call();
  169 +// return Future.value();
  170 +// }
  171 +
  172 +// OnData<T>? _data;
  173 +
  174 +// Function? _onError;
  175 +
  176 +// Callback? _onDone;
  177 +
  178 +// bool _isPaused = false;
  179 +
  180 +// @override
  181 +// void onData(OnData<T>? handleData) => _data = handleData;
  182 +
  183 +// @override
  184 +// void onError(Function? handleError) => _onError = handleError;
  185 +
  186 +// @override
  187 +// void onDone(Callback? handleDone) => _onDone = handleDone;
  188 +
  189 +// @override
  190 +// void pause([Future<void>? resumeSignal]) {
  191 +// _isPaused = true;
  192 +// onPause?.call();
  193 +// }
  194 +
  195 +// @override
  196 +// void resume() {
  197 +// _isPaused = false;
  198 +// onResume?.call();
  199 +// }
  200 +
  201 +// @override
  202 +// bool get isPaused => _isPaused;
  203 +
  204 +// @override
  205 +// Future<E> asFuture<E>([E? futureValue]) => Future.value(futureValue);
  206 +// }
  207 +
  208 +// class GetStreamTransformation<T> extends Stream<T> {
  209 +// final AddSubscription<T> _addSubscription;
  210 +// final RemoveSubscription<T> _removeSubscription;
  211 +// GetStreamTransformation(this._addSubscription, this._removeSubscription);
  212 +
  213 +// @override
  214 +// LightSubscription<T> listen(void Function(T event)? onData,
  215 +// {Function? onError, void Function()? onDone, bool? cancelOnError}) {
  216 +// final subs = LightSubscription<T>(_removeSubscription)
  217 +// ..onData(onData)
  218 +// ..onError(onError)
  219 +// ..onDone(onDone);
  220 +// _addSubscription(subs);
  221 +// return subs;
  222 +// }
  223 +// }
  224 +
  225 +// typedef RemoveSubscription<T> = FutureOr<bool?> Function(
  226 +// LightSubscription<T> subs);
  227 +
  228 +// typedef AddSubscription<T> =
  229 +//FutureOr<void> Function(LightSubscription<T> subs);
@@ -3,7 +3,6 @@ library rx_stream; @@ -3,7 +3,6 @@ library rx_stream;
3 import 'dart:async'; 3 import 'dart:async';
4 4
5 import '../rx_typedefs/rx_typedefs.dart'; 5 import '../rx_typedefs/rx_typedefs.dart';
6 -import '../rx_types/rx_types.dart';  
7 6
8 -part 'get_stream.dart'; 7 +//part 'get_stream.dart';
9 part 'mini_stream.dart'; 8 part 'mini_stream.dart';
@@ -4,7 +4,7 @@ part of rx_types; @@ -4,7 +4,7 @@ part of rx_types;
4 /// reactivity 4 /// reactivity
5 /// of those `Widgets` and Rx values. 5 /// of those `Widgets` and Rx values.
6 6
7 -mixin RxObjectMixin<T> on NotifyManager<T> { 7 +mixin RxObjectMixin<T> on GetListenable<T> {
8 //late T _value; 8 //late T _value;
9 9
10 /// Makes a direct update of [value] adding it to the Stream 10 /// Makes a direct update of [value] adding it to the Stream
@@ -25,9 +25,9 @@ mixin RxObjectMixin<T> on NotifyManager<T> { @@ -25,9 +25,9 @@ mixin RxObjectMixin<T> on NotifyManager<T> {
25 /// person.refresh(); 25 /// person.refresh();
26 /// print( person ); 26 /// print( person );
27 /// ``` 27 /// ```
28 - void refresh() {  
29 - subject.add(value);  
30 - } 28 + // void refresh() {
  29 + // subject.add(value);
  30 + // }
31 31
32 /// updates the value to `null` and adds it to the Stream. 32 /// updates the value to `null` and adds it to the Stream.
33 /// Even with null-safety coming, is still an important feature to support, as 33 /// Even with null-safety coming, is still an important feature to support, as
@@ -59,6 +59,7 @@ mixin RxObjectMixin<T> on NotifyManager<T> { @@ -59,6 +59,7 @@ mixin RxObjectMixin<T> on NotifyManager<T> {
59 /// onChanged: myText, 59 /// onChanged: myText,
60 /// ), 60 /// ),
61 ///``` 61 ///```
  62 + @override
62 T call([T? v]) { 63 T call([T? v]) {
63 if (v != null) { 64 if (v != null) {
64 value = v; 65 value = v;
@@ -95,25 +96,18 @@ mixin RxObjectMixin<T> on NotifyManager<T> { @@ -95,25 +96,18 @@ mixin RxObjectMixin<T> on NotifyManager<T> {
95 96
96 /// Updates the [value] and adds it to the stream, updating the observer 97 /// Updates the [value] and adds it to the stream, updating the observer
97 /// Widget, only if it's different from the previous value. 98 /// Widget, only if it's different from the previous value.
  99 + @override
98 set value(T val) { 100 set value(T val) {
99 - if (subject.isClosed) return; 101 + if (isDisposed) return;
100 sentToStream = false; 102 sentToStream = false;
101 if (value == val && !firstRebuild) return; 103 if (value == val && !firstRebuild) return;
102 firstRebuild = false; 104 firstRebuild = false;
103 // _value = val; 105 // _value = val;
104 sentToStream = true; 106 sentToStream = true;
105 - subject.add(val); 107 + //TODO: Check this
  108 + super.value = val;
106 } 109 }
107 110
108 - /// Returns the current [value]  
109 - T get value {  
110 - return subject.value;  
111 - //RxInterface.proxy?.addListener(subject);  
112 - // return _value;  
113 - }  
114 -  
115 - Stream<T> get stream => subject.stream;  
116 -  
117 /// Returns a [StreamSubscription] similar to [listen], but with the 111 /// Returns a [StreamSubscription] similar to [listen], but with the
118 /// added benefit that it primes the stream with the current [value], rather 112 /// added benefit that it primes the stream with the current [value], rather
119 /// than waiting for the next [value]. This should not be called in [onInit] 113 /// than waiting for the next [value]. This should not be called in [onInit]
@@ -127,6 +121,7 @@ mixin RxObjectMixin<T> on NotifyManager<T> { @@ -127,6 +121,7 @@ mixin RxObjectMixin<T> on NotifyManager<T> {
127 cancelOnError: cancelOnError, 121 cancelOnError: cancelOnError,
128 ); 122 );
129 123
  124 + //TODO: Change to refresh????
130 subject.add(value); 125 subject.add(value);
131 126
132 return subscription; 127 return subscription;
@@ -137,64 +132,64 @@ mixin RxObjectMixin<T> on NotifyManager<T> { @@ -137,64 +132,64 @@ mixin RxObjectMixin<T> on NotifyManager<T> {
137 /// Closing the subscription will happen automatically when the observer 132 /// Closing the subscription will happen automatically when the observer
138 /// Widget (`GetX` or `Obx`) gets unmounted from the Widget tree. 133 /// Widget (`GetX` or `Obx`) gets unmounted from the Widget tree.
139 void bindStream(Stream<T> stream) { 134 void bindStream(Stream<T> stream) {
140 - final listSubscriptions =  
141 - _subscriptions[subject] ??= <StreamSubscription>[];  
142 - listSubscriptions.add(stream.listen((va) => value = va));  
143 - }  
144 -}  
145 -  
146 -class RxNotifier<T> = RxInterface<T> with NotifyManager<T>;  
147 -  
148 -mixin NotifyManager<T> {  
149 - GetStream<T> subject = GetStream<T>();  
150 - final _subscriptions = <GetStream, List<StreamSubscription>>{}; 135 + // final listSubscriptions =
  136 + // _subscriptions[subject] ??= <StreamSubscription>[];
151 137
152 - bool get canUpdate => _subscriptions.isNotEmpty;  
153 -  
154 - /// This is an internal method.  
155 - /// Subscribe to changes on the inner stream.  
156 - void addListener(GetStream<T> rxGetx) {  
157 - if (!_subscriptions.containsKey(rxGetx)) {  
158 - final subs = rxGetx.listen((data) {  
159 - if (!subject.isClosed) subject.add(data);  
160 - });  
161 - final listSubscriptions =  
162 - _subscriptions[rxGetx] ??= <StreamSubscription>[];  
163 - listSubscriptions.add(subs);  
164 - }  
165 - }  
166 -  
167 - StreamSubscription<T> listen(  
168 - void Function(T) onData, {  
169 - Function? onError,  
170 - void Function()? onDone,  
171 - bool? cancelOnError,  
172 - }) =>  
173 - subject.listen(  
174 - onData,  
175 - onError: onError,  
176 - onDone: onDone,  
177 - cancelOnError: cancelOnError ?? false,  
178 - );  
179 -  
180 - /// Closes the subscriptions for this Rx, releasing the resources.  
181 - void close() {  
182 - _subscriptions.forEach((getStream, _subscriptions) {  
183 - for (final subscription in _subscriptions) {  
184 - subscription.cancel();  
185 - }  
186 - });  
187 -  
188 - _subscriptions.clear();  
189 - subject.close(); 138 + final sub = stream.listen((va) => value = va);
  139 + reportAdd(sub.cancel);
190 } 140 }
191 } 141 }
192 142
  143 +//class RxNotifier<T> = RxInterface<T> with NotifyManager<T>;
  144 +
  145 +// mixin NotifyManager<T> {
  146 +// GetStream<T> subject = GetStream<T>();
  147 +// final _subscriptions = <GetStream, List<StreamSubscription>>{};
  148 +
  149 +// bool get canUpdate => _subscriptions.isNotEmpty;
  150 +
  151 +// /// This is an internal method.
  152 +// /// Subscribe to changes on the inner stream.
  153 +// void addListener(GetStream<T> rxGetx) {
  154 +// if (!_subscriptions.containsKey(rxGetx)) {
  155 +// final subs = rxGetx.listen((data) {
  156 +// if (!subject.isClosed) subject.add(data);
  157 +// });
  158 +// final listSubscriptions =
  159 +// _subscriptions[rxGetx] ??= <StreamSubscription>[];
  160 +// listSubscriptions.add(subs);
  161 +// }
  162 +// }
  163 +
  164 +// StreamSubscription<T> listen(
  165 +// void Function(T) onData, {
  166 +// Function? onError,
  167 +// void Function()? onDone,
  168 +// bool? cancelOnError,
  169 +// }) =>
  170 +// subject.listen(
  171 +// onData,
  172 +// onError: onError,
  173 +// onDone: onDone,
  174 +// cancelOnError: cancelOnError ?? false,
  175 +// );
  176 +
  177 +// /// Closes the subscriptions for this Rx, releasing the resources.
  178 +// void close() {
  179 +// _subscriptions.forEach((getStream, _subscriptions) {
  180 +// for (final subscription in _subscriptions) {
  181 +// subscription.cancel();
  182 +// }
  183 +// });
  184 +
  185 +// _subscriptions.clear();
  186 +// subject.close();
  187 +// }
  188 +// }
  189 +
193 /// Base Rx class that manages all the stream logic for any Type. 190 /// Base Rx class that manages all the stream logic for any Type.
194 -abstract class _RxImpl<T> extends RxNotifier<T> with RxObjectMixin<T> {  
195 - _RxImpl(T initial) {  
196 - subject = GetStream.fromValue(initial);  
197 - } 191 +abstract class _RxImpl<T> extends GetListenable<T> with RxObjectMixin<T> {
  192 + _RxImpl(T initial) : super(initial);
198 193
199 void addError(Object error, [StackTrace? stackTrace]) { 194 void addError(Object error, [StackTrace? stackTrace]) {
200 subject.addError(error, stackTrace); 195 subject.addError(error, stackTrace);
@@ -5,12 +5,10 @@ part of rx_types; @@ -5,12 +5,10 @@ part of rx_types;
5 /// This interface is the contract that _RxImpl]<T> uses in all it's 5 /// This interface is the contract that _RxImpl]<T> uses in all it's
6 /// subclass. 6 /// subclass.
7 abstract class RxInterface<T> { 7 abstract class RxInterface<T> {
8 - static RxInterface? proxy;  
9 -  
10 - bool get canUpdate; 8 + //bool get canUpdate;
11 9
12 /// Adds a listener to stream 10 /// Adds a listener to stream
13 - void addListener(GetStream<T> rxGetx); 11 + void addListener(VoidCallback listener);
14 12
15 /// Close the Rx Variable 13 /// Close the Rx Variable
16 void close(); 14 void close();
@@ -20,13 +18,24 @@ abstract class RxInterface<T> { @@ -20,13 +18,24 @@ abstract class RxInterface<T> {
20 {Function? onError, void Function()? onDone, bool? cancelOnError}); 18 {Function? onError, void Function()? onDone, bool? cancelOnError});
21 19
22 /// Avoids an unsafe usage of the `proxy` 20 /// Avoids an unsafe usage of the `proxy`
23 - static T notifyChildren<T>(RxNotifier observer, ValueGetter<T> builder) {  
24 - final _observer = RxInterface.proxy;  
25 - RxInterface.proxy = observer;  
26 - final result = builder();  
27 - if (!observer.canUpdate) {  
28 - RxInterface.proxy = _observer;  
29 - throw """ 21 + // static T notifyChildren<T>(RxNotifier observer, ValueGetter<T> builder) {
  22 + // final _observer = RxInterface.proxy;
  23 + // RxInterface.proxy = observer;
  24 + // final result = builder();
  25 + // if (!observer.canUpdate) {
  26 + // RxInterface.proxy = _observer;
  27 + // throw ObxError();
  28 + // }
  29 + // RxInterface.proxy = _observer;
  30 + // return result;
  31 + // }
  32 +}
  33 +
  34 +class ObxError {
  35 + const ObxError();
  36 + @override
  37 + String toString() {
  38 + return """
30 [Get] the improper use of a GetX has been detected. 39 [Get] the improper use of a GetX has been detected.
31 You should only use GetX or Obx for the specific widget that will be updated. 40 You should only use GetX or Obx for the specific widget that will be updated.
32 If you are seeing this error, you probably did not insert any observable variables into GetX/Obx 41 If you are seeing this error, you probably did not insert any observable variables into GetX/Obx
@@ -34,8 +43,5 @@ abstract class RxInterface<T> { @@ -34,8 +43,5 @@ abstract class RxInterface<T> {
34 (example: GetX => HeavyWidget => variableObservable). 43 (example: GetX => HeavyWidget => variableObservable).
35 If you need to update a parent widget and a child widget, wrap each one in an Obx/GetX. 44 If you need to update a parent widget and a child widget, wrap each one in an Obx/GetX.
36 """; 45 """;
37 - }  
38 - RxInterface.proxy = _observer;  
39 - return result;  
40 } 46 }
41 } 47 }
1 part of rx_types; 1 part of rx_types;
2 2
3 /// Create a list similar to `List<T>` 3 /// Create a list similar to `List<T>`
4 -class RxList<E> extends ListMixin<E>  
5 - with NotifyManager<List<E>>, RxObjectMixin<List<E>>  
6 - implements RxInterface<List<E>> {  
7 - RxList([List<E> initial = const []]) {  
8 - subject = GetStream.fromValue(List.from(initial));  
9 - } 4 +class RxList<E> extends GetListenable<List<E>>
  5 + with ListMixin<E>, RxObjectMixin<List<E>> {
  6 + RxList([List<E> initial = const []]) : super(initial);
10 7
11 factory RxList.filled(int length, E fill, {bool growable = false}) { 8 factory RxList.filled(int length, E fill, {bool growable = false}) {
12 return RxList(List.filled(length, fill, growable: growable)); 9 return RxList(List.filled(length, fill, growable: growable));
@@ -87,12 +84,12 @@ class RxList<E> extends ListMixin<E> @@ -87,12 +84,12 @@ class RxList<E> extends ListMixin<E>
87 @override 84 @override
88 int get length => value.length; 85 int get length => value.length;
89 86
90 - @override  
91 - @protected  
92 - List<E> get value {  
93 - RxInterface.proxy?.addListener(subject);  
94 - return subject.value;  
95 - } 87 + // @override
  88 + // @protected
  89 + // List<E> get value {
  90 + // RxInterface.proxy?.addListener(subject);
  91 + // return subject.value;
  92 + // }
96 93
97 @override 94 @override
98 set length(int newLength) { 95 set length(int newLength) {
1 part of rx_types; 1 part of rx_types;
2 2
3 -class RxMap<K, V> extends MapMixin<K, V>  
4 - with NotifyManager<Map<K, V>>, RxObjectMixin<Map<K, V>>  
5 - implements RxInterface<Map<K, V>> {  
6 - RxMap([Map<K, V> initial = const {}]) {  
7 - subject = GetStream.fromValue(Map.from(initial));  
8 - } 3 +class RxMap<K, V> extends GetListenable<Map<K, V>>
  4 + with MapMixin<K, V>, RxObjectMixin<Map<K, V>> {
  5 + RxMap([Map<K, V> initial = const {}]) : super(initial);
9 6
10 factory RxMap.from(Map<K, V> other) { 7 factory RxMap.from(Map<K, V> other) {
11 return RxMap(Map.from(other)); 8 return RxMap(Map.from(other));
@@ -53,13 +50,13 @@ class RxMap<K, V> extends MapMixin<K, V> @@ -53,13 +50,13 @@ class RxMap<K, V> extends MapMixin<K, V>
53 return val; 50 return val;
54 } 51 }
55 52
56 - @override  
57 - @protected  
58 - Map<K, V> get value {  
59 - return subject.value;  
60 - // RxInterface.proxy?.addListener(subject);  
61 - // return _value;  
62 - } 53 + // @override
  54 + // @protected
  55 + // Map<K, V> get value {
  56 + // return subject.value;
  57 + // // RxInterface.proxy?.addListener(subject);
  58 + // // return _value;
  59 + // }
63 } 60 }
64 61
65 extension MapExtension<K, V> on Map<K, V> { 62 extension MapExtension<K, V> on Map<K, V> {
1 part of rx_types; 1 part of rx_types;
2 2
3 -class RxSet<E> extends SetMixin<E>  
4 - with NotifyManager<Set<E>>, RxObjectMixin<Set<E>>  
5 - implements RxInterface<Set<E>> {  
6 - RxSet([Set<E> initial = const {}]) {  
7 - subject = GetStream.fromValue(Set.from(initial));  
8 - } 3 +class RxSet<E> extends GetListenable<Set<E>>
  4 + with SetMixin<E>, RxObjectMixin<Set<E>> {
  5 + RxSet([Set<E> initial = const {}]) : super(initial);
9 6
10 /// Special override to push() element(s) in a reactive way 7 /// Special override to push() element(s) in a reactive way
11 /// inside the List, 8 /// inside the List,
@@ -20,13 +17,13 @@ class RxSet<E> extends SetMixin<E> @@ -20,13 +17,13 @@ class RxSet<E> extends SetMixin<E>
20 refresh(); 17 refresh();
21 } 18 }
22 19
23 - @override  
24 - @protected  
25 - Set<E> get value {  
26 - return subject.value;  
27 - // RxInterface.proxy?.addListener(subject);  
28 - // return _value;  
29 - } 20 + // @override
  21 + // @protected
  22 + // Set<E> get value {
  23 + // return subject.value;
  24 + // // RxInterface.proxy?.addListener(subject);
  25 + // // return _value;
  26 + // }
30 27
31 @override 28 @override
32 @protected 29 @protected
@@ -4,6 +4,7 @@ import 'dart:async'; @@ -4,6 +4,7 @@ import 'dart:async';
4 import 'dart:collection'; 4 import 'dart:collection';
5 5
6 import 'package:flutter/foundation.dart'; 6 import 'package:flutter/foundation.dart';
  7 +import 'package:get/get_state_manager/src/rx_flutter/rx_notifier.dart';
7 import 'package:get/get_state_manager/src/simple/list_notifier.dart'; 8 import 'package:get/get_state_manager/src/simple/list_notifier.dart';
8 9
9 import '../rx_stream/rx_stream.dart'; 10 import '../rx_stream/rx_stream.dart';
1 import 'dart:async'; 1 import 'dart:async';
2 2
3 import '../../../get_core/get_core.dart'; 3 import '../../../get_core/get_core.dart';
  4 +import '../../../get_state_manager/src/rx_flutter/rx_notifier.dart';
4 import '../rx_types/rx_types.dart'; 5 import '../rx_types/rx_types.dart';
5 import 'utils/debouncer.dart'; 6 import 'utils/debouncer.dart';
6 7
@@ -57,7 +58,7 @@ class Workers { @@ -57,7 +58,7 @@ class Workers {
57 /// } 58 /// }
58 /// ``` 59 /// ```
59 Worker ever<T>( 60 Worker ever<T>(
60 - RxInterface<T> listener, 61 + GetListenable<T> listener,
61 WorkerCallback<T> callback, { 62 WorkerCallback<T> callback, {
62 dynamic condition = true, 63 dynamic condition = true,
63 Function? onError, 64 Function? onError,
@@ -132,7 +133,7 @@ Worker everAll( @@ -132,7 +133,7 @@ Worker everAll(
132 /// } 133 /// }
133 ///``` 134 ///```
134 Worker once<T>( 135 Worker once<T>(
135 - RxInterface<T> listener, 136 + GetListenable<T> listener,
136 WorkerCallback<T> callback, { 137 WorkerCallback<T> callback, {
137 dynamic condition = true, 138 dynamic condition = true,
138 Function? onError, 139 Function? onError,
@@ -175,7 +176,7 @@ Worker once<T>( @@ -175,7 +176,7 @@ Worker once<T>(
175 /// ); 176 /// );
176 /// ``` 177 /// ```
177 Worker interval<T>( 178 Worker interval<T>(
178 - RxInterface<T> listener, 179 + GetListenable<T> listener,
179 WorkerCallback<T> callback, { 180 WorkerCallback<T> callback, {
180 Duration time = const Duration(seconds: 1), 181 Duration time = const Duration(seconds: 1),
181 dynamic condition = true, 182 dynamic condition = true,
@@ -219,7 +220,7 @@ Worker interval<T>( @@ -219,7 +220,7 @@ Worker interval<T>(
219 /// } 220 /// }
220 /// ``` 221 /// ```
221 Worker debounce<T>( 222 Worker debounce<T>(
222 - RxInterface<T> listener, 223 + GetListenable<T> listener,
223 WorkerCallback<T> callback, { 224 WorkerCallback<T> callback, {
224 Duration? time, 225 Duration? time,
225 Function? onError, 226 Function? onError,
1 -import 'dart:async';  
2 -  
3 import 'package:flutter/foundation.dart'; 1 import 'package:flutter/foundation.dart';
4 import 'package:flutter/widgets.dart'; 2 import 'package:flutter/widgets.dart';
5 3
6 import '../../../get_core/get_core.dart'; 4 import '../../../get_core/get_core.dart';
7 import '../../../get_instance/src/get_instance.dart'; 5 import '../../../get_instance/src/get_instance.dart';
8 import '../../../get_instance/src/lifecycle.dart'; 6 import '../../../get_instance/src/lifecycle.dart';
9 -import '../../../get_rx/src/rx_types/rx_types.dart'; 7 +import '../simple/list_notifier.dart';
  8 +import '../simple/simple_builder.dart';
10 9
11 typedef GetXControllerBuilder<T extends GetLifeCycleMixin> = Widget Function( 10 typedef GetXControllerBuilder<T extends GetLifeCycleMixin> = Widget Function(
12 T controller); 11 T controller);
13 12
  13 +class StatefulObserverComponent = StatefulElement with ObserverComponent;
  14 +
14 class GetX<T extends GetLifeCycleMixin> extends StatefulWidget { 15 class GetX<T extends GetLifeCycleMixin> extends StatefulWidget {
15 final GetXControllerBuilder<T> builder; 16 final GetXControllerBuilder<T> builder;
16 final bool global; 17 final bool global;
@@ -39,6 +40,9 @@ class GetX<T extends GetLifeCycleMixin> extends StatefulWidget { @@ -39,6 +40,9 @@ class GetX<T extends GetLifeCycleMixin> extends StatefulWidget {
39 }); 40 });
40 41
41 @override 42 @override
  43 + StatefulElement createElement() => StatefulElement(this);
  44 +
  45 + @override
42 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 46 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
43 super.debugFillProperties(properties); 47 super.debugFillProperties(properties);
44 properties 48 properties
@@ -55,10 +59,8 @@ class GetX<T extends GetLifeCycleMixin> extends StatefulWidget { @@ -55,10 +59,8 @@ class GetX<T extends GetLifeCycleMixin> extends StatefulWidget {
55 } 59 }
56 60
57 class GetXState<T extends GetLifeCycleMixin> extends State<GetX<T>> { 61 class GetXState<T extends GetLifeCycleMixin> extends State<GetX<T>> {
58 - final _observer = RxNotifier();  
59 T? controller; 62 T? controller;
60 bool? _isCreator = false; 63 bool? _isCreator = false;
61 - late StreamSubscription _subs;  
62 64
63 @override 65 @override
64 void initState() { 66 void initState() {
@@ -83,7 +85,7 @@ class GetXState<T extends GetLifeCycleMixin> extends State<GetX<T>> { @@ -83,7 +85,7 @@ class GetXState<T extends GetLifeCycleMixin> extends State<GetX<T>> {
83 if (widget.global && Get.smartManagement == SmartManagement.onlyBuilder) { 85 if (widget.global && Get.smartManagement == SmartManagement.onlyBuilder) {
84 controller?.onStart(); 86 controller?.onStart();
85 } 87 }
86 - _subs = _observer.listen((data) => setState(() {}), cancelOnError: false); 88 +
87 super.initState(); 89 super.initState();
88 } 90 }
89 91
@@ -109,22 +111,29 @@ class GetXState<T extends GetLifeCycleMixin> extends State<GetX<T>> { @@ -109,22 +111,29 @@ class GetXState<T extends GetLifeCycleMixin> extends State<GetX<T>> {
109 GetInstance().delete<T>(tag: widget.tag); 111 GetInstance().delete<T>(tag: widget.tag);
110 } 112 }
111 } 113 }
112 - _subs.cancel();  
113 - _observer.close(); 114 +
  115 + for (final disposer in disposers) {
  116 + disposer();
  117 + }
  118 +
114 controller = null; 119 controller = null;
115 _isCreator = null; 120 _isCreator = null;
116 super.dispose(); 121 super.dispose();
117 } 122 }
118 123
  124 + void _update() {
  125 + setState(() {});
  126 + }
  127 +
  128 + final disposers = <Disposer>[];
  129 +
  130 + @override
  131 + Widget build(BuildContext context) => TaskManager.instance
  132 + .exchange(disposers, _update, () => widget.builder(controller!));
  133 +
119 @override 134 @override
120 void debugFillProperties(DiagnosticPropertiesBuilder properties) { 135 void debugFillProperties(DiagnosticPropertiesBuilder properties) {
121 super.debugFillProperties(properties); 136 super.debugFillProperties(properties);
122 properties.add(DiagnosticsProperty<T>('controller', controller)); 137 properties.add(DiagnosticsProperty<T>('controller', controller));
123 } 138 }
124 -  
125 - @override  
126 - Widget build(BuildContext context) => RxInterface.notifyChildren(  
127 - _observer,  
128 - () => widget.builder(controller!),  
129 - );  
130 } 139 }
  1 +import 'dart:async';
  2 +
1 import 'package:flutter/foundation.dart'; 3 import 'package:flutter/foundation.dart';
2 import 'package:flutter/material.dart'; 4 import 'package:flutter/material.dart';
3 5
@@ -5,10 +7,7 @@ import '../../../instance_manager.dart'; @@ -5,10 +7,7 @@ import '../../../instance_manager.dart';
5 import '../../get_state_manager.dart'; 7 import '../../get_state_manager.dart';
6 import '../simple/list_notifier.dart'; 8 import '../simple/list_notifier.dart';
7 9
8 -mixin StateMixin<T> on ListNotifier {  
9 - late T _value;  
10 - RxStatus? _status;  
11 - 10 +extension _NullOrEmpty on Object {
12 bool _isNullOrEmpty(dynamic val) { 11 bool _isNullOrEmpty(dynamic val) {
13 if (val == null) return true; 12 if (val == null) return true;
14 var result = false; 13 var result = false;
@@ -21,6 +20,11 @@ mixin StateMixin<T> on ListNotifier { @@ -21,6 +20,11 @@ mixin StateMixin<T> on ListNotifier {
21 } 20 }
22 return result; 21 return result;
23 } 22 }
  23 +}
  24 +
  25 +mixin StateMixin<T> on ListNotifier {
  26 + late T _value;
  27 + RxStatus? _status;
24 28
25 void _fillEmptyStatus() { 29 void _fillEmptyStatus() {
26 _status = _isNullOrEmpty(_value) ? RxStatus.loading() : RxStatus.success(); 30 _status = _isNullOrEmpty(_value) ? RxStatus.loading() : RxStatus.success();
@@ -72,6 +76,77 @@ mixin StateMixin<T> on ListNotifier { @@ -72,6 +76,77 @@ mixin StateMixin<T> on ListNotifier {
72 } 76 }
73 } 77 }
74 78
  79 +class GetListenable<T> extends ListNotifierSingle
  80 + implements ValueListenable<T> {
  81 + GetListenable(T val) : _value = val;
  82 +
  83 + StreamController<T>? _controller;
  84 +
  85 + StreamController<T> get subject {
  86 + if (_controller == null) {
  87 + _controller = StreamController<T>.broadcast();
  88 + addListener(_streamListener);
  89 + }
  90 + return _controller!;
  91 + }
  92 +
  93 + void _streamListener() {
  94 + _controller?.add(_value);
  95 + }
  96 +
  97 + @mustCallSuper
  98 + void close() {
  99 + removeListener(_streamListener);
  100 + _controller?.close();
  101 + dispose();
  102 + }
  103 +
  104 + Stream<T> get stream {
  105 + return subject.stream;
  106 + }
  107 +
  108 + T _value;
  109 +
  110 + @override
  111 + T get value {
  112 + reportRead();
  113 + return _value;
  114 + }
  115 +
  116 + void _notify() {
  117 + refresh();
  118 + }
  119 +
  120 + set value(T newValue) {
  121 + if (_value == newValue) return;
  122 + _value = newValue;
  123 + _notify();
  124 + }
  125 +
  126 + T? call([T? v]) {
  127 + if (v != null) {
  128 + value = v;
  129 + }
  130 + return value;
  131 + }
  132 +
  133 + StreamSubscription<T> listen(
  134 + void Function(T)? onData, {
  135 + Function? onError,
  136 + void Function()? onDone,
  137 + bool? cancelOnError,
  138 + }) =>
  139 + stream.listen(
  140 + onData,
  141 + onError: onError,
  142 + onDone: onDone,
  143 + cancelOnError: cancelOnError ?? false,
  144 + );
  145 +
  146 + @override
  147 + String toString() => value.toString();
  148 +}
  149 +
75 class Value<T> extends ListNotifier 150 class Value<T> extends ListNotifier
76 with StateMixin<T> 151 with StateMixin<T>
77 implements ValueListenable<T?> { 152 implements ValueListenable<T?> {
@@ -115,8 +190,6 @@ extension ReactiveT<T> on T { @@ -115,8 +190,6 @@ extension ReactiveT<T> on T {
115 Value<T> get reactive => Value<T>(this); 190 Value<T> get reactive => Value<T>(this);
116 } 191 }
117 192
118 -typedef Condition = bool Function();  
119 -  
120 abstract class GetNotifier<T> extends Value<T> with GetLifeCycleMixin { 193 abstract class GetNotifier<T> extends Value<T> with GetLifeCycleMixin {
121 GetNotifier(T initial) : super(initial); 194 GetNotifier(T initial) : super(initial);
122 } 195 }
@@ -128,7 +201,7 @@ extension StateExt<T> on StateMixin<T> { @@ -128,7 +201,7 @@ extension StateExt<T> on StateMixin<T> {
128 Widget? onLoading, 201 Widget? onLoading,
129 Widget? onEmpty, 202 Widget? onEmpty,
130 }) { 203 }) {
131 - return SimpleBuilder(builder: (_) { 204 + return Observer(builder: (_) {
132 if (status.isLoading) { 205 if (status.isLoading) {
133 return onLoading ?? const Center(child: CircularProgressIndicator()); 206 return onLoading ?? const Center(child: CircularProgressIndicator());
134 } else if (status.isError) { 207 } else if (status.isError) {
1 -import 'dart:async';  
2 -  
3 -import 'package:flutter/foundation.dart';  
4 import 'package:flutter/widgets.dart'; 1 import 'package:flutter/widgets.dart';
5 2
6 import '../../../get_rx/src/rx_types/rx_types.dart'; 3 import '../../../get_rx/src/rx_types/rx_types.dart';
  4 +import '../simple/simple_builder.dart';
7 5
8 typedef WidgetCallback = Widget Function(); 6 typedef WidgetCallback = Widget Function();
9 7
@@ -12,48 +10,8 @@ typedef WidgetCallback = Widget Function(); @@ -12,48 +10,8 @@ typedef WidgetCallback = Widget Function();
12 /// See also: 10 /// See also:
13 /// - [Obx] 11 /// - [Obx]
14 /// - [ObxValue] 12 /// - [ObxValue]
15 -abstract class ObxWidget extends StatefulWidget { 13 +abstract class ObxWidget extends ObxStatelessWidget {
16 const ObxWidget({Key? key}) : super(key: key); 14 const ObxWidget({Key? key}) : super(key: key);
17 -  
18 - @override  
19 - void debugFillProperties(DiagnosticPropertiesBuilder properties) {  
20 - super.debugFillProperties(properties);  
21 - properties..add(ObjectFlagProperty<Function>.has('builder', build));  
22 - }  
23 -  
24 - @override  
25 - _ObxState createState() => _ObxState();  
26 -  
27 - @protected  
28 - Widget build();  
29 -}  
30 -  
31 -class _ObxState extends State<ObxWidget> {  
32 - final _observer = RxNotifier();  
33 - late StreamSubscription subs;  
34 -  
35 - @override  
36 - void initState() {  
37 - super.initState();  
38 - subs = _observer.subject.stream.listen(_updateTree, cancelOnError: false);  
39 - }  
40 -  
41 - void _updateTree(_) {  
42 - if (mounted) {  
43 - setState(() {});  
44 - }  
45 - }  
46 -  
47 - @override  
48 - void dispose() {  
49 - subs.cancel();  
50 - _observer.close();  
51 - super.dispose();  
52 - }  
53 -  
54 - @override  
55 - Widget build(BuildContext context) =>  
56 - RxInterface.notifyChildren(_observer, widget.build);  
57 } 15 }
58 16
59 /// The simplest reactive widget in GetX. 17 /// The simplest reactive widget in GetX.
@@ -69,7 +27,9 @@ class Obx extends ObxWidget { @@ -69,7 +27,9 @@ class Obx extends ObxWidget {
69 const Obx(this.builder); 27 const Obx(this.builder);
70 28
71 @override 29 @override
72 - Widget build() => builder(); 30 + Widget build(BuildContext context) {
  31 + return builder();
  32 + }
73 } 33 }
74 34
75 /// Similar to Obx, but manages a local state. 35 /// Similar to Obx, but manages a local state.
@@ -90,5 +50,5 @@ class ObxValue<T extends RxInterface> extends ObxWidget { @@ -90,5 +50,5 @@ class ObxValue<T extends RxInterface> extends ObxWidget {
90 const ObxValue(this.builder, this.data, {Key? key}) : super(key: key); 50 const ObxValue(this.builder, this.data, {Key? key}) : super(key: key);
91 51
92 @override 52 @override
93 - Widget build() => builder(data); 53 + Widget build(BuildContext context) => builder(data);
94 } 54 }
@@ -47,15 +47,22 @@ mixin ListNotifierSingleMixin on Listenable { @@ -47,15 +47,22 @@ mixin ListNotifierSingleMixin on Listenable {
47 TaskManager.instance.notify(this); 47 TaskManager.instance.notify(this);
48 } 48 }
49 49
  50 + @protected
  51 + void reportAdd(VoidCallback disposer) {
  52 + TaskManager.instance.reportAdd(disposer);
  53 + }
  54 +
50 void _notifyUpdate() { 55 void _notifyUpdate() {
51 for (var element in _updaters!) { 56 for (var element in _updaters!) {
52 element!(); 57 element!();
53 } 58 }
54 } 59 }
55 60
  61 + bool get isDisposed => _updaters == null;
  62 +
56 bool _debugAssertNotDisposed() { 63 bool _debugAssertNotDisposed() {
57 assert(() { 64 assert(() {
58 - if (_updaters == null) { 65 + if (isDisposed) {
59 throw FlutterError('''A $runtimeType was used after being disposed.\n 66 throw FlutterError('''A $runtimeType was used after being disposed.\n
60 'Once you have called dispose() on a $runtimeType, it can no longer be used.'''); 67 'Once you have called dispose() on a $runtimeType, it can no longer be used.''');
61 } 68 }
@@ -151,18 +158,16 @@ class TaskManager { @@ -151,18 +158,16 @@ class TaskManager {
151 GetStateUpdate? _setter; 158 GetStateUpdate? _setter;
152 List<VoidCallback>? _remove; 159 List<VoidCallback>? _remove;
153 160
154 - final listNotifier = ListNotifierGroup();  
155 -  
156 - // void addElement(Object id, GetStateUpdate listener) {  
157 - // _remove?.add(listNotifier.addListenerId(id, listener));  
158 - // } 161 + void reportAdd(VoidCallback listener) {
  162 + _remove?.add(listener);
  163 + }
159 164
160 void notify(ListNotifierSingleMixin _updaters) { 165 void notify(ListNotifierSingleMixin _updaters) {
161 final listener = _setter; 166 final listener = _setter;
162 if (listener != null) { 167 if (listener != null) {
163 if (!_updaters.containsListener(listener)) { 168 if (!_updaters.containsListener(listener)) {
164 _updaters.addListener(listener); 169 _updaters.addListener(listener);
165 - _remove?.add(() => _updaters.removeListener(listener)); 170 + reportAdd(() => _updaters.removeListener(listener));
166 } 171 }
167 } 172 }
168 } 173 }
@@ -172,8 +177,26 @@ class TaskManager { @@ -172,8 +177,26 @@ class TaskManager {
172 _remove = disposers; 177 _remove = disposers;
173 _setter = setState; 178 _setter = setState;
174 final result = builder(); 179 final result = builder();
  180 + if (disposers.isEmpty) {
  181 + throw ObxError();
  182 + }
175 _remove = null; 183 _remove = null;
176 _setter = null; 184 _setter = null;
177 return result; 185 return result;
178 } 186 }
179 } 187 }
  188 +
  189 +class ObxError {
  190 + const ObxError();
  191 + @override
  192 + String toString() {
  193 + return """
  194 + [Get] the improper use of a GetX has been detected.
  195 + You should only use GetX or Obx for the specific widget that will be updated.
  196 + If you are seeing this error, you probably did not insert any observable variables into GetX/Obx
  197 + or insert them outside the scope that GetX considers suitable for an update
  198 + (example: GetX => HeavyWidget => variableObservable).
  199 + If you need to update a parent widget and a child widget, wrap each one in an Obx/GetX.
  200 + """;
  201 + }
  202 +}
@@ -78,10 +78,10 @@ class _ValueBuilderState<T> extends State<ValueBuilder<T?>> { @@ -78,10 +78,10 @@ class _ValueBuilderState<T> extends State<ValueBuilder<T?>> {
78 class ObxElement = StatelessElement with ObserverComponent; 78 class ObxElement = StatelessElement with ObserverComponent;
79 79
80 // It's a experimental feature 80 // It's a experimental feature
81 -class SimpleBuilder extends ObxStatelessWidget { 81 +class Observer extends ObxStatelessWidget {
82 final WidgetBuilder builder; 82 final WidgetBuilder builder;
83 83
84 - const SimpleBuilder({Key? key, required this.builder}) : super(key: key); 84 + const Observer({Key? key, required this.builder}) : super(key: key);
85 85
86 @override 86 @override
87 Widget build(BuildContext context) => builder(context); 87 Widget build(BuildContext context) => builder(context);
1 import 'dart:async'; 1 import 'dart:async';
  2 +
2 import 'package:flutter/foundation.dart'; 3 import 'package:flutter/foundation.dart';
3 import 'package:flutter_test/flutter_test.dart'; 4 import 'package:flutter_test/flutter_test.dart';
4 import 'package:get/state_manager.dart'; 5 import 'package:get/state_manager.dart';
@@ -73,28 +74,28 @@ Future<int> stream() { @@ -73,28 +74,28 @@ Future<int> stream() {
73 return c.future; 74 return c.future;
74 } 75 }
75 76
76 -Future<int> getStream() {  
77 - final c = Completer<int>(); 77 +// Future<int> getStream() {
  78 +// final c = Completer<int>();
78 79
79 - final value = GetStream<int>();  
80 - final timer = Stopwatch();  
81 - timer.start(); 80 +// final value = GetStream<int>();
  81 +// final timer = Stopwatch();
  82 +// timer.start();
82 83
83 - value.listen((v) {  
84 - if (times == v) {  
85 - timer.stop();  
86 - print(  
87 - """$v listeners notified | [GET_STREAM] time: ${timer.elapsedMicroseconds}ms""");  
88 - c.complete(timer.elapsedMicroseconds);  
89 - }  
90 - }); 84 +// value.listen((v) {
  85 +// if (times == v) {
  86 +// timer.stop();
  87 +// print(
  88 +// """$v listeners notified | [GET_STREAM] time: ${timer.elapsedMicroseconds}ms""");
  89 +// c.complete(timer.elapsedMicroseconds);
  90 +// }
  91 +// });
91 92
92 - for (var i = 0; i < times + 1; i++) {  
93 - value.add(i);  
94 - } 93 +// for (var i = 0; i < times + 1; i++) {
  94 +// value.add(i);
  95 +// }
95 96
96 - return c.future;  
97 -} 97 +// return c.future;
  98 +// }
98 99
99 Future<int> miniStream() { 100 Future<int> miniStream() {
100 final c = Completer<int>(); 101 final c = Completer<int>();
@@ -157,7 +158,7 @@ GetValue is ${calculePercentage(dart, getx).round()}% faster than Default ValueN @@ -157,7 +158,7 @@ GetValue is ${calculePercentage(dart, getx).round()}% faster than Default ValueN
157 print('============================================'); 158 print('============================================');
158 print('DART STREAM X GET_STREAM X GET_MINI_STREAM TEST'); 159 print('DART STREAM X GET_STREAM X GET_MINI_STREAM TEST');
159 print('-----------'); 160 print('-----------');
160 - var getx = await getStream(); 161 + // var getx = await getStream();
161 var mini = await miniStream(); 162 var mini = await miniStream();
162 var dart = await stream(); 163 var dart = await stream();
163 print('-----------'); 164 print('-----------');
@@ -167,16 +168,16 @@ GetStream is ${calculePercentage(dart, mini).round()}% faster than Default Strea @@ -167,16 +168,16 @@ GetStream is ${calculePercentage(dart, mini).round()}% faster than Default Strea
167 168
168 times = 30000; 169 times = 30000;
169 dart = await stream(); 170 dart = await stream();
170 - getx = await getStream(); 171 + // getx = await getStream();
171 mini = await miniStream(); 172 mini = await miniStream();
172 173
173 times = 60000; 174 times = 60000;
174 dart = await stream(); 175 dart = await stream();
175 - getx = await getStream(); 176 + // getx = await getStream();
176 mini = await miniStream(); 177 mini = await miniStream();
177 print('-----------'); 178 print('-----------');
178 print('dart_stream delay $dart ms to made $times requests'); 179 print('dart_stream delay $dart ms to made $times requests');
179 - print('getx_stream delay $getx ms to made $times requests'); 180 + // print('getx_stream delay $getx ms to made $times requests');
180 print('getx_mini_stream delay $mini ms to made $times requests'); 181 print('getx_mini_stream delay $mini ms to made $times requests');
181 print('-----------'); 182 print('-----------');
182 print(''' 183 print('''