Jonny Borges
Committed by GitHub

Merge pull request #2095 from jonataslaw/sm-refactor

Sm refactor
@@ -3,7 +3,7 @@ import 'package:get/get.dart'; @@ -3,7 +3,7 @@ import 'package:get/get.dart';
3 import '../../domain/adapters/repository_adapter.dart'; 3 import '../../domain/adapters/repository_adapter.dart';
4 import '../../domain/entity/cases_model.dart'; 4 import '../../domain/entity/cases_model.dart';
5 5
6 -class HomeController extends SuperController<CasesModel> { 6 +class HomeController extends StateController<CasesModel> {
7 HomeController({required this.homeRepository}); 7 HomeController({required this.homeRepository});
8 8
9 final IHomeRepository homeRepository; 9 final IHomeRepository homeRepository;
@@ -11,74 +11,12 @@ class HomeController extends SuperController<CasesModel> { @@ -11,74 +11,12 @@ class HomeController extends SuperController<CasesModel> {
11 @override 11 @override
12 void onInit() { 12 void onInit() {
13 super.onInit(); 13 super.onInit();
14 -  
15 //Loading, Success, Error handle with 1 line of code 14 //Loading, Success, Error handle with 1 line of code
16 - append(() => homeRepository.getCases); 15 + futurize(() => homeRepository.getCases);
17 } 16 }
18 17
19 Country getCountryById(String id) { 18 Country getCountryById(String id) {
20 final index = int.tryParse(id); 19 final index = int.tryParse(id);
21 - if (index != null) {  
22 - return state.countries[index];  
23 - }  
24 -  
25 - return state.countries.first;  
26 - }  
27 -  
28 - @override  
29 - void onReady() {  
30 - print('The build method is done. '  
31 - 'Your controller is ready to call dialogs and snackbars');  
32 - super.onReady();  
33 - }  
34 -  
35 - @override  
36 - void onClose() {  
37 - print('onClose called');  
38 - super.onClose();  
39 - }  
40 -  
41 - @override  
42 - void didChangeMetrics() {  
43 - print('the window size did change');  
44 - super.didChangeMetrics();  
45 - }  
46 -  
47 - @override  
48 - void didChangePlatformBrightness() {  
49 - print('platform change ThemeMode');  
50 - super.didChangePlatformBrightness();  
51 - }  
52 -  
53 - @override  
54 - Future<bool> didPushRoute(String route) {  
55 - print('the route $route will be open');  
56 - return super.didPushRoute(route);  
57 - }  
58 -  
59 - @override  
60 - Future<bool> didPopRoute() {  
61 - print('the current route will be closed');  
62 - return super.didPopRoute();  
63 - }  
64 -  
65 - @override  
66 - void onDetached() {  
67 - print('onDetached called');  
68 - }  
69 -  
70 - @override  
71 - void onInactive() {  
72 - print('onInative called');  
73 - }  
74 -  
75 - @override  
76 - void onPaused() {  
77 - print('onPaused called');  
78 - }  
79 -  
80 - @override  
81 - void onResumed() {  
82 - print('onResumed called'); 20 + return index != null ? state.countries[index] : state.countries.first;
83 } 21 }
84 } 22 }
1 import 'dart:io'; 1 import 'dart:io';
2 -import 'dart:math';  
3 2
4 import 'package:flutter/material.dart'; 3 import 'package:flutter/material.dart';
5 import 'package:flutter_test/flutter_test.dart'; 4 import 'package:flutter_test/flutter_test.dart';
@@ -11,28 +10,29 @@ import 'package:get_demo/pages/home/presentation/controllers/home_controller.dar @@ -11,28 +10,29 @@ import 'package:get_demo/pages/home/presentation/controllers/home_controller.dar
11 // import 'package:get_test/get_test.dart'; 10 // import 'package:get_test/get_test.dart';
12 import 'package:matcher/matcher.dart' as m; 11 import 'package:matcher/matcher.dart' as m;
13 12
14 -class MockRepository implements IHomeRepository { 13 +class MockRepositorySuccess implements IHomeRepository {
15 @override 14 @override
16 Future<CasesModel> getCases() async { 15 Future<CasesModel> getCases() async {
17 - await Future.delayed(Duration(milliseconds: 100));  
18 -  
19 - if (Random().nextBool()) {  
20 - return CasesModel(  
21 - global: Global(  
22 - totalDeaths: 100,  
23 - totalConfirmed: 200,  
24 - date: DateTime.now(),  
25 - newConfirmed: 0,  
26 - newDeaths: 0,  
27 - newRecovered: 0,  
28 - totalRecovered: 0),  
29 - countries: [],  
30 - date: DateTime.now(),  
31 - id: '',  
32 - message: '',  
33 - );  
34 - } 16 + return CasesModel(
  17 + global: Global(
  18 + totalDeaths: 100,
  19 + totalConfirmed: 200,
  20 + date: DateTime.now(),
  21 + newConfirmed: 0,
  22 + newDeaths: 0,
  23 + newRecovered: 0,
  24 + totalRecovered: 0),
  25 + countries: [],
  26 + date: DateTime.now(),
  27 + id: '',
  28 + message: '',
  29 + );
  30 + }
  31 +}
35 32
  33 +class MockRepositoryFailure implements IHomeRepository {
  34 + @override
  35 + Future<CasesModel> getCases() async {
36 return Future<CasesModel>.error('error'); 36 return Future<CasesModel>.error('error');
37 } 37 }
38 } 38 }
@@ -41,28 +41,18 @@ void main() { @@ -41,28 +41,18 @@ void main() {
41 WidgetsFlutterBinding.ensureInitialized(); 41 WidgetsFlutterBinding.ensureInitialized();
42 setUpAll(() => HttpOverrides.global = null); 42 setUpAll(() => HttpOverrides.global = null);
43 final binding = BindingsBuilder(() { 43 final binding = BindingsBuilder(() {
44 - Get.lazyPut<IHomeRepository>(() => MockRepository()); 44 + Get.lazyPut<IHomeRepository>(() => MockRepositorySuccess());
45 Get.lazyPut<HomeController>( 45 Get.lazyPut<HomeController>(
46 - () => HomeController(homeRepository: Get.find())); 46 + () => HomeController(homeRepository: Get.find()),
  47 + );
47 }); 48 });
48 49
49 - test('Test Binding', () {  
50 - expect(Get.isPrepared<HomeController>(), false);  
51 - expect(Get.isPrepared<IHomeRepository>(), false);  
52 -  
53 - /// test you Binding class with BindingsBuilder  
54 - binding.builder();  
55 -  
56 - expect(Get.isPrepared<HomeController>(), true);  
57 - expect(Get.isPrepared<IHomeRepository>(), true);  
58 -  
59 - Get.reset();  
60 - });  
61 test('Test Controller', () async { 50 test('Test Controller', () async {
62 /// Controller can't be on memory 51 /// Controller can't be on memory
63 - expect(() => Get.find<HomeController>(), throwsA(m.TypeMatcher<String>())); 52 + expect(() => Get.find<HomeController>(tag: 'success'),
  53 + throwsA(m.TypeMatcher<String>()));
64 54
65 - /// build Binding 55 + /// binding will put the controller on memory
66 binding.builder(); 56 binding.builder();
67 57
68 /// recover your controller 58 /// recover your controller
@@ -77,24 +67,15 @@ void main() { @@ -77,24 +67,15 @@ void main() {
77 /// await time request 67 /// await time request
78 await Future.delayed(Duration(milliseconds: 100)); 68 await Future.delayed(Duration(milliseconds: 100));
79 69
80 - if (controller.status.isError) {  
81 - expect(controller.state, null);  
82 - }  
83 -  
84 - if (controller.status.isSuccess) {  
85 - expect(controller.state.global.totalDeaths, 100);  
86 - expect(controller.state.global.totalConfirmed, 200);  
87 - }  
88 - }); 70 + /// test if status is success
  71 + expect(controller.status.isSuccess, true);
  72 + expect(controller.state.global.totalDeaths, 100);
  73 + expect(controller.state.global.totalConfirmed, 200);
89 74
90 - test('ever', () async {  
91 - final count = ''.obs;  
92 - var result = '';  
93 - ever<String>(count, (value) {  
94 - result = value;  
95 - });  
96 - count.value = '1';  
97 - expect('1', result); 75 + /// test if status is error
  76 + Get.lazyReplace<IHomeRepository>(() => MockRepositoryFailure());
  77 + expect(controller.status.isError, true);
  78 + expect(controller.state, null);
98 }); 79 });
99 80
100 /// Tests with GetTests 81 /// Tests with GetTests
@@ -151,26 +132,3 @@ void main() { @@ -151,26 +132,3 @@ void main() {
151 }, 132 },
152 );*/ 133 );*/
153 } 134 }
154 -  
155 -class Controller extends GetxController {  
156 - final count = 0.obs;  
157 - void increment() => count.value++;  
158 -  
159 - @override  
160 - void onInit() {  
161 - print('inittt');  
162 - super.onInit();  
163 - }  
164 -  
165 - @override  
166 - void onReady() {  
167 - print('onReady');  
168 - super.onReady();  
169 - }  
170 -  
171 - @override  
172 - void onClose() {  
173 - super.onClose();  
174 - print('onClose');  
175 - }  
176 -}  
@@ -21,6 +21,6 @@ @@ -21,6 +21,6 @@
21 <key>CFBundleVersion</key> 21 <key>CFBundleVersion</key>
22 <string>1.0</string> 22 <string>1.0</string>
23 <key>MinimumOSVersion</key> 23 <key>MinimumOSVersion</key>
24 - <string>8.0</string> 24 + <string>9.0</string>
25 </dict> 25 </dict>
26 </plist> 26 </plist>
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 archiveVersion = 1; 3 archiveVersion = 1;
4 classes = { 4 classes = {
5 }; 5 };
6 - objectVersion = 46; 6 + objectVersion = 50;
7 objects = { 7 objects = {
8 8
9 /* Begin PBXBuildFile section */ 9 /* Begin PBXBuildFile section */
@@ -127,7 +127,7 @@ @@ -127,7 +127,7 @@
127 97C146E61CF9000F007C117D /* Project object */ = { 127 97C146E61CF9000F007C117D /* Project object */ = {
128 isa = PBXProject; 128 isa = PBXProject;
129 attributes = { 129 attributes = {
130 - LastUpgradeCheck = 1020; 130 + LastUpgradeCheck = 1300;
131 ORGANIZATIONNAME = ""; 131 ORGANIZATIONNAME = "";
132 TargetAttributes = { 132 TargetAttributes = {
133 97C146ED1CF9000F007C117D = { 133 97C146ED1CF9000F007C117D = {
1 <?xml version="1.0" encoding="UTF-8"?> 1 <?xml version="1.0" encoding="UTF-8"?>
2 <Scheme 2 <Scheme
3 - LastUpgradeVersion = "1020" 3 + LastUpgradeVersion = "1300"
4 version = "1.3"> 4 version = "1.3">
5 <BuildAction 5 <BuildAction
6 parallelizeBuildables = "YES" 6 parallelizeBuildables = "YES"
@@ -6,7 +6,8 @@ import 'package:flutter/material.dart'; @@ -6,7 +6,8 @@ import 'package:flutter/material.dart';
6 import '../../../get.dart'; 6 import '../../../get.dart';
7 import '../../../get_state_manager/src/simple/list_notifier.dart'; 7 import '../../../get_state_manager/src/simple/list_notifier.dart';
8 8
9 -class GetDelegate extends RouterDelegate<GetNavConfig> with ListNotifierMixin { 9 +class GetDelegate extends RouterDelegate<GetNavConfig>
  10 + with ListNotifierSingleMixin {
10 final List<GetNavConfig> history = <GetNavConfig>[]; 11 final List<GetNavConfig> history = <GetNavConfig>[];
11 final PopMode backButtonPopMode; 12 final PopMode backButtonPopMode;
12 final PreventDuplicateHandlingMode preventDuplicateHandlingMode; 13 final PreventDuplicateHandlingMode preventDuplicateHandlingMode;
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> {
@@ -99,6 +96,7 @@ extension MapExtension<K, V> on Map<K, V> { @@ -99,6 +96,7 @@ extension MapExtension<K, V> on Map<K, V> {
99 final map = (this as RxMap); 96 final map = (this as RxMap);
100 if (map.value == val) return; 97 if (map.value == val) return;
101 map.value = val; 98 map.value = val;
  99 + // ignore: invalid_use_of_protected_member
102 map.refresh(); 100 map.refresh();
103 } else { 101 } else {
104 if (this == val) return; 102 if (this == val) return;
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
@@ -5,7 +5,7 @@ import 'dart:collection'; @@ -5,7 +5,7 @@ import 'dart:collection';
5 5
6 import 'package:flutter/foundation.dart'; 6 import 'package:flutter/foundation.dart';
7 7
8 -import '../rx_stream/rx_stream.dart'; 8 +import '../../../get_state_manager/src/rx_flutter/rx_notifier.dart';
9 import '../rx_typedefs/rx_typedefs.dart'; 9 import '../rx_typedefs/rx_typedefs.dart';
10 10
11 part 'rx_core/rx_impl.dart'; 11 part 'rx_core/rx_impl.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,37 +7,52 @@ import '../../../instance_manager.dart'; @@ -5,37 +7,52 @@ 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 ListNotifierMixin {  
9 - late T _value;  
10 - RxStatus? _status;  
11 -  
12 - bool _isNullOrEmpty(dynamic val) {  
13 - if (val == null) return true; 10 +extension _Empty on Object {
  11 + bool _isEmpty() {
  12 + final val = this;
  13 + // if (val == null) return true;
14 var result = false; 14 var result = false;
15 if (val is Iterable) { 15 if (val is Iterable) {
16 result = val.isEmpty; 16 result = val.isEmpty;
17 } else if (val is String) { 17 } else if (val is String) {
18 - result = val.isEmpty; 18 + result = val.trim().isEmpty;
19 } else if (val is Map) { 19 } else if (val is Map) {
20 result = val.isEmpty; 20 result = val.isEmpty;
21 } 21 }
22 return result; 22 return result;
23 } 23 }
  24 +}
24 25
25 - void _fillEmptyStatus() {  
26 - _status = _isNullOrEmpty(_value) ? RxStatus.loading() : RxStatus.success(); 26 +mixin StateMixin<T> on ListNotifier {
  27 + late T _value;
  28 + GetState<T>? _status;
  29 +
  30 + void _fillInitialStatus() {
  31 + _status = (value == null || value!._isEmpty())
  32 + ? GetState<T>.loading()
  33 + : GetState<T>.success(_value);
27 } 34 }
28 35
29 - RxStatus get status {  
30 - notifyChildrens();  
31 - return _status ??= _status = RxStatus.loading(); 36 + GetState<T> get status {
  37 + reportRead();
  38 + return _status ??= _status = GetState.loading();
32 } 39 }
33 40
34 T get state => value; 41 T get state => value;
35 42
  43 + set status(GetState<T> newStatus) {
  44 + if (newStatus == status) return;
  45 + _status = newStatus;
  46 + if (newStatus is SuccessState<T>) {
  47 + _value = newStatus.data!;
  48 + return;
  49 + }
  50 + refresh();
  51 + }
  52 +
36 @protected 53 @protected
37 T get value { 54 T get value {
38 - notifyChildrens(); 55 + reportRead();
39 return _value; 56 return _value;
40 } 57 }
41 58
@@ -46,43 +63,103 @@ mixin StateMixin<T> on ListNotifierMixin { @@ -46,43 +63,103 @@ mixin StateMixin<T> on ListNotifierMixin {
46 refresh(); 63 refresh();
47 } 64 }
48 65
49 - @protected  
50 - void change(T newState, {RxStatus? status}) {  
51 - var _canUpdate = false;  
52 - if (status != null) {  
53 - _status = status;  
54 - _canUpdate = true;  
55 - }  
56 - if (newState != _value) {  
57 - _value = newState;  
58 - _canUpdate = true;  
59 - }  
60 - if (_canUpdate) {  
61 - refresh();  
62 - }  
63 - }  
64 -  
65 - void append(Future<T> Function() body(), {String? errorMessage}) { 66 + void futurize(Future<T> Function() body(),
  67 + {String? errorMessage, bool useEmpty = true}) {
66 final compute = body(); 68 final compute = body();
67 compute().then((newValue) { 69 compute().then((newValue) {
68 - change(newValue, status: RxStatus.success()); 70 + if ((newValue == null || newValue._isEmpty()) && useEmpty) {
  71 + status = GetState<T>.loading();
  72 + } else {
  73 + status = GetState<T>.success(newValue);
  74 + }
69 }, onError: (err) { 75 }, onError: (err) {
70 - change(state, status: RxStatus.error(errorMessage ?? err.toString())); 76 + status = GetState.error(errorMessage ?? err.toString());
71 }); 77 });
72 } 78 }
73 } 79 }
74 80
  81 +class GetListenable<T> extends ListNotifierSingle
  82 + implements ValueListenable<T> {
  83 + GetListenable(T val) : _value = val;
  84 +
  85 + StreamController<T>? _controller;
  86 +
  87 + StreamController<T> get subject {
  88 + if (_controller == null) {
  89 + _controller = StreamController<T>.broadcast();
  90 + addListener(_streamListener);
  91 + }
  92 + return _controller!;
  93 + }
  94 +
  95 + void _streamListener() {
  96 + _controller?.add(_value);
  97 + }
  98 +
  99 + @mustCallSuper
  100 + void close() {
  101 + removeListener(_streamListener);
  102 + _controller?.close();
  103 + dispose();
  104 + }
  105 +
  106 + Stream<T> get stream {
  107 + return subject.stream;
  108 + }
  109 +
  110 + T _value;
  111 +
  112 + @override
  113 + T get value {
  114 + reportRead();
  115 + return _value;
  116 + }
  117 +
  118 + void _notify() {
  119 + refresh();
  120 + }
  121 +
  122 + set value(T newValue) {
  123 + if (_value == newValue) return;
  124 + _value = newValue;
  125 + _notify();
  126 + }
  127 +
  128 + T? call([T? v]) {
  129 + if (v != null) {
  130 + value = v;
  131 + }
  132 + return value;
  133 + }
  134 +
  135 + StreamSubscription<T> listen(
  136 + void Function(T)? onData, {
  137 + Function? onError,
  138 + void Function()? onDone,
  139 + bool? cancelOnError,
  140 + }) =>
  141 + stream.listen(
  142 + onData,
  143 + onError: onError,
  144 + onDone: onDone,
  145 + cancelOnError: cancelOnError ?? false,
  146 + );
  147 +
  148 + @override
  149 + String toString() => value.toString();
  150 +}
  151 +
75 class Value<T> extends ListNotifier 152 class Value<T> extends ListNotifier
76 with StateMixin<T> 153 with StateMixin<T>
77 implements ValueListenable<T?> { 154 implements ValueListenable<T?> {
78 Value(T val) { 155 Value(T val) {
79 _value = val; 156 _value = val;
80 - _fillEmptyStatus(); 157 + _fillInitialStatus();
81 } 158 }
82 159
83 @override 160 @override
84 T get value { 161 T get value {
85 - notifyChildrens(); 162 + reportRead();
86 return _value; 163 return _value;
87 } 164 }
88 165
@@ -111,12 +188,6 @@ class Value<T> extends ListNotifier @@ -111,12 +188,6 @@ class Value<T> extends ListNotifier
111 dynamic toJson() => (value as dynamic)?.toJson(); 188 dynamic toJson() => (value as dynamic)?.toJson();
112 } 189 }
113 190
114 -extension ReactiveT<T> on T {  
115 - Value<T> get reactive => Value<T>(this);  
116 -}  
117 -  
118 -typedef Condition = bool Function();  
119 -  
120 abstract class GetNotifier<T> extends Value<T> with GetLifeCycleMixin { 191 abstract class GetNotifier<T> extends Value<T> with GetLifeCycleMixin {
121 GetNotifier(T initial) : super(initial); 192 GetNotifier(T initial) : super(initial);
122 } 193 }
@@ -128,7 +199,7 @@ extension StateExt<T> on StateMixin<T> { @@ -128,7 +199,7 @@ extension StateExt<T> on StateMixin<T> {
128 Widget? onLoading, 199 Widget? onLoading,
129 Widget? onEmpty, 200 Widget? onEmpty,
130 }) { 201 }) {
131 - return SimpleBuilder(builder: (_) { 202 + return Observer(builder: (_) {
132 if (status.isLoading) { 203 if (status.isLoading) {
133 return onLoading ?? const Center(child: CircularProgressIndicator()); 204 return onLoading ?? const Center(child: CircularProgressIndicator());
134 } else if (status.isError) { 205 } else if (status.isError) {
@@ -145,78 +216,40 @@ extension StateExt<T> on StateMixin<T> { @@ -145,78 +216,40 @@ extension StateExt<T> on StateMixin<T> {
145 } 216 }
146 } 217 }
147 218
148 -class RxStatus {  
149 - final bool isLoading;  
150 - final bool isError;  
151 - final bool isSuccess;  
152 - final bool isEmpty;  
153 - final bool isLoadingMore;  
154 - final String? errorMessage;  
155 -  
156 - RxStatus._({  
157 - this.isEmpty = false,  
158 - this.isLoading = false,  
159 - this.isError = false,  
160 - this.isSuccess = false,  
161 - this.errorMessage,  
162 - this.isLoadingMore = false,  
163 - });  
164 -  
165 - factory RxStatus.loading() {  
166 - return RxStatus._(isLoading: true);  
167 - }  
168 -  
169 - factory RxStatus.loadingMore() {  
170 - return RxStatus._(isSuccess: true, isLoadingMore: true);  
171 - }  
172 -  
173 - factory RxStatus.success() {  
174 - return RxStatus._(isSuccess: true);  
175 - }  
176 -  
177 - factory RxStatus.error([String? message]) {  
178 - return RxStatus._(isError: true, errorMessage: message);  
179 - }  
180 -  
181 - factory RxStatus.empty() {  
182 - return RxStatus._(isEmpty: true);  
183 - }  
184 -}  
185 -  
186 typedef NotifierBuilder<T> = Widget Function(T state); 219 typedef NotifierBuilder<T> = Widget Function(T state);
187 220
188 -abstract class GState<T> {  
189 - const GState();  
190 - factory GState.loading() => GLoading();  
191 - factory GState.error(String message) => GError(message);  
192 - factory GState.empty() => GEmpty();  
193 - factory GState.success(T data) => GSuccess(data); 221 +abstract class GetState<T> {
  222 + const GetState();
  223 + factory GetState.loading() => LoadingState();
  224 + factory GetState.error(String message) => ErrorState(message);
  225 + factory GetState.empty() => EmptyState();
  226 + factory GetState.success(T data) => SuccessState(data);
194 } 227 }
195 228
196 -class GLoading<T> extends GState<T> {} 229 +class LoadingState<T> extends GetState<T> {}
197 230
198 -class GSuccess<T> extends GState<T> { 231 +class SuccessState<T> extends GetState<T> {
199 final T data; 232 final T data;
200 233
201 - GSuccess(this.data); 234 + SuccessState(this.data);
202 } 235 }
203 236
204 -class GError<T, S> extends GState<T> { 237 +class ErrorState<T, S> extends GetState<T> {
205 final S? error; 238 final S? error;
206 - GError([this.error]); 239 + ErrorState([this.error]);
207 } 240 }
208 241
209 -class GEmpty<T> extends GState<T> {} 242 +class EmptyState<T> extends GetState<T> {}
210 243
211 -extension StatusDataExt<T> on GState<T> {  
212 - bool get isLoading => this is GLoading;  
213 - bool get isSuccess => this is GSuccess;  
214 - bool get isError => this is GError;  
215 - bool get isEmpty => this is GEmpty; 244 +extension StatusDataExt<T> on GetState<T> {
  245 + bool get isLoading => this is LoadingState;
  246 + bool get isSuccess => this is SuccessState;
  247 + bool get isError => this is ErrorState;
  248 + bool get isEmpty => this is EmptyState;
216 String get errorMessage { 249 String get errorMessage {
217 - final isError = this is GError; 250 + final isError = this is ErrorState;
218 if (isError) { 251 if (isError) {
219 - final err = this as GError; 252 + final err = this as ErrorState;
220 if (err.error != null && err.error is String) { 253 if (err.error != null && err.error is String) {
221 return err.error as String; 254 return err.error as String;
222 } 255 }
@@ -224,4 +257,12 @@ extension StatusDataExt<T> on GState<T> { @@ -224,4 +257,12 @@ extension StatusDataExt<T> on GState<T> {
224 257
225 return ''; 258 return '';
226 } 259 }
  260 +
  261 + T? get data {
  262 + if (this is SuccessState<T>) {
  263 + final success = this as SuccessState<T>;
  264 + return success.data;
  265 + }
  266 + return null;
  267 + }
227 } 268 }
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 }
@@ -6,8 +6,7 @@ import '../rx_flutter/rx_notifier.dart'; @@ -6,8 +6,7 @@ import '../rx_flutter/rx_notifier.dart';
6 import 'list_notifier.dart'; 6 import 'list_notifier.dart';
7 7
8 // ignore: prefer_mixin 8 // ignore: prefer_mixin
9 -abstract class GetxController extends Listenable  
10 - with GetLifeCycleMixin, ListNotifierMixin { 9 +abstract class GetxController extends ListNotifier with GetLifeCycleMixin {
11 /// Rebuilds `GetBuilder` each time you call `update()`; 10 /// Rebuilds `GetBuilder` each time you call `update()`;
12 /// Can take a List of [ids], that will only update the matching 11 /// Can take a List of [ids], that will only update the matching
13 /// `GetBuilder( id: )`, 12 /// `GetBuilder( id: )`,
@@ -73,6 +72,8 @@ mixin ScrollMixin on GetLifeCycleMixin { @@ -73,6 +72,8 @@ mixin ScrollMixin on GetLifeCycleMixin {
73 72
74 abstract class RxController with GetLifeCycleMixin {} 73 abstract class RxController with GetLifeCycleMixin {}
75 74
  75 +abstract class StateController<T> extends GetxController with StateMixin<T> {}
  76 +
76 abstract class SuperController<T> extends FullLifeCycleController 77 abstract class SuperController<T> extends FullLifeCycleController
77 with FullLifeCycleMixin, StateMixin<T> {} 78 with FullLifeCycleMixin, StateMixin<T> {}
78 79
1 import 'dart:collection'; 1 import 'dart:collection';
2 2
3 -import 'package:flutter/widgets.dart'; 3 +import 'package:flutter/foundation.dart';
4 4
5 // This callback remove the listener on addListener function 5 // This callback remove the listener on addListener function
6 typedef Disposer = void Function(); 6 typedef Disposer = void Function();
@@ -9,45 +9,60 @@ typedef Disposer = void Function(); @@ -9,45 +9,60 @@ typedef Disposer = void Function();
9 // if it brings overhead the extra call, 9 // if it brings overhead the extra call,
10 typedef GetStateUpdate = void Function(); 10 typedef GetStateUpdate = void Function();
11 11
12 -class ListNotifier extends Listenable with ListNotifierMixin {} 12 +class ListNotifier extends Listenable
  13 + with ListNotifierSingleMixin, ListNotifierGroupMixin {}
13 14
14 -mixin ListNotifierMixin on Listenable { 15 +class ListNotifierSingle = ListNotifier with ListNotifierSingleMixin;
  16 +
  17 +class ListNotifierGroup = ListNotifier with ListNotifierGroupMixin;
  18 +
  19 +mixin ListNotifierSingleMixin on Listenable {
15 List<GetStateUpdate?>? _updaters = <GetStateUpdate?>[]; 20 List<GetStateUpdate?>? _updaters = <GetStateUpdate?>[];
16 21
17 - HashMap<Object?, List<GetStateUpdate>>? _updatersGroupIds =  
18 - HashMap<Object?, List<GetStateUpdate>>(); 22 + @override
  23 + Disposer addListener(GetStateUpdate listener) {
  24 + assert(_debugAssertNotDisposed());
  25 + _updaters!.add(listener);
  26 + return () => _updaters!.remove(listener);
  27 + }
  28 +
  29 + bool containsListener(GetStateUpdate listener) {
  30 + return _updaters?.contains(listener) ?? false;
  31 + }
  32 +
  33 + @override
  34 + void removeListener(VoidCallback listener) {
  35 + assert(_debugAssertNotDisposed());
  36 + _updaters!.remove(listener);
  37 + }
19 38
20 @protected 39 @protected
21 void refresh() { 40 void refresh() {
22 assert(_debugAssertNotDisposed()); 41 assert(_debugAssertNotDisposed());
23 -  
24 _notifyUpdate(); 42 _notifyUpdate();
25 } 43 }
26 44
  45 + @protected
  46 + void reportRead() {
  47 + TaskManager.instance.notify(this);
  48 + }
  49 +
  50 + @protected
  51 + void reportAdd(VoidCallback disposer) {
  52 + TaskManager.instance.reportAdd(disposer);
  53 + }
  54 +
27 void _notifyUpdate() { 55 void _notifyUpdate() {
28 for (var element in _updaters!) { 56 for (var element in _updaters!) {
29 element!(); 57 element!();
30 } 58 }
31 } 59 }
32 60
33 - void _notifyIdUpdate(Object id) {  
34 - if (_updatersGroupIds!.containsKey(id)) {  
35 - final listGroup = _updatersGroupIds![id]!;  
36 - for (var item in listGroup) {  
37 - item();  
38 - }  
39 - }  
40 - }  
41 -  
42 - @protected  
43 - void refreshGroup(Object id) {  
44 - assert(_debugAssertNotDisposed());  
45 - _notifyIdUpdate(id);  
46 - } 61 + bool get isDisposed => _updaters == null;
47 62
48 bool _debugAssertNotDisposed() { 63 bool _debugAssertNotDisposed() {
49 assert(() { 64 assert(() {
50 - if (_updaters == null) { 65 + if (isDisposed) {
51 throw FlutterError('''A $runtimeType was used after being disposed.\n 66 throw FlutterError('''A $runtimeType was used after being disposed.\n
52 '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.''');
53 } 68 }
@@ -56,59 +71,79 @@ mixin ListNotifierMixin on Listenable { @@ -56,59 +71,79 @@ mixin ListNotifierMixin on Listenable {
56 return true; 71 return true;
57 } 72 }
58 73
59 - @protected  
60 - void notifyChildrens() {  
61 - TaskManager.instance.notify(_updaters); 74 + int get listenersLength {
  75 + assert(_debugAssertNotDisposed());
  76 + return _updaters!.length;
62 } 77 }
63 78
64 - bool get hasListeners { 79 + @mustCallSuper
  80 + void dispose() {
65 assert(_debugAssertNotDisposed()); 81 assert(_debugAssertNotDisposed());
66 - return _updaters!.isNotEmpty; 82 + _updaters = null;
  83 + }
  84 +}
  85 +
  86 +mixin ListNotifierGroupMixin on Listenable {
  87 + HashMap<Object?, ListNotifierSingleMixin>? _updatersGroupIds =
  88 + HashMap<Object?, ListNotifierSingleMixin>();
  89 +
  90 + void _notifyGroupUpdate(Object id) {
  91 + if (_updatersGroupIds!.containsKey(id)) {
  92 + _updatersGroupIds![id]!._notifyUpdate();
  93 + }
67 } 94 }
68 95
69 - int get listeners { 96 + @protected
  97 + void notifyGroupChildrens(Object id) {
70 assert(_debugAssertNotDisposed()); 98 assert(_debugAssertNotDisposed());
71 - return _updaters!.length; 99 + TaskManager.instance.notify(_updatersGroupIds![id]!);
72 } 100 }
73 101
74 - @override  
75 - void removeListener(VoidCallback listener) { 102 + bool containsId(Object id) {
  103 + return _updatersGroupIds?.containsKey(id) ?? false;
  104 + }
  105 +
  106 + @protected
  107 + void refreshGroup(Object id) {
76 assert(_debugAssertNotDisposed()); 108 assert(_debugAssertNotDisposed());
77 - _updaters!.remove(listener); 109 + _notifyGroupUpdate(id);
  110 + }
  111 +
  112 + bool _debugAssertNotDisposed() {
  113 + assert(() {
  114 + if (_updatersGroupIds == null) {
  115 + throw FlutterError('''A $runtimeType was used after being disposed.\n
  116 +'Once you have called dispose() on a $runtimeType, it can no longer be used.''');
  117 + }
  118 + return true;
  119 + }());
  120 + return true;
78 } 121 }
79 122
80 void removeListenerId(Object id, VoidCallback listener) { 123 void removeListenerId(Object id, VoidCallback listener) {
81 assert(_debugAssertNotDisposed()); 124 assert(_debugAssertNotDisposed());
82 if (_updatersGroupIds!.containsKey(id)) { 125 if (_updatersGroupIds!.containsKey(id)) {
83 - _updatersGroupIds![id]!.remove(listener); 126 + _updatersGroupIds![id]!.removeListener(listener);
84 } 127 }
85 - _updaters!.remove(listener);  
86 } 128 }
87 129
88 @mustCallSuper 130 @mustCallSuper
89 void dispose() { 131 void dispose() {
90 assert(_debugAssertNotDisposed()); 132 assert(_debugAssertNotDisposed());
91 - _updaters = null; 133 + _updatersGroupIds?.forEach((key, value) => value.dispose());
92 _updatersGroupIds = null; 134 _updatersGroupIds = null;
93 } 135 }
94 136
95 - @override  
96 - Disposer addListener(GetStateUpdate listener) {  
97 - assert(_debugAssertNotDisposed());  
98 - _updaters!.add(listener);  
99 - return () => _updaters!.remove(listener);  
100 - }  
101 -  
102 Disposer addListenerId(Object? key, GetStateUpdate listener) { 137 Disposer addListenerId(Object? key, GetStateUpdate listener) {
103 - _updatersGroupIds![key] ??= <GetStateUpdate>[];  
104 - _updatersGroupIds![key]!.add(listener);  
105 - return () => _updatersGroupIds![key]!.remove(listener); 138 + _updatersGroupIds![key] ??= ListNotifierSingle();
  139 + return _updatersGroupIds![key]!.addListener(listener);
106 } 140 }
107 141
108 /// To dispose an [id] from future updates(), this ids are registered 142 /// To dispose an [id] from future updates(), this ids are registered
109 /// by `GetBuilder()` or similar, so is a way to unlink the state change with 143 /// by `GetBuilder()` or similar, so is a way to unlink the state change with
110 /// the Widget from the Controller. 144 /// the Widget from the Controller.
111 void disposeId(Object id) { 145 void disposeId(Object id) {
  146 + _updatersGroupIds?[id]?.dispose();
112 _updatersGroupIds!.remove(id); 147 _updatersGroupIds!.remove(id);
113 } 148 }
114 } 149 }
@@ -123,11 +158,16 @@ class TaskManager { @@ -123,11 +158,16 @@ class TaskManager {
123 GetStateUpdate? _setter; 158 GetStateUpdate? _setter;
124 List<VoidCallback>? _remove; 159 List<VoidCallback>? _remove;
125 160
126 - void notify(List<GetStateUpdate?>? _updaters) {  
127 - if (_setter != null) {  
128 - if (!_updaters!.contains(_setter)) {  
129 - _updaters.add(_setter);  
130 - _remove!.add(() => _updaters.remove(_setter)); 161 + void reportAdd(VoidCallback listener) {
  162 + _remove?.add(listener);
  163 + }
  164 +
  165 + void notify(ListNotifierSingleMixin _updaters) {
  166 + final listener = _setter;
  167 + if (listener != null) {
  168 + if (!_updaters.containsListener(listener)) {
  169 + _updaters.addListener(listener);
  170 + reportAdd(() => _updaters.removeListener(listener));
131 } 171 }
132 } 172 }
133 } 173 }
@@ -136,9 +176,29 @@ class TaskManager { @@ -136,9 +176,29 @@ class TaskManager {
136 T Function() builder) { 176 T Function() builder) {
137 _remove = disposers; 177 _remove = disposers;
138 _setter = setState; 178 _setter = setState;
  179 +
139 final result = builder(); 180 final result = builder();
  181 + print(disposers.isEmpty);
  182 + if (disposers.isEmpty) {
  183 + throw ObxError();
  184 + }
140 _remove = null; 185 _remove = null;
141 _setter = null; 186 _setter = null;
142 return result; 187 return result;
143 } 188 }
144 } 189 }
  190 +
  191 +class ObxError {
  192 + const ObxError();
  193 + @override
  194 + String toString() {
  195 + return """
  196 + [Get] the improper use of a GetX has been detected.
  197 + You should only use GetX or Obx for the specific widget that will be updated.
  198 + If you are seeing this error, you probably did not insert any observable variables into GetX/Obx
  199 + or insert them outside the scope that GetX considers suitable for an update
  200 + (example: GetX => HeavyWidget => variableObservable).
  201 + If you need to update a parent widget and a child widget, wrap each one in an Obx/GetX.
  202 + """;
  203 + }
  204 +}
@@ -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('''