Jonatas

refactor getview from scratch, reformulate rx variables, add error handler to wo…

…rkers, improve RxList, RxMap and RxSet factorys constructors, fix GetStream addError, refactor instance manager, add patch method to http
1 class Logger { 1 class Logger {
2 // Sample of abstract logging function 2 // Sample of abstract logging function
3 static void write(String text, {bool isError = false}) { 3 static void write(String text, {bool isError = false}) {
4 - print('** $text [$isError]'); 4 + Future.microtask(() => print('** $text. isError: [$isError]'));
5 } 5 }
6 } 6 }
@@ -253,25 +253,6 @@ class GetHttpClient { @@ -253,25 +253,6 @@ class GetHttpClient {
253 )); 253 ));
254 } 254 }
255 255
256 - Future<Request<T>> _post<T>(  
257 - String url, {  
258 - String contentType,  
259 - @required dynamic body,  
260 - Map<String, dynamic> query,  
261 - Decoder<T> decoder,  
262 - @required Progress uploadProgress,  
263 - }) {  
264 - return _requestWithBody<T>(  
265 - url,  
266 - contentType,  
267 - body,  
268 - 'post',  
269 - query,  
270 - decoder ?? (defaultDecoder as Decoder<T>),  
271 - uploadProgress,  
272 - );  
273 - }  
274 -  
275 Future<Request<T>> _request<T>( 256 Future<Request<T>> _request<T>(
276 String url, 257 String url,
277 String method, { 258 String method, {
@@ -292,25 +273,6 @@ class GetHttpClient { @@ -292,25 +273,6 @@ class GetHttpClient {
292 ); 273 );
293 } 274 }
294 275
295 - Future<Request<T>> _put<T>(  
296 - String url, {  
297 - String contentType,  
298 - @required dynamic body,  
299 - @required Map<String, dynamic> query,  
300 - Decoder<T> decoder,  
301 - @required Progress uploadProgress,  
302 - }) {  
303 - return _requestWithBody<T>(  
304 - url,  
305 - contentType,  
306 - body,  
307 - 'put',  
308 - query,  
309 - decoder ?? (defaultDecoder as Decoder<T>),  
310 - uploadProgress,  
311 - );  
312 - }  
313 -  
314 Request<T> _delete<T>( 276 Request<T> _delete<T>(
315 String url, 277 String url,
316 String contentType, 278 String contentType,
@@ -329,6 +291,40 @@ class GetHttpClient { @@ -329,6 +291,40 @@ class GetHttpClient {
329 ); 291 );
330 } 292 }
331 293
  294 + Future<Response<T>> patch<T>(
  295 + String url, {
  296 + dynamic body,
  297 + String contentType,
  298 + Map<String, String> headers,
  299 + Map<String, dynamic> query,
  300 + Decoder<T> decoder,
  301 + Progress uploadProgress,
  302 + // List<MultipartFile> files,
  303 + }) async {
  304 + try {
  305 + var response = await _performRequest<T>(
  306 + () => _request<T>(
  307 + url,
  308 + 'patch',
  309 + contentType: contentType,
  310 + body: body,
  311 + query: query,
  312 + decoder: decoder,
  313 + uploadProgress: uploadProgress,
  314 + ),
  315 + headers: headers,
  316 + );
  317 + return response;
  318 + } on Exception catch (e) {
  319 + if (!errorSafety) {
  320 + throw GetHttpException(e.toString());
  321 + }
  322 + return Future.value(Response<T>(
  323 + statusText: 'Can not connect to server. Reason: $e',
  324 + ));
  325 + }
  326 + }
  327 +
332 Future<Response<T>> post<T>( 328 Future<Response<T>> post<T>(
333 String url, { 329 String url, {
334 dynamic body, 330 dynamic body,
@@ -341,8 +337,9 @@ class GetHttpClient { @@ -341,8 +337,9 @@ class GetHttpClient {
341 }) async { 337 }) async {
342 try { 338 try {
343 var response = await _performRequest<T>( 339 var response = await _performRequest<T>(
344 - () => _post<T>( 340 + () => _request<T>(
345 url, 341 url,
  342 + 'post',
346 contentType: contentType, 343 contentType: contentType,
347 body: body, 344 body: body,
348 query: query, 345 query: query,
@@ -407,8 +404,9 @@ class GetHttpClient { @@ -407,8 +404,9 @@ class GetHttpClient {
407 }) async { 404 }) async {
408 try { 405 try {
409 var response = await _performRequest<T>( 406 var response = await _performRequest<T>(
410 - () => _put<T>( 407 + () => _request<T>(
411 url, 408 url,
  409 + 'put',
412 contentType: contentType, 410 contentType: contentType,
413 query: query, 411 query: query,
414 body: body, 412 body: body,
1 import 'dart:async'; 1 import 'dart:async';
2 import 'dart:collection'; 2 import 'dart:collection';
3 -import '../../get_core/get_core.dart'; 3 +
  4 +import 'package:get/utils.dart';
4 5
5 import 'lifecycle.dart'; 6 import 'lifecycle.dart';
6 7
@@ -19,7 +20,7 @@ class GetInstance { @@ -19,7 +20,7 @@ class GetInstance {
19 20
20 /// Holds a reference to every registered callback when using 21 /// Holds a reference to every registered callback when using
21 /// [Get.lazyPut()] 22 /// [Get.lazyPut()]
22 - static final Map<String, _Lazy> _factory = {}; 23 + // static final Map<String, _Lazy> _factory = {};
23 24
24 /// Holds a reference to [Get.reference] when the Instance was 25 /// Holds a reference to [Get.reference] when the Instance was
25 /// created to manage the memory. 26 /// created to manage the memory.
@@ -56,10 +57,14 @@ class GetInstance { @@ -56,10 +57,14 @@ class GetInstance {
56 void lazyPut<S>( 57 void lazyPut<S>(
57 InstanceBuilderCallback<S> builder, { 58 InstanceBuilderCallback<S> builder, {
58 String tag, 59 String tag,
59 - bool fenix = false, 60 + bool fenix,
60 }) { 61 }) {
61 - final key = _getKey(S, tag);  
62 - _factory.putIfAbsent(key, () => _Lazy(builder, fenix)); 62 + _insert(
  63 + isSingleton: true,
  64 + name: tag,
  65 + permanent: fenix ?? Get.smartManagement == SmartManagement.keepFactory,
  66 + builder: builder,
  67 + );
63 } 68 }
64 69
65 void injector<S>( 70 void injector<S>(
@@ -133,7 +138,11 @@ class GetInstance { @@ -133,7 +138,11 @@ class GetInstance {
133 bool permanent = true, 138 bool permanent = true,
134 }) { 139 }) {
135 _insert( 140 _insert(
136 - isSingleton: false, name: tag, builder: builder, permanent: permanent); 141 + isSingleton: false,
  142 + name: tag,
  143 + builder: builder,
  144 + permanent: permanent,
  145 + );
137 } 146 }
138 147
139 /// Injects the Instance [S] builder into the [_singleton] HashMap. 148 /// Injects the Instance [S] builder into the [_singleton] HashMap.
@@ -240,17 +249,6 @@ class GetInstance { @@ -240,17 +249,6 @@ class GetInstance {
240 if (_singl.containsKey(key)) { 249 if (_singl.containsKey(key)) {
241 return _singl[key].getDependency() as S; 250 return _singl[key].getDependency() as S;
242 } else { 251 } else {
243 - if (_factory.containsKey(key)) {  
244 - final _value = put<S>((_factory[key].builder() as S), tag: tag);  
245 -  
246 - if (Get.smartManagement != SmartManagement.keepFactory) {  
247 - if (!_factory[key].fenix) {  
248 - _factory.remove(key);  
249 - }  
250 - }  
251 - return _value;  
252 - }  
253 -  
254 return GetInstance().put(dep(), tag: tag); 252 return GetInstance().put(dep(), tag: tag);
255 } 253 }
256 } 254 }
@@ -277,21 +275,8 @@ class GetInstance { @@ -277,21 +275,8 @@ class GetInstance {
277 final i = _initDependencies<S>(name: tag); 275 final i = _initDependencies<S>(name: tag);
278 return i ?? _singl[key].getDependency() as S; 276 return i ?? _singl[key].getDependency() as S;
279 } else { 277 } else {
280 - if (!_factory.containsKey(key)) {  
281 - // ignore: lines_longer_than_80_chars  
282 - throw '"$S" not found. You need to call "Get.put($S())" or "Get.lazyPut(()=>$S())"';  
283 - }  
284 -  
285 - Get.log('Lazy instance "$S" created');  
286 - final _value = put<S>(_factory[key].builder() as S, tag: tag);  
287 - _initDependencies<S>(name: tag);  
288 -  
289 - if (Get.smartManagement != SmartManagement.keepFactory &&  
290 - !_factory[key].fenix) {  
291 - _factory.remove(key);  
292 - }  
293 -  
294 - return _value; 278 + // ignore: lines_longer_than_80_chars
  279 + throw '"$S" not found. You need to call "Get.put($S())" or "Get.lazyPut(()=>$S())"';
295 } 280 }
296 } 281 }
297 282
@@ -308,7 +293,7 @@ class GetInstance { @@ -308,7 +293,7 @@ class GetInstance {
308 /// [clearRouteBindings] clears Instances associated with routes. 293 /// [clearRouteBindings] clears Instances associated with routes.
309 /// 294 ///
310 bool reset({bool clearFactory = true, bool clearRouteBindings = true}) { 295 bool reset({bool clearFactory = true, bool clearRouteBindings = true}) {
311 - if (clearFactory) _factory.clear(); 296 + // if (clearFactory) _factory.clear();
312 if (clearRouteBindings) _routesKey.clear(); 297 if (clearRouteBindings) _routesKey.clear();
313 _singl.clear(); 298 _singl.clear();
314 return true; 299 return true;
@@ -330,13 +315,13 @@ class GetInstance { @@ -330,13 +315,13 @@ class GetInstance {
330 /// - [key] For internal usage, is the processed key used to register 315 /// - [key] For internal usage, is the processed key used to register
331 /// the Instance. **don't use** it unless you know what you are doing. 316 /// the Instance. **don't use** it unless you know what you are doing.
332 /// - [force] Will delete an Instance even if marked as [permanent]. 317 /// - [force] Will delete an Instance even if marked as [permanent].
333 - bool delete<S>({String tag, String key, bool force = false}) { 318 + Future<bool> delete<S>({String tag, String key, bool force = false}) {
334 // return _queue.secure<bool>(() { 319 // return _queue.secure<bool>(() {
335 return _delete<S>(tag: tag, key: key, force: force); 320 return _delete<S>(tag: tag, key: key, force: force);
336 // }); 321 // });
337 } 322 }
338 323
339 - bool _delete<S>({String tag, String key, bool force = false}) { 324 + Future<bool> _delete<S>({String tag, String key, bool force = false}) async {
340 final newKey = key ?? _getKey(S, tag); 325 final newKey = key ?? _getKey(S, tag);
341 326
342 if (!_singl.containsKey(newKey)) { 327 if (!_singl.containsKey(newKey)) {
@@ -358,18 +343,20 @@ class GetInstance { @@ -358,18 +343,20 @@ class GetInstance {
358 if (i is GetxServiceMixin && !force) { 343 if (i is GetxServiceMixin && !force) {
359 return false; 344 return false;
360 } 345 }
361 - if (i is GetLifeCycle) {  
362 - i.onDelete();  
363 - Get.log('"$newKey" onClose() called');  
364 - } 346 + await Get.asap(() {
  347 + if (i is GetLifeCycle) {
  348 + i.onDelete();
  349 + Get.log('"$newKey" onClose() called');
  350 + }
365 351
366 - _singl.removeWhere((oldKey, value) => (oldKey == newKey));  
367 - if (_singl.containsKey(newKey)) {  
368 - Get.log('Error removing object "$newKey"', isError: true);  
369 - } else {  
370 - Get.log('"$newKey" deleted from memory');  
371 - }  
372 - // _routesKey?.remove(key); 352 + _singl.remove(newKey);
  353 +
  354 + if (_singl.containsKey(newKey)) {
  355 + Get.log('Error removing object "$newKey"', isError: true);
  356 + } else {
  357 + Get.log('"$newKey" deleted from memory');
  358 + }
  359 + });
373 return true; 360 return true;
374 } 361 }
375 362
@@ -380,7 +367,20 @@ class GetInstance { @@ -380,7 +367,20 @@ class GetInstance {
380 /// Checks if a lazy factory callback ([Get.lazyPut()] that returns an 367 /// Checks if a lazy factory callback ([Get.lazyPut()] that returns an
381 /// Instance<[S]> is registered in memory. 368 /// Instance<[S]> is registered in memory.
382 /// - [tag] is optional, if you used a [tag] to register the lazy Instance. 369 /// - [tag] is optional, if you used a [tag] to register the lazy Instance.
383 - bool isPrepared<S>({String tag}) => _factory.containsKey(_getKey(S, tag)); 370 + bool isPrepared<S>({String tag}) {
  371 + final newKey = _getKey(S, tag);
  372 +
  373 + if (!_singl.containsKey(newKey)) {
  374 + Get.log('Instance "$newKey" not found.', isError: true);
  375 + return false;
  376 + }
  377 +
  378 + final builder = _singl[newKey];
  379 + if (!builder.isInit) {
  380 + return true;
  381 + }
  382 + return false;
  383 + }
384 } 384 }
385 385
386 typedef InstanceBuilderCallback<S> = S Function(); 386 typedef InstanceBuilderCallback<S> = S Function();
@@ -420,13 +420,3 @@ class _InstanceBuilderFactory<S> { @@ -420,13 +420,3 @@ class _InstanceBuilderFactory<S> {
420 return isSingleton ? dependency ??= builderFunc() : builderFunc(); 420 return isSingleton ? dependency ??= builderFunc() : builderFunc();
421 } 421 }
422 } 422 }
423 -  
424 -/// Internal class to register a future instance with [lazyPut],  
425 -/// keeps a reference to the callback to be called.  
426 -class _Lazy {  
427 - bool fenix;  
428 - bool permanent = false;  
429 - InstanceBuilderCallback builder;  
430 -  
431 - _Lazy(this.builder, this.fenix);  
432 -}  
@@ -384,14 +384,14 @@ class GetPageRoute<T> extends PageRoute<T> { @@ -384,14 +384,14 @@ class GetPageRoute<T> extends PageRoute<T> {
384 384
385 @override 385 @override
386 void dispose() { 386 void dispose() {
387 - super.dispose();  
388 // if (Get.smartManagement != SmartManagement.onlyBuilder) { 387 // if (Get.smartManagement != SmartManagement.onlyBuilder) {
389 // WidgetsBinding.instance.addPostFrameCallback((_) => GetInstance() 388 // WidgetsBinding.instance.addPostFrameCallback((_) => GetInstance()
390 // .removeDependencyByRoute("${settings?.name ?? routeName}")); 389 // .removeDependencyByRoute("${settings?.name ?? routeName}"));
391 // } 390 // }
  391 +
  392 + super.dispose();
392 if (Get.smartManagement != SmartManagement.onlyBuilder) { 393 if (Get.smartManagement != SmartManagement.onlyBuilder) {
393 - WidgetsBinding.instance.addPostFrameCallback(  
394 - (_) => GetInstance().removeDependencyByRoute("$reference")); 394 + GetInstance().removeDependencyByRoute("$reference");
395 } 395 }
396 396
397 final middlewareRunner = MiddlewareRunner(middlewares); 397 final middlewareRunner = MiddlewareRunner(middlewares);
@@ -56,7 +56,12 @@ class GetStream<T> { @@ -56,7 +56,12 @@ class GetStream<T> {
56 var itemsToRemove = <LightSubscription<T>>[]; 56 var itemsToRemove = <LightSubscription<T>>[];
57 for (final item in _onData) { 57 for (final item in _onData) {
58 if (!item.isPaused) { 58 if (!item.isPaused) {
59 - item._onError?.call(error, stackTrace); 59 + if (stackTrace != null) {
  60 + item._onError?.call(error, stackTrace);
  61 + } else {
  62 + item._onError?.call(error);
  63 + }
  64 +
60 if (item.cancelOnError) { 65 if (item.cancelOnError) {
61 //item.cancel?.call(); 66 //item.cancel?.call();
62 itemsToRemove.add(item); 67 itemsToRemove.add(item);
@@ -147,7 +152,7 @@ class LightSubscription<T> extends StreamSubscription<T> { @@ -147,7 +152,7 @@ class LightSubscription<T> extends StreamSubscription<T> {
147 152
148 OnData<T> _data; 153 OnData<T> _data;
149 154
150 - dynamic _onError; 155 + Function _onError;
151 156
152 Callback _onDone; 157 Callback _onDone;
153 158
@@ -166,6 +166,10 @@ abstract class _RxImpl<T> extends RxNotifier<T> with RxObjectMixin<T> { @@ -166,6 +166,10 @@ abstract class _RxImpl<T> extends RxNotifier<T> with RxObjectMixin<T> {
166 _value = initial; 166 _value = initial;
167 } 167 }
168 168
  169 + void addError(Object error, [StackTrace stackTrace]) {
  170 + subject.addError(error, stackTrace);
  171 + }
  172 +
169 Stream<R> map<R>(R mapper(T data)) => stream.map(mapper); 173 Stream<R> map<R>(R mapper(T data)) => stream.map(mapper);
170 174
171 /// Uses a callback to update [value] internally, similar to [refresh], 175 /// Uses a callback to update [value] internally, similar to [refresh],
@@ -198,6 +202,10 @@ abstract class _RxImpl<T> extends RxNotifier<T> with RxObjectMixin<T> { @@ -198,6 +202,10 @@ abstract class _RxImpl<T> extends RxNotifier<T> with RxObjectMixin<T> {
198 class RxBool extends _RxImpl<bool> { 202 class RxBool extends _RxImpl<bool> {
199 RxBool([bool initial]) : super(initial); 203 RxBool([bool initial]) : super(initial);
200 204
  205 + bool get isTrue => value;
  206 +
  207 + bool get isfalse => !isTrue;
  208 +
201 bool operator &(bool other) => other && value; 209 bool operator &(bool other) => other && value;
202 210
203 bool operator |(bool other) => other || value; 211 bool operator |(bool other) => other || value;
@@ -221,10 +229,134 @@ class RxBool extends _RxImpl<bool> { @@ -221,10 +229,134 @@ class RxBool extends _RxImpl<bool> {
221 } 229 }
222 230
223 /// Rx class for `String` Type. 231 /// Rx class for `String` Type.
224 -class RxString extends _RxImpl<String> { 232 +class RxString extends _RxImpl<String> implements Comparable<String>, Pattern {
225 RxString([String initial]) : super(initial); 233 RxString([String initial]) : super(initial);
226 234
227 String operator +(String val) => _value + val; 235 String operator +(String val) => _value + val;
  236 +
  237 + /// Compares this string to [other].
  238 + @override
  239 + int compareTo(String other) {
  240 + return value.compareTo(other);
  241 + }
  242 +
  243 + /// Returns true if this string ends with [other]. For example:
  244 + ///
  245 + /// 'Dart'.endsWith('t'); // true
  246 + bool endsWith(String other) {
  247 + return value.endsWith(other);
  248 + }
  249 +
  250 + /// Returns true if this string starts with a match of [pattern].
  251 + bool startsWith(Pattern pattern, [int index = 0]) {
  252 + return value.startsWith(pattern, index);
  253 + }
  254 +
  255 + /// Returns the position of the first match of [pattern] in this string
  256 + int indexOf(Pattern pattern, [int start = 0]) {
  257 + return value.indexOf(pattern, start);
  258 + }
  259 +
  260 + /// Returns the starting position of the last match [pattern] in this string,
  261 + /// searching backward starting at [start], inclusive:
  262 + int lastIndexOf(Pattern pattern, [int start]) {
  263 + return value.lastIndexOf(pattern, start);
  264 + }
  265 +
  266 + /// Returns true if this string is empty.
  267 + bool get isEmpty => value.isEmpty;
  268 +
  269 + /// Returns true if this string is not empty.
  270 + bool get isNotEmpty => !isEmpty;
  271 +
  272 + /// Returns the substring of this string that extends from [startIndex],
  273 + /// inclusive, to [endIndex], exclusive
  274 + String substring(int startIndex, [int endIndex]) {
  275 + return value.substring(startIndex, endIndex);
  276 + }
  277 +
  278 + /// Returns the string without any leading and trailing whitespace.
  279 + String trim() {
  280 + return value.trim();
  281 + }
  282 +
  283 + /// Returns the string without any leading whitespace.
  284 + ///
  285 + /// As [trim], but only removes leading whitespace.
  286 + String trimLeft() {
  287 + return value.trimLeft();
  288 + }
  289 +
  290 + /// Returns the string without any trailing whitespace.
  291 + ///
  292 + /// As [trim], but only removes trailing whitespace.
  293 + String trimRight() {
  294 + return value.trimRight();
  295 + }
  296 +
  297 + /// Pads this string on the left if it is shorter than [width].
  298 + ///
  299 + /// Return a new string that prepends [padding] onto this string
  300 + /// one time for each position the length is less than [width].
  301 + String padLeft(int width, [String padding = ' ']) {
  302 + return value.padLeft(width, padding);
  303 + }
  304 +
  305 + /// Pads this string on the right if it is shorter than [width].
  306 +
  307 + /// Return a new string that appends [padding] after this string
  308 + /// one time for each position the length is less than [width].
  309 + String padRight(int width, [String padding = ' ']) {
  310 + return value.padRight(width, padding);
  311 + }
  312 +
  313 + /// Returns true if this string contains a match of [other]:
  314 + bool contains(Pattern other, [int startIndex = 0]) {
  315 + return value.contains(other, startIndex);
  316 + }
  317 +
  318 + /// Replaces all substrings that match [from] with [replace].
  319 + String replaceAll(Pattern from, String replace) {
  320 + return value.replaceAll(from, replace);
  321 + }
  322 +
  323 + /// Splits the string at matches of [pattern] and returns a list
  324 + /// of substrings.
  325 + List<String> split(Pattern pattern) {
  326 + return value.split(pattern);
  327 + }
  328 +
  329 + /// Returns an unmodifiable list of the UTF-16 code units of this string.
  330 + List<int> get codeUnits => value.codeUnits;
  331 +
  332 + /// Returns an [Iterable] of Unicode code-points of this string.
  333 + ///
  334 + /// If the string contains surrogate pairs, they are combined and returned
  335 + /// as one integer by this iterator. Unmatched surrogate halves are treated
  336 + /// like valid 16-bit code-units.
  337 + Runes get runes => value.runes;
  338 +
  339 + /// Converts all characters in this string to lower case.
  340 + /// If the string is already in all lower case, this method returns `this`.
  341 + String toLowerCase() {
  342 + return value.toLowerCase();
  343 + }
  344 +
  345 + /// Converts all characters in this string to upper case.
  346 + /// If the string is already in all upper case, this method returns `this`.
  347 + String toUpperCase() {
  348 + return value.toUpperCase();
  349 + }
  350 +
  351 + @override
  352 + Iterable<Match> allMatches(String string, [int start = 0]) {
  353 + return value.allMatches(string, start);
  354 + }
  355 +
  356 + @override
  357 + Match matchAsPrefix(String string, [int start = 0]) {
  358 + return value.matchAsPrefix(string, start);
  359 + }
228 } 360 }
229 361
230 /// Foundation class used for custom `Types` outside the common native Dart 362 /// Foundation class used for custom `Types` outside the common native Dart
@@ -10,6 +10,35 @@ class RxList<E> extends ListMixin<E> @@ -10,6 +10,35 @@ class RxList<E> extends ListMixin<E>
10 } 10 }
11 } 11 }
12 12
  13 + factory RxList.filled(int length, E fill, {bool growable = false}) {
  14 + return RxList(List.filled(length, fill, growable: growable));
  15 + }
  16 +
  17 + factory RxList.empty({bool growable = false}) {
  18 + return RxList(List.empty(growable: growable));
  19 + }
  20 +
  21 + /// Creates a list containing all [elements].
  22 + factory RxList.from(Iterable elements, {bool growable = true}) {
  23 + return RxList(List.from(elements, growable: growable));
  24 + }
  25 +
  26 + /// Creates a list from [elements].
  27 + factory RxList.of(Iterable<E> elements, {bool growable = true}) {
  28 + return RxList(List.of(elements, growable: growable));
  29 + }
  30 +
  31 + /// Generates a list of values.
  32 + factory RxList.generate(int length, E generator(int index),
  33 + {bool growable = true}) {
  34 + return RxList(List.generate(length, generator, growable: growable));
  35 + }
  36 +
  37 + /// Creates an unmodifiable list containing all [elements].
  38 + factory RxList.unmodifiable(Iterable elements) {
  39 + return RxList(List.unmodifiable(elements));
  40 + }
  41 +
13 @override 42 @override
14 Iterator<E> get iterator => value.iterator; 43 Iterator<E> get iterator => value.iterator;
15 44
@@ -136,10 +165,6 @@ class RxList<E> extends ListMixin<E> @@ -136,10 +165,6 @@ class RxList<E> extends ListMixin<E>
136 165
137 extension ListExtension<E> on List<E> { 166 extension ListExtension<E> on List<E> {
138 RxList<E> get obs { 167 RxList<E> get obs {
139 - if (this != null) {  
140 - return RxList<E>(this);  
141 - } else {  
142 - return RxList<E>(null);  
143 - } 168 + return RxList<E>(this);
144 } 169 }
145 } 170 }
@@ -9,6 +9,25 @@ class RxMap<K, V> extends MapMixin<K, V> @@ -9,6 +9,25 @@ class RxMap<K, V> extends MapMixin<K, V>
9 } 9 }
10 } 10 }
11 11
  12 + factory RxMap.from(Map<K, V> other) {
  13 + return RxMap(Map.from(other));
  14 + }
  15 +
  16 + /// Creates a [LinkedHashMap] with the same keys and values as [other].
  17 + factory RxMap.of(Map<K, V> other) {
  18 + return RxMap(Map.of(other));
  19 + }
  20 +
  21 + ///Creates an unmodifiable hash based map containing the entries of [other].
  22 + factory RxMap.unmodifiable(Map<dynamic, dynamic> other) {
  23 + return RxMap(Map.unmodifiable(other));
  24 + }
  25 +
  26 + /// Creates an identity map with the default implementation, [LinkedHashMap].
  27 + factory RxMap.identity() {
  28 + return RxMap(Map.identity());
  29 + }
  30 +
12 @override 31 @override
13 V operator [](Object key) { 32 V operator [](Object key) {
14 return value[key]; 33 return value[key];
@@ -43,11 +43,22 @@ typedef WorkerCallback<T> = Function(T callback); @@ -43,11 +43,22 @@ typedef WorkerCallback<T> = Function(T callback);
43 /// void increment() => count + 1; 43 /// void increment() => count + 1;
44 /// } 44 /// }
45 /// ``` 45 /// ```
46 -Worker ever<T>(RxInterface<T> listener, WorkerCallback<T> callback,  
47 - {dynamic condition = true}) {  
48 - StreamSubscription sub = listener.listen((event) {  
49 - if (_conditional(condition)) callback(event);  
50 - }); 46 +Worker ever<T>(
  47 + RxInterface<T> listener,
  48 + WorkerCallback<T> callback, {
  49 + dynamic condition = true,
  50 + Function onError,
  51 + void Function() onDone,
  52 + bool cancelOnError,
  53 +}) {
  54 + StreamSubscription sub = listener.listen(
  55 + (event) {
  56 + if (_conditional(condition)) callback(event);
  57 + },
  58 + onError: onError,
  59 + onDone: onDone,
  60 + cancelOnError: cancelOnError,
  61 + );
51 return Worker(sub.cancel, '[ever]'); 62 return Worker(sub.cancel, '[ever]');
52 } 63 }
53 64
@@ -55,13 +66,24 @@ Worker ever<T>(RxInterface<T> listener, WorkerCallback<T> callback, @@ -55,13 +66,24 @@ Worker ever<T>(RxInterface<T> listener, WorkerCallback<T> callback,
55 /// for the [callback] is common to all [listeners], 66 /// for the [callback] is common to all [listeners],
56 /// and the [callback] is executed to each one of them. The [Worker] is 67 /// and the [callback] is executed to each one of them. The [Worker] is
57 /// common to all, so [worker.dispose()] will cancel all streams. 68 /// common to all, so [worker.dispose()] will cancel all streams.
58 -Worker everAll(List<RxInterface> listeners, WorkerCallback callback,  
59 - {dynamic condition = true}) { 69 +Worker everAll(
  70 + List<RxInterface> listeners,
  71 + WorkerCallback callback, {
  72 + dynamic condition = true,
  73 + Function onError,
  74 + void Function() onDone,
  75 + bool cancelOnError,
  76 +}) {
60 final evers = <StreamSubscription>[]; 77 final evers = <StreamSubscription>[];
61 for (var i in listeners) { 78 for (var i in listeners) {
62 - final sub = i.listen((event) {  
63 - if (_conditional(condition)) callback(event);  
64 - }); 79 + final sub = i.listen(
  80 + (event) {
  81 + if (_conditional(condition)) callback(event);
  82 + },
  83 + onError: onError,
  84 + onDone: onDone,
  85 + cancelOnError: cancelOnError,
  86 + );
65 evers.add(sub); 87 evers.add(sub);
66 } 88 }
67 89
@@ -96,17 +118,28 @@ Worker everAll(List<RxInterface> listeners, WorkerCallback callback, @@ -96,17 +118,28 @@ Worker everAll(List<RxInterface> listeners, WorkerCallback callback,
96 /// void increment() => count + 1; 118 /// void increment() => count + 1;
97 /// } 119 /// }
98 ///``` 120 ///```
99 -Worker once<T>(RxInterface<T> listener, WorkerCallback<T> callback,  
100 - {dynamic condition}) { 121 +Worker once<T>(
  122 + RxInterface<T> listener,
  123 + WorkerCallback<T> callback, {
  124 + dynamic condition = true,
  125 + Function onError,
  126 + void Function() onDone,
  127 + bool cancelOnError,
  128 +}) {
101 Worker ref; 129 Worker ref;
102 StreamSubscription sub; 130 StreamSubscription sub;
103 - sub = listener.listen((event) {  
104 - if (!_conditional(condition)) return;  
105 - ref._disposed = true;  
106 - ref._log('called');  
107 - sub?.cancel();  
108 - callback(event);  
109 - }); 131 + sub = listener.listen(
  132 + (event) {
  133 + if (!_conditional(condition)) return;
  134 + ref._disposed = true;
  135 + ref._log('called');
  136 + sub?.cancel();
  137 + callback(event);
  138 + },
  139 + onError: onError,
  140 + onDone: onDone,
  141 + cancelOnError: cancelOnError,
  142 + );
110 ref = Worker(sub.cancel, '[once]'); 143 ref = Worker(sub.cancel, '[once]');
111 return ref; 144 return ref;
112 } 145 }
@@ -128,17 +161,29 @@ Worker once<T>(RxInterface<T> listener, WorkerCallback<T> callback, @@ -128,17 +161,29 @@ Worker once<T>(RxInterface<T> listener, WorkerCallback<T> callback,
128 /// condition: () => count < 20, 161 /// condition: () => count < 20,
129 /// ); 162 /// );
130 /// ``` 163 /// ```
131 -Worker interval<T>(RxInterface<T> listener, WorkerCallback<T> callback,  
132 - {Duration time = const Duration(seconds: 1), dynamic condition = true}) { 164 +Worker interval<T>(
  165 + RxInterface<T> listener,
  166 + WorkerCallback<T> callback, {
  167 + Duration time = const Duration(seconds: 1),
  168 + dynamic condition = true,
  169 + Function onError,
  170 + void Function() onDone,
  171 + bool cancelOnError,
  172 +}) {
133 var debounceActive = false; 173 var debounceActive = false;
134 time ??= const Duration(seconds: 1); 174 time ??= const Duration(seconds: 1);
135 - StreamSubscription sub = listener.listen((event) async {  
136 - if (debounceActive || !_conditional(condition)) return;  
137 - debounceActive = true;  
138 - await Future.delayed(time);  
139 - debounceActive = false;  
140 - callback(event);  
141 - }); 175 + StreamSubscription sub = listener.listen(
  176 + (event) async {
  177 + if (debounceActive || !_conditional(condition)) return;
  178 + debounceActive = true;
  179 + await Future.delayed(time);
  180 + debounceActive = false;
  181 + callback(event);
  182 + },
  183 + onError: onError,
  184 + onDone: onDone,
  185 + cancelOnError: cancelOnError,
  186 + );
142 return Worker(sub.cancel, '[interval]'); 187 return Worker(sub.cancel, '[interval]');
143 } 188 }
144 189
@@ -161,15 +206,26 @@ Worker interval<T>(RxInterface<T> listener, WorkerCallback<T> callback, @@ -161,15 +206,26 @@ Worker interval<T>(RxInterface<T> listener, WorkerCallback<T> callback,
161 /// ); 206 /// );
162 /// } 207 /// }
163 /// ``` 208 /// ```
164 -Worker debounce<T>(RxInterface<T> listener, WorkerCallback<T> callback,  
165 - {Duration time}) { 209 +Worker debounce<T>(
  210 + RxInterface<T> listener,
  211 + WorkerCallback<T> callback, {
  212 + Duration time,
  213 + Function onError,
  214 + void Function() onDone,
  215 + bool cancelOnError,
  216 +}) {
166 final _debouncer = 217 final _debouncer =
167 Debouncer(delay: time ?? const Duration(milliseconds: 800)); 218 Debouncer(delay: time ?? const Duration(milliseconds: 800));
168 - StreamSubscription sub = listener.listen((event) {  
169 - _debouncer(() {  
170 - callback(event);  
171 - });  
172 - }); 219 + StreamSubscription sub = listener.listen(
  220 + (event) {
  221 + _debouncer(() {
  222 + callback(event);
  223 + });
  224 + },
  225 + onError: onError,
  226 + onDone: onDone,
  227 + cancelOnError: cancelOnError,
  228 + );
173 return Worker(sub.cancel, '[debounce]'); 229 return Worker(sub.cancel, '[debounce]');
174 } 230 }
175 231
@@ -183,6 +239,8 @@ class Worker { @@ -183,6 +239,8 @@ class Worker {
183 final String type; 239 final String type;
184 bool _disposed = false; 240 bool _disposed = false;
185 241
  242 + bool get disposed => _disposed;
  243 +
186 //final bool _verbose = true; 244 //final bool _verbose = true;
187 void _log(String msg) { 245 void _log(String msg) {
188 // if (!_verbose) return; 246 // if (!_verbose) return;
@@ -53,18 +53,17 @@ class GetXState<T extends DisposableInterface> extends State<GetX<T>> { @@ -53,18 +53,17 @@ class GetXState<T extends DisposableInterface> extends State<GetX<T>> {
53 53
54 @override 54 @override
55 void initState() { 55 void initState() {
56 - var isPrepared = GetInstance().isPrepared<T>(tag: widget.tag); 56 + // var isPrepared = GetInstance().isPrepared<T>(tag: widget.tag);
57 var isRegistered = GetInstance().isRegistered<T>(tag: widget.tag); 57 var isRegistered = GetInstance().isRegistered<T>(tag: widget.tag);
58 58
59 if (widget.global) { 59 if (widget.global) {
60 - if (isPrepared) {  
61 - if (Get.smartManagement != SmartManagement.keepFactory) { 60 + if (isRegistered) {
  61 + if (GetInstance().isPrepared<T>(tag: widget.tag)) {
62 isCreator = true; 62 isCreator = true;
  63 + } else {
  64 + isCreator = false;
63 } 65 }
64 controller = GetInstance().find<T>(tag: widget.tag); 66 controller = GetInstance().find<T>(tag: widget.tag);
65 - } else if (isRegistered) {  
66 - controller = GetInstance().find<T>(tag: widget.tag);  
67 - isCreator = false;  
68 } else { 67 } else {
69 controller = widget.init; 68 controller = widget.init;
70 isCreator = true; 69 isCreator = true;
@@ -75,7 +74,7 @@ class GetXState<T extends DisposableInterface> extends State<GetX<T>> { @@ -75,7 +74,7 @@ class GetXState<T extends DisposableInterface> extends State<GetX<T>> {
75 isCreator = true; 74 isCreator = true;
76 controller?.onStart(); 75 controller?.onStart();
77 } 76 }
78 - if (widget.initState != null) widget.initState(this); 77 + widget.initState?.call(this);
79 if (widget.global && Get.smartManagement == SmartManagement.onlyBuilder) { 78 if (widget.global && Get.smartManagement == SmartManagement.onlyBuilder) {
80 controller?.onStart(); 79 controller?.onStart();
81 } 80 }
@@ -29,10 +29,16 @@ class _ObxState extends State<ObxWidget> { @@ -29,10 +29,16 @@ class _ObxState extends State<ObxWidget> {
29 29
30 @override 30 @override
31 void initState() { 31 void initState() {
32 - subs = _observer.listen((data) => setState(() {})); 32 + subs = _observer.listen(_updateTree);
33 super.initState(); 33 super.initState();
34 } 34 }
35 35
  36 + void _updateTree(_) {
  37 + if (mounted) {
  38 + setState(() {});
  39 + }
  40 + }
  41 +
36 @override 42 @override
37 void dispose() { 43 void dispose() {
38 subs.cancel(); 44 subs.cancel();
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
2 -import '../../../get_core/get_core.dart';  
3 import '../../../get_instance/src/get_instance.dart'; 2 import '../../../get_instance/src/get_instance.dart';
4 import '../../get_state_manager.dart'; 3 import '../../get_state_manager.dart';
5 import 'list_notifier.dart'; 4 import 'list_notifier.dart';
@@ -89,19 +88,18 @@ class _GetBuilderState<T extends GetxController> extends State<GetBuilder<T>> @@ -89,19 +88,18 @@ class _GetBuilderState<T extends GetxController> extends State<GetBuilder<T>>
89 void initState() { 88 void initState() {
90 super.initState(); 89 super.initState();
91 90
92 - if (widget.initState != null) widget.initState(this);  
93 - if (widget.global) {  
94 - final isPrepared = GetInstance().isPrepared<T>(tag: widget.tag);  
95 - final isRegistered = GetInstance().isRegistered<T>(tag: widget.tag); 91 + widget.initState?.call(this);
  92 +
  93 + var isRegistered = GetInstance().isRegistered<T>(tag: widget.tag);
96 94
97 - if (isPrepared) {  
98 - if (Get.smartManagement != SmartManagement.keepFactory) { 95 + if (widget.global) {
  96 + if (isRegistered) {
  97 + if (GetInstance().isPrepared<T>(tag: widget.tag)) {
99 isCreator = true; 98 isCreator = true;
  99 + } else {
  100 + isCreator = false;
100 } 101 }
101 controller = GetInstance().find<T>(tag: widget.tag); 102 controller = GetInstance().find<T>(tag: widget.tag);
102 - } else if (isRegistered) {  
103 - controller = GetInstance().find<T>(tag: widget.tag);  
104 - isCreator = false;  
105 } else { 103 } else {
106 controller = widget.init; 104 controller = widget.init;
107 isCreator = true; 105 isCreator = true;
@@ -160,36 +158,3 @@ class _GetBuilderState<T extends GetxController> extends State<GetBuilder<T>> @@ -160,36 +158,3 @@ class _GetBuilderState<T extends GetxController> extends State<GetBuilder<T>>
160 @override 158 @override
161 Widget build(BuildContext context) => widget.builder(controller); 159 Widget build(BuildContext context) => widget.builder(controller);
162 } 160 }
163 -  
164 -/// It's Experimental class, the Api can be change  
165 -abstract class GetState<T> extends GetxController {  
166 - GetState(T initialValue) {  
167 - _state = initialValue;  
168 - }  
169 -  
170 - // StreamController<T> _subject;  
171 -  
172 - // @override  
173 - // void onClose() {  
174 - // _subject?.close();  
175 - // }  
176 -  
177 - // Stream<T> get stream {  
178 - // if (_subject == null) {  
179 - // _subject = StreamController<T>.broadcast();  
180 - // }  
181 - // return _subject.stream;  
182 - // }  
183 -  
184 - T _state;  
185 -  
186 - T get state => _state;  
187 -  
188 - @protected  
189 - void change(T newState) {  
190 - if (newState != _state) {  
191 - _state = newState;  
192 - update();  
193 - }  
194 - }  
195 -}  
1 import 'package:flutter/widgets.dart'; 1 import 'package:flutter/widgets.dart';
2 -import '../../../get_instance/src/get_instance.dart'; 2 +
3 import '../../../instance_manager.dart'; 3 import '../../../instance_manager.dart';
  4 +import '../../../utils.dart';
4 import 'get_widget_cache.dart'; 5 import 'get_widget_cache.dart';
5 6
6 /// GetView is a great way of quickly access your Controller 7 /// GetView is a great way of quickly access your Controller
@@ -40,25 +41,6 @@ abstract class GetView<T> extends StatelessWidget { @@ -40,25 +41,6 @@ abstract class GetView<T> extends StatelessWidget {
40 Widget build(BuildContext context); 41 Widget build(BuildContext context);
41 } 42 }
42 43
43 -// abstract class GetView<A, B> extends StatelessWidget {  
44 -// const GetView({Key key}) : super(key: key);  
45 -// A get controller => GetInstance().find();  
46 -// B get controller2 => GetInstance().find();  
47 -  
48 -// @override  
49 -// Widget build(BuildContext context);  
50 -// }  
51 -  
52 -// abstract class GetView2<A, B, C> extends StatelessWidget {  
53 -// const GetView2({Key key}) : super(key: key);  
54 -// A get controller => GetInstance().find();  
55 -// B get controller2 => GetInstance().find();  
56 -// C get controller3 => GetInstance().find();  
57 -  
58 -// @override  
59 -// Widget build(BuildContext context);  
60 -// }  
61 -  
62 /// GetWidget is a great way of quickly access your individual Controller 44 /// GetWidget is a great way of quickly access your individual Controller
63 /// without having to call Get.find<AwesomeController>() yourself. 45 /// without having to call Get.find<AwesomeController>() yourself.
64 /// Get save you controller on cache, so, you can to use Get.create() safely 46 /// Get save you controller on cache, so, you can to use Get.create() safely
@@ -73,7 +55,9 @@ abstract class GetWidget<S extends GetLifeCycleBase> extends GetWidgetCache { @@ -73,7 +55,9 @@ abstract class GetWidget<S extends GetLifeCycleBase> extends GetWidgetCache {
73 55
74 S get controller => GetWidget._cache[this] as S; 56 S get controller => GetWidget._cache[this] as S;
75 57
76 - static final _cache = <GetWidget, GetLifeCycleBase>{}; 58 + // static final _cache = <GetWidget, GetLifeCycleBase>{};
  59 +
  60 + static final _cache = Expando<GetLifeCycleBase>();
77 61
78 @protected 62 @protected
79 Widget build(BuildContext context); 63 Widget build(BuildContext context);
@@ -84,8 +68,10 @@ abstract class GetWidget<S extends GetLifeCycleBase> extends GetWidgetCache { @@ -84,8 +68,10 @@ abstract class GetWidget<S extends GetLifeCycleBase> extends GetWidgetCache {
84 68
85 class _GetCache<S extends GetLifeCycleBase> extends WidgetCache<GetWidget<S>> { 69 class _GetCache<S extends GetLifeCycleBase> extends WidgetCache<GetWidget<S>> {
86 S _controller; 70 S _controller;
  71 + bool _isCreator = false;
87 @override 72 @override
88 void onInit() { 73 void onInit() {
  74 + _isCreator = Get.isPrepared<S>(tag: widget.tag);
89 _controller = Get.find<S>(tag: widget.tag); 75 _controller = Get.find<S>(tag: widget.tag);
90 GetWidget._cache[widget] = _controller; 76 GetWidget._cache[widget] = _controller;
91 super.onInit(); 77 super.onInit();
@@ -93,7 +79,14 @@ class _GetCache<S extends GetLifeCycleBase> extends WidgetCache<GetWidget<S>> { @@ -93,7 +79,14 @@ class _GetCache<S extends GetLifeCycleBase> extends WidgetCache<GetWidget<S>> {
93 79
94 @override 80 @override
95 void onClose() { 81 void onClose() {
96 - GetWidget._cache.remove(widget); 82 + if (_isCreator) {
  83 + Get.asap(() {
  84 + widget.controller.onDelete();
  85 + Get.log('"${widget.controller.runtimeType}" onClose() called');
  86 + Get.log('"${widget.controller.runtimeType}" deleted from memory');
  87 + GetWidget._cache[widget] = null;
  88 + });
  89 + }
97 super.onClose(); 90 super.onClose();
98 } 91 }
99 92
1 import '../get_utils/get_utils.dart'; 1 import '../get_utils/get_utils.dart';
2 2
3 -extension GetDynamicUtils on dynamic { 3 +extension GetDynamicUtils<T> on T {
4 @Deprecated('isNull is deprecated and cannot be used, use "==" operator') 4 @Deprecated('isNull is deprecated and cannot be used, use "==" operator')
5 bool get isNull => GetUtils.isNull(this); 5 bool get isNull => GetUtils.isNull(this);
6 6
@@ -103,12 +103,13 @@ void main() { @@ -103,12 +103,13 @@ void main() {
103 tearDownAll(Get.reset); 103 tearDownAll(Get.reset);
104 104
105 test('Get.put test with init check', () async { 105 test('Get.put test with init check', () async {
106 - final instance = Get.put<DisposableController>(DisposableController()); 106 + final instance = Get.put(DisposableController());
107 expect(instance, Get.find<DisposableController>()); 107 expect(instance, Get.find<DisposableController>());
108 expect(instance.initialized, true); 108 expect(instance.initialized, true);
109 }); 109 });
110 110
111 test('Get.delete test with disposable controller', () async { 111 test('Get.delete test with disposable controller', () async {
  112 + // Get.put(DisposableController());
112 expect(await Get.delete<DisposableController>(), true); 113 expect(await Get.delete<DisposableController>(), true);
113 expect(() => Get.find<DisposableController>(), 114 expect(() => Get.find<DisposableController>(),
114 throwsA(m.TypeMatcher<String>())); 115 throwsA(m.TypeMatcher<String>()));