Renat Fakhrutdinov
Committed by GitHub

Merge pull request #14 from jonataslaw/master

Update
@@ -3,12 +3,11 @@ name: build @@ -3,12 +3,11 @@ name: build
3 # Trigger the workflow on push or pull request 3 # Trigger the workflow on push or pull request
4 on: 4 on:
5 push: 5 push:
6 - branches: [ master ] 6 + branches: [master]
7 pull_request: 7 pull_request:
8 - branches: [ master ] 8 + branches: [master]
9 #A workflow run is made up of one or more jobs. Jobs run in parallel by default. 9 #A workflow run is made up of one or more jobs. Jobs run in parallel by default.
10 jobs: 10 jobs:
11 -  
12 test: 11 test:
13 #The type of machine to run the job on. [windows,macos, ubuntu , self-hosted] 12 #The type of machine to run the job on. [windows,macos, ubuntu , self-hosted]
14 defaults: 13 defaults:
@@ -24,8 +23,8 @@ jobs: @@ -24,8 +23,8 @@ jobs:
24 # https://github.com/marketplace/actions/flutter-action 23 # https://github.com/marketplace/actions/flutter-action
25 - uses: subosito/flutter-action@v1 24 - uses: subosito/flutter-action@v1
26 with: 25 with:
27 - flutter-version: '1.20.4'  
28 - channel: 'stable' 26 + flutter-version: "1.22.2"
  27 + channel: "stable"
29 - run: flutter pub get 28 - run: flutter pub get
30 #- run: flutter analyze 29 #- run: flutter analyze
31 # run flutter widgets tests and unit tests 30 # run flutter widgets tests and unit tests
@@ -33,4 +32,3 @@ jobs: @@ -33,4 +32,3 @@ jobs:
33 # Upload coverage reports to Codecov 32 # Upload coverage reports to Codecov
34 # https://github.com/marketplace/actions/codecov 33 # https://github.com/marketplace/actions/codecov
35 - uses: codecov/codecov-action@v1.0.7 34 - uses: codecov/codecov-action@v1.0.7
36 -  
@@ -19,7 +19,10 @@ class HomeController extends GetxController { @@ -19,7 +19,10 @@ class HomeController extends GetxController {
19 19
20 /// When the controller is initialized, make the http request 20 /// When the controller is initialized, make the http request
21 @override 21 @override
22 - void onInit() => fetchDataFromApi(); 22 + void onInit() {
  23 + super.onInit();
  24 + fetchDataFromApi();
  25 + }
23 26
24 /// fetch cases from Api 27 /// fetch cases from Api
25 Future<void> fetchDataFromApi() async { 28 Future<void> fetchDataFromApi() async {
@@ -170,7 +170,9 @@ class Controller extends GetxController { @@ -170,7 +170,9 @@ class Controller extends GetxController {
170 super.onReady(); 170 super.onReady();
171 } 171 }
172 172
  173 + @override
173 void onClose() { 174 void onClose() {
  175 + super.onClose();
174 print('onClose'); 176 print('onClose');
175 } 177 }
176 } 178 }
@@ -5,3 +5,5 @@ export 'src/get_main.dart'; @@ -5,3 +5,5 @@ export 'src/get_main.dart';
5 export 'src/log.dart'; 5 export 'src/log.dart';
6 6
7 export 'src/smart_management.dart'; 7 export 'src/smart_management.dart';
  8 +
  9 +export 'src/typedefs.dart';
  1 +typedef ValueUpdater<T> = T Function();
  1 +import 'package:meta/meta.dart';
  2 +import '../../get_core/get_core.dart';
  3 +
1 /// Special callable class to keep the contract of a regular method, and avoid 4 /// Special callable class to keep the contract of a regular method, and avoid
2 /// overrides if you extend the class that uses it, as Dart has no final 5 /// overrides if you extend the class that uses it, as Dart has no final
3 /// methods. 6 /// methods.
4 /// Used in [DisposableInterface] to avoid the danger of overriding onStart. 7 /// Used in [DisposableInterface] to avoid the danger of overriding onStart.
5 -///  
6 class _InternalFinalCallback<T> { 8 class _InternalFinalCallback<T> {
7 - T Function() callback; 9 + ValueUpdater<T> _callback;
8 10
9 - _InternalFinalCallback(); 11 + _InternalFinalCallback({ValueUpdater<T> callback}) : _callback = callback;
10 12
11 - T call() => callback.call(); 13 + T call() => _callback.call();
12 } 14 }
13 15
  16 +/// The [GetLifeCycle]
  17 +///
  18 +/// ```dart
  19 +/// class SomeController with GetLifeCycle {
  20 +/// SomeController() {
  21 +/// initLifeCycle();
  22 +/// }
  23 +/// }
  24 +/// ```
14 mixin GetLifeCycle { 25 mixin GetLifeCycle {
  26 + /// The `initLifeCycle` works as a constructor for the [GetLifeCycle]
  27 + ///
  28 + /// This method must be invoked in the constructor of the implementation
  29 + void initLifeCycle() {
  30 + onStart._callback = _onStart;
  31 + onDelete._callback = _onDelete;
  32 + }
  33 +
15 /// Called at the exact moment the widget is allocated in memory. 34 /// Called at the exact moment the widget is allocated in memory.
16 /// It uses an internal "callable" type, to avoid any @overrides in subclases. 35 /// It uses an internal "callable" type, to avoid any @overrides in subclases.
17 /// This method should be internal and is required to define the 36 /// This method should be internal and is required to define the
18 /// lifetime cycle of the subclass. 37 /// lifetime cycle of the subclass.
19 final onStart = _InternalFinalCallback<void>(); 38 final onStart = _InternalFinalCallback<void>();
20 39
  40 + /// Internal callback that starts the cycle of this controller.
21 final onDelete = _InternalFinalCallback<void>(); 41 final onDelete = _InternalFinalCallback<void>();
22 42
23 /// Called immediately after the widget is allocated in memory. 43 /// Called immediately after the widget is allocated in memory.
24 /// You might use this to initialize something for the controller. 44 /// You might use this to initialize something for the controller.
  45 + @mustCallSuper
25 void onInit() {} 46 void onInit() {}
26 47
27 /// Called 1 frame after onInit(). It is the perfect place to enter 48 /// Called 1 frame after onInit(). It is the perfect place to enter
28 /// navigation events, like snackbar, dialogs, or a new route, or 49 /// navigation events, like snackbar, dialogs, or a new route, or
29 /// async request. 50 /// async request.
  51 + @mustCallSuper
30 void onReady() {} 52 void onReady() {}
31 53
32 /// Called before [onDelete] method. [onClose] might be used to 54 /// Called before [onDelete] method. [onClose] might be used to
@@ -35,7 +57,32 @@ mixin GetLifeCycle { @@ -35,7 +57,32 @@ mixin GetLifeCycle {
35 /// Or dispose objects that can potentially create some memory leaks, 57 /// Or dispose objects that can potentially create some memory leaks,
36 /// like TextEditingControllers, AnimationControllers. 58 /// like TextEditingControllers, AnimationControllers.
37 /// Might be useful as well to persist some data on disk. 59 /// Might be useful as well to persist some data on disk.
  60 + @mustCallSuper
38 void onClose() {} 61 void onClose() {}
  62 +
  63 + bool _initialized = false;
  64 +
  65 + /// Checks whether the controller has already been initialized.
  66 + bool get initialized => _initialized;
  67 +
  68 + // Internal callback that starts the cycle of this controller.
  69 + void _onStart() {
  70 + if (_initialized) return;
  71 + onInit();
  72 + _initialized = true;
  73 + }
  74 +
  75 + bool _isClosed = false;
  76 +
  77 + /// Checks whether the controller has already been closed.
  78 + bool get isClosed => _isClosed;
  79 +
  80 + // Internal callback that starts the cycle of this controller.
  81 + void _onDelete() {
  82 + if (_isClosed) return;
  83 + _isClosed = true;
  84 + onClose();
  85 + }
39 } 86 }
40 87
41 /// Allow track difference between GetxServices and GetxControllers 88 /// Allow track difference between GetxServices and GetxControllers
@@ -5,7 +5,6 @@ export 'src/extension_navigation.dart'; @@ -5,7 +5,6 @@ export 'src/extension_navigation.dart';
5 export 'src/root/root_widget.dart'; 5 export 'src/root/root_widget.dart';
6 export 'src/routes/custom_transition.dart'; 6 export 'src/routes/custom_transition.dart';
7 export 'src/routes/default_route.dart'; 7 export 'src/routes/default_route.dart';
8 -export 'src/routes/default_route.dart';  
9 export 'src/routes/get_route.dart'; 8 export 'src/routes/get_route.dart';
10 export 'src/routes/observers/route_observer.dart'; 9 export 'src/routes/observers/route_observer.dart';
11 export 'src/routes/transitions_type.dart'; 10 export 'src/routes/transitions_type.dart';
@@ -104,7 +104,7 @@ extension ExtensionSnackbar on GetInterface { @@ -104,7 +104,7 @@ extension ExtensionSnackbar on GetInterface {
104 return key?.currentState?.push(SnackRoute<T>(snack: snackbar)); 104 return key?.currentState?.push(SnackRoute<T>(snack: snackbar));
105 } 105 }
106 106
107 - void snackbar( 107 + void snackbar<T>(
108 String title, 108 String title,
109 String message, { 109 String message, {
110 Color colorText, 110 Color colorText,
@@ -199,11 +199,11 @@ extension ExtensionSnackbar on GetInterface { @@ -199,11 +199,11 @@ extension ExtensionSnackbar on GetInterface {
199 userInputForm: userInputForm); 199 userInputForm: userInputForm);
200 200
201 if (instantInit) { 201 if (instantInit) {
202 - showSnackbar(getBar); 202 + showSnackbar<T>(getBar);
203 } else { 203 } else {
204 routing.isSnackbar = true; 204 routing.isSnackbar = true;
205 SchedulerBinding.instance.addPostFrameCallback((_) { 205 SchedulerBinding.instance.addPostFrameCallback((_) {
206 - showSnackbar(getBar); 206 + showSnackbar<T>(getBar);
207 }); 207 });
208 } 208 }
209 } 209 }
@@ -220,9 +220,11 @@ extension ExtensionDialog on GetInterface { @@ -220,9 +220,11 @@ extension ExtensionDialog on GetInterface {
220 Color barrierColor, 220 Color barrierColor,
221 bool useSafeArea = true, 221 bool useSafeArea = true,
222 bool useRootNavigator = true, 222 bool useRootNavigator = true,
223 - RouteSettings routeSettings, 223 + Object arguments,
224 Duration transitionDuration, 224 Duration transitionDuration,
225 Curve transitionCurve, 225 Curve transitionCurve,
  226 + String name,
  227 + RouteSettings routeSettings,
226 }) { 228 }) {
227 assert(widget != null); 229 assert(widget != null);
228 assert(barrierDismissible != null); 230 assert(barrierDismissible != null);
@@ -231,7 +233,7 @@ extension ExtensionDialog on GetInterface { @@ -231,7 +233,7 @@ extension ExtensionDialog on GetInterface {
231 assert(debugCheckHasMaterialLocalizations(context)); 233 assert(debugCheckHasMaterialLocalizations(context));
232 234
233 final theme = Theme.of(context, shadowThemeOnly: true); 235 final theme = Theme.of(context, shadowThemeOnly: true);
234 - return generalDialog( 236 + return generalDialog<T>(
235 pageBuilder: (buildContext, animation, secondaryAnimation) { 237 pageBuilder: (buildContext, animation, secondaryAnimation) {
236 final pageChild = widget; 238 final pageChild = widget;
237 Widget dialog = Builder(builder: (context) { 239 Widget dialog = Builder(builder: (context) {
@@ -258,7 +260,8 @@ extension ExtensionDialog on GetInterface { @@ -258,7 +260,8 @@ extension ExtensionDialog on GetInterface {
258 ); 260 );
259 }, 261 },
260 useRootNavigator: useRootNavigator, 262 useRootNavigator: useRootNavigator,
261 - routeSettings: routeSettings, 263 + routeSettings:
  264 + routeSettings ?? RouteSettings(arguments: arguments, name: name),
262 ); 265 );
263 } 266 }
264 267
@@ -360,7 +363,7 @@ extension ExtensionDialog on GetInterface { @@ -360,7 +363,7 @@ extension ExtensionDialog on GetInterface {
360 } 363 }
361 } 364 }
362 365
363 - return dialog( 366 + return dialog<T>(
364 AlertDialog( 367 AlertDialog(
365 titlePadding: EdgeInsets.all(8), 368 titlePadding: EdgeInsets.all(8),
366 contentPadding: EdgeInsets.all(8), 369 contentPadding: EdgeInsets.all(8),
@@ -484,8 +487,8 @@ extension GetNavigation on GetInterface { @@ -484,8 +487,8 @@ extension GetNavigation on GetInterface {
484 if (preventDuplicates && routeName == currentRoute) { 487 if (preventDuplicates && routeName == currentRoute) {
485 return null; 488 return null;
486 } 489 }
487 - return global(id)?.currentState?.push(  
488 - GetPageRoute( 490 + return global(id)?.currentState?.push<T>(
  491 + GetPageRoute<T>(
489 opaque: opaque ?? true, 492 opaque: opaque ?? true,
490 page: () => page, 493 page: () => page,
491 routeName: routeName, 494 routeName: routeName,
@@ -528,7 +531,7 @@ extension GetNavigation on GetInterface { @@ -528,7 +531,7 @@ extension GetNavigation on GetInterface {
528 if (preventDuplicates && page == currentRoute) { 531 if (preventDuplicates && page == currentRoute) {
529 return null; 532 return null;
530 } 533 }
531 - return global(id)?.currentState?.pushNamed(page, arguments: arguments); 534 + return global(id)?.currentState?.pushNamed<T>(page, arguments: arguments);
532 } 535 }
533 536
534 /// **Navigation.pushReplacementNamed()** shortcut.<br><br> 537 /// **Navigation.pushReplacementNamed()** shortcut.<br><br>
@@ -601,7 +604,7 @@ extension GetNavigation on GetInterface { @@ -601,7 +604,7 @@ extension GetNavigation on GetInterface {
601 Future<T> offUntil<T>(Route<T> page, RoutePredicate predicate, {int id}) { 604 Future<T> offUntil<T>(Route<T> page, RoutePredicate predicate, {int id}) {
602 // if (key.currentState.mounted) // add this if appear problems on future with route navigate 605 // if (key.currentState.mounted) // add this if appear problems on future with route navigate
603 // when widget don't mounted 606 // when widget don't mounted
604 - return global(id)?.currentState?.pushAndRemoveUntil(page, predicate); 607 + return global(id)?.currentState?.pushAndRemoveUntil<T>(page, predicate);
605 } 608 }
606 609
607 /// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br> 610 /// **Navigation.pushNamedAndRemoveUntil()** shortcut.<br><br>
@@ -629,7 +632,7 @@ extension GetNavigation on GetInterface { @@ -629,7 +632,7 @@ extension GetNavigation on GetInterface {
629 }) { 632 }) {
630 return global(id) 633 return global(id)
631 ?.currentState 634 ?.currentState
632 - ?.pushNamedAndRemoveUntil(page, predicate, arguments: arguments); 635 + ?.pushNamedAndRemoveUntil<T>(page, predicate, arguments: arguments);
633 } 636 }
634 637
635 /// **Navigation.popAndPushNamed()** shortcut.<br><br> 638 /// **Navigation.popAndPushNamed()** shortcut.<br><br>
@@ -690,7 +693,7 @@ extension GetNavigation on GetInterface { @@ -690,7 +693,7 @@ extension GetNavigation on GetInterface {
690 dynamic arguments, 693 dynamic arguments,
691 int id, 694 int id,
692 }) { 695 }) {
693 - return global(id)?.currentState?.pushNamedAndRemoveUntil( 696 + return global(id)?.currentState?.pushNamedAndRemoveUntil<T>(
694 newRouteName, 697 newRouteName,
695 predicate ?? (_) => false, 698 predicate ?? (_) => false,
696 arguments: arguments, 699 arguments: arguments,
@@ -717,8 +720,8 @@ extension GetNavigation on GetInterface { @@ -717,8 +720,8 @@ extension GetNavigation on GetInterface {
717 /// 720 ///
718 /// It has the advantage of not needing context, so you can call 721 /// It has the advantage of not needing context, so you can call
719 /// from your business logic. 722 /// from your business logic.
720 - void back({  
721 - dynamic result, 723 + void back<T>({
  724 + T result,
722 bool closeOverlays = false, 725 bool closeOverlays = false,
723 bool canPop = true, 726 bool canPop = true,
724 int id, 727 int id,
@@ -730,10 +733,10 @@ extension GetNavigation on GetInterface { @@ -730,10 +733,10 @@ extension GetNavigation on GetInterface {
730 } 733 }
731 if (canPop) { 734 if (canPop) {
732 if (global(id)?.currentState?.canPop() == true) { 735 if (global(id)?.currentState?.canPop() == true) {
733 - global(id)?.currentState?.pop(result); 736 + global(id)?.currentState?.pop<T>(result);
734 } 737 }
735 } else { 738 } else {
736 - global(id)?.currentState?.pop(result); 739 + global(id)?.currentState?.pop<T>(result);
737 } 740 }
738 } 741 }
739 742
@@ -854,8 +857,8 @@ extension GetNavigation on GetInterface { @@ -854,8 +857,8 @@ extension GetNavigation on GetInterface {
854 }) { 857 }) {
855 var routeName = "/${page.runtimeType.toString()}"; 858 var routeName = "/${page.runtimeType.toString()}";
856 859
857 - return global(id)?.currentState?.pushAndRemoveUntil(  
858 - GetPageRoute( 860 + return global(id)?.currentState?.pushAndRemoveUntil<T>(
  861 + GetPageRoute<T>(
859 opaque: opaque ?? true, 862 opaque: opaque ?? true,
860 popGesture: popGesture ?? defaultPopGesture, 863 popGesture: popGesture ?? defaultPopGesture,
861 page: () => page, 864 page: () => page,
  1 +import 'package:flutter/material.dart';
1 import 'package:flutter/scheduler.dart'; 2 import 'package:flutter/scheduler.dart';
2 import '../../../get_instance/src/lifecycle.dart'; 3 import '../../../get_instance/src/lifecycle.dart';
3 4
@@ -10,45 +11,24 @@ import '../../../get_instance/src/lifecycle.dart'; @@ -10,45 +11,24 @@ import '../../../get_instance/src/lifecycle.dart';
10 abstract class GetxService extends DisposableInterface with GetxServiceMixin {} 11 abstract class GetxService extends DisposableInterface with GetxServiceMixin {}
11 12
12 abstract class DisposableInterface with GetLifeCycle { 13 abstract class DisposableInterface with GetLifeCycle {
13 - bool _initialized = false;  
14 -  
15 - /// Checks whether the controller has already been initialized.  
16 - bool get initialized => _initialized;  
17 -  
18 - bool _isClosed = false;  
19 -  
20 - /// Checks whether the controller has already been closed.  
21 - bool get isClosed => _isClosed;  
22 -  
23 DisposableInterface() { 14 DisposableInterface() {
24 - onStart.callback = _onStart;  
25 - onDelete.callback = _onDelete;  
26 - }  
27 -  
28 - // Internal callback that starts the cycle of this controller.  
29 - void _onStart() {  
30 - if (_initialized) return;  
31 - onInit();  
32 - _initialized = true;  
33 - SchedulerBinding.instance?.addPostFrameCallback((_) => onReady());  
34 - }  
35 -  
36 - // Internal callback that starts the cycle of this controller.  
37 - void _onDelete() {  
38 - if (_isClosed) return;  
39 - _isClosed = true;  
40 - onClose(); 15 + initLifeCycle();
41 } 16 }
42 17
43 /// Called immediately after the widget is allocated in memory. 18 /// Called immediately after the widget is allocated in memory.
44 /// You might use this to initialize something for the controller. 19 /// You might use this to initialize something for the controller.
45 @override 20 @override
46 - void onInit() {} 21 + @mustCallSuper
  22 + void onInit() {
  23 + super.onInit();
  24 + SchedulerBinding.instance?.addPostFrameCallback((_) => onReady());
  25 + }
47 26
48 /// Called 1 frame after onInit(). It is the perfect place to enter 27 /// Called 1 frame after onInit(). It is the perfect place to enter
49 /// navigation events, like snackbar, dialogs, or a new route, or 28 /// navigation events, like snackbar, dialogs, or a new route, or
50 /// async request. 29 /// async request.
51 @override 30 @override
  31 + @mustCallSuper
52 void onReady() {} 32 void onReady() {}
53 33
54 /// Called before [onDelete] method. [onClose] might be used to 34 /// Called before [onDelete] method. [onClose] might be used to
@@ -38,36 +38,17 @@ typedef Condition = bool Function(); @@ -38,36 +38,17 @@ typedef Condition = bool Function();
38 38
39 abstract class GetNotifier<T> extends Value<T> with GetLifeCycle { 39 abstract class GetNotifier<T> extends Value<T> with GetLifeCycle {
40 GetNotifier(T initial) : super(initial) { 40 GetNotifier(T initial) : super(initial) {
41 - onStart.callback = _onStart;  
42 - onDelete.callback = _onDelete; 41 + initLifeCycle();
43 _fillEmptyStatus(); 42 _fillEmptyStatus();
44 } 43 }
45 44
46 - bool _initialized = false;  
47 -  
48 - /// Checks whether the controller has already been initialized.  
49 - bool get initialized => _initialized;  
50 -  
51 - bool _isClosed = false;  
52 -  
53 - /// Checks whether the controller has already been closed.  
54 - bool get isClosed => _isClosed;  
55 -  
56 - // Internal callback that starts the cycle of this controller.  
57 - void _onStart() {  
58 - if (_initialized) return;  
59 - onInit();  
60 - _initialized = true; 45 + @override
  46 + @mustCallSuper
  47 + void onInit() {
  48 + super.onInit();
61 SchedulerBinding.instance?.addPostFrameCallback((_) => onReady()); 49 SchedulerBinding.instance?.addPostFrameCallback((_) => onReady());
62 } 50 }
63 51
64 - // Internal callback that starts the cycle of this controller.  
65 - void _onDelete() {  
66 - if (_isClosed) return;  
67 - _isClosed = true;  
68 - onClose();  
69 - }  
70 -  
71 RxStatus _status; 52 RxStatus _status;
72 53
73 bool get isNullOrEmpty { 54 bool get isNullOrEmpty {
@@ -4,22 +4,21 @@ import '../../../get_rx/get_rx.dart'; @@ -4,22 +4,21 @@ import '../../../get_rx/get_rx.dart';
4 4
5 typedef WidgetCallback = Widget Function(); 5 typedef WidgetCallback = Widget Function();
6 6
7 -/// The simplest reactive widget in GetX.  
8 -///  
9 -/// Just pass your Rx variable in the root scope of the callback to have it  
10 -/// automatically registered for changes. 7 +/// The [ObxWidget] is the base for all GetX reactive widgets
11 /// 8 ///
12 -/// final _name = "GetX".obs;  
13 -/// Obx(() => Text( _name.value )),... ;  
14 -class Obx extends StatefulWidget {  
15 - final WidgetCallback builder;  
16 -  
17 - const Obx(this.builder); 9 +/// See also:
  10 +/// - [Obx]
  11 +/// - [ObxValue]
  12 +abstract class ObxWidget extends StatefulWidget {
  13 + const ObxWidget({Key key}) : super(key: key);
18 14
19 _ObxState createState() => _ObxState(); 15 _ObxState createState() => _ObxState();
  16 +
  17 + @protected
  18 + Widget build();
20 } 19 }
21 20
22 -class _ObxState extends State<Obx> { 21 +class _ObxState extends State<ObxWidget> {
23 RxInterface _observer; 22 RxInterface _observer;
24 StreamSubscription subs; 23 StreamSubscription subs;
25 24
@@ -43,7 +42,7 @@ class _ObxState extends State<Obx> { @@ -43,7 +42,7 @@ class _ObxState extends State<Obx> {
43 Widget get notifyChilds { 42 Widget get notifyChilds {
44 final observer = getObs; 43 final observer = getObs;
45 getObs = _observer; 44 getObs = _observer;
46 - final result = widget.builder(); 45 + final result = widget.build();
47 if (!_observer.canUpdate) { 46 if (!_observer.canUpdate) {
48 throw """ 47 throw """
49 [Get] the improper use of a GetX has been detected. 48 [Get] the improper use of a GetX has been detected.
@@ -62,6 +61,22 @@ class _ObxState extends State<Obx> { @@ -62,6 +61,22 @@ class _ObxState extends State<Obx> {
62 Widget build(BuildContext context) => notifyChilds; 61 Widget build(BuildContext context) => notifyChilds;
63 } 62 }
64 63
  64 +/// The simplest reactive widget in GetX.
  65 +///
  66 +/// Just pass your Rx variable in the root scope of the callback to have it
  67 +/// automatically registered for changes.
  68 +///
  69 +/// final _name = "GetX".obs;
  70 +/// Obx(() => Text( _name.value )),... ;
  71 +class Obx extends ObxWidget {
  72 + final WidgetCallback builder;
  73 +
  74 + const Obx(this.builder);
  75 +
  76 + @override
  77 + Widget build() => builder();
  78 +}
  79 +
65 /// Similar to Obx, but manages a local state. 80 /// Similar to Obx, but manages a local state.
66 /// Pass the initial data in constructor. 81 /// Pass the initial data in constructor.
67 /// Useful for simple local states, like toggles, visibility, themes, 82 /// Useful for simple local states, like toggles, visibility, themes,
@@ -76,45 +91,12 @@ class _ObxState extends State<Obx> { @@ -76,45 +91,12 @@ class _ObxState extends State<Obx> {
76 91
77 // TODO: change T to a proper Rx interface, that includes the accessor 92 // TODO: change T to a proper Rx interface, that includes the accessor
78 // for ::value 93 // for ::value
79 -class ObxValue<T extends RxInterface> extends StatefulWidget { 94 +class ObxValue<T extends RxInterface> extends ObxWidget {
80 final Widget Function(T) builder; 95 final Widget Function(T) builder;
81 final T data; 96 final T data;
82 97
83 const ObxValue(this.builder, this.data, {Key key}) : super(key: key); 98 const ObxValue(this.builder, this.data, {Key key}) : super(key: key);
84 99
85 - _ObxValueState createState() => _ObxValueState();  
86 -}  
87 -  
88 -class _ObxValueState extends State<ObxValue> {  
89 - RxInterface _observer;  
90 - StreamSubscription subs;  
91 -  
92 - _ObxValueState() {  
93 - _observer = Rx();  
94 - }  
95 -  
96 - @override  
97 - void initState() {  
98 - subs = _observer.subject.stream.listen((data) => setState(() {}));  
99 - super.initState();  
100 - }  
101 -  
102 - @override  
103 - void dispose() {  
104 - subs.cancel();  
105 - _observer.close();  
106 - super.dispose();  
107 - }  
108 -  
109 - Widget get notifyChilds {  
110 - final observer = getObs;  
111 - getObs = _observer;  
112 - // observable is implicity taken from the constructor.  
113 - final result = widget.builder(widget.data);  
114 - getObs = observer;  
115 - return result;  
116 - }  
117 -  
118 @override 100 @override
119 - Widget build(BuildContext context) => notifyChilds; 101 + Widget build() => builder(data);
120 } 102 }
@@ -39,17 +39,21 @@ abstract class GetView<T> extends StatelessWidget { @@ -39,17 +39,21 @@ abstract class GetView<T> extends StatelessWidget {
39 Widget build(BuildContext context); 39 Widget build(BuildContext context);
40 } 40 }
41 41
  42 +class _Wrapper<T> {
  43 + T data;
  44 +}
  45 +
42 abstract class GetWidget<T extends DisposableInterface> 46 abstract class GetWidget<T extends DisposableInterface>
43 extends StatelessWidget { 47 extends StatelessWidget {
44 GetWidget({Key key}) : super(key: key); 48 GetWidget({Key key}) : super(key: key);
45 49
46 - final Set<T> _value = <T>{}; 50 + final _value = _Wrapper<T>();
47 51
48 final String tag = null; 52 final String tag = null;
49 53
50 T get controller { 54 T get controller {
51 - if (_value.isEmpty) _value.add(GetInstance().find<T>(tag: tag));  
52 - return _value.first; 55 + _value.data ??= GetInstance().find<T>(tag: tag);
  56 + return _value.data;
53 } 57 }
54 58
55 @override 59 @override
@@ -203,8 +203,10 @@ class GetUtils { @@ -203,8 +203,10 @@ class GetUtils {
203 r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'); 203 r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$');
204 204
205 /// Checks if string is phone number. 205 /// Checks if string is phone number.
206 - static bool isPhoneNumber(String s) => hasMatch(s,  
207 - r'^(0|\+|(\+[0-9]{2,4}|\(\+?[0-9]{2,4}\)) ?)([0-9]*|\d{2,4}-\d{2,4}(-\d{2,4})?)$'); 206 + static bool isPhoneNumber(String s) {
  207 + if (s == null || s.length > 16 || s.length < 9) return false;
  208 + return hasMatch(s, r'^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\s\./0-9]*$');
  209 + }
208 210
209 /// Checks if string is DateTime (UTC or Iso8601). 211 /// Checks if string is DateTime (UTC or Iso8601).
210 static bool isDateTime(String s) => 212 static bool isDateTime(String s) =>
@@ -4,11 +4,12 @@ version: 3.13.2 @@ -4,11 +4,12 @@ version: 3.13.2
4 homepage: https://github.com/jonataslaw/getx 4 homepage: https://github.com/jonataslaw/getx
5 5
6 environment: 6 environment:
7 - sdk: ">=2.8.0 <3.0.0" 7 + sdk: ">=2.10.0 <3.0.0"
8 8
9 dependencies: 9 dependencies:
10 flutter: 10 flutter:
11 sdk: flutter 11 sdk: flutter
  12 + meta: 1.3.0-nullsafety.3
12 13
13 dev_dependencies: 14 dev_dependencies:
14 flutter_test: 15 flutter_test:
  1 +import 'dart:async';
  2 +
  3 +import 'package:flutter/foundation.dart';
  4 +import 'package:get/state_manager.dart';
  5 +
  6 +int times = 3;
  7 +int get last => times - 1;
  8 +
  9 +Future<String> valueNotifier() {
  10 + final c = Completer<String>();
  11 + final value = ValueNotifier<int>(0);
  12 + final timer = Stopwatch();
  13 + timer.start();
  14 +
  15 + value.addListener(() {
  16 + if (last == value.value) {
  17 + timer.stop();
  18 + c.complete("""${value.value} item value notifier
  19 +objs time: ${timer.elapsedMicroseconds}ms""");
  20 + }
  21 + });
  22 +
  23 + for (var i = 0; i < times; i++) {
  24 + value.value = i;
  25 + }
  26 +
  27 + return c.future;
  28 +}
  29 +
  30 +Future<String> getValue() {
  31 + final c = Completer<String>();
  32 + final value = Value<int>(0);
  33 + final timer = Stopwatch();
  34 + timer.start();
  35 +
  36 + value.addListener(() {
  37 + if (last == value.value) {
  38 + timer.stop();
  39 + c.complete("""${value.value} item get value objs
  40 + time: ${timer.elapsedMicroseconds}ms""");
  41 + }
  42 + });
  43 +
  44 + for (var i = 0; i < times; i++) {
  45 + value.value = i;
  46 + }
  47 +
  48 + return c.future;
  49 +}
  50 +
  51 +Future<String> getStream() {
  52 + final c = Completer<String>();
  53 +
  54 + final value = StreamController<int>();
  55 + final timer = Stopwatch();
  56 + timer.start();
  57 +
  58 + value.stream.listen((v) {
  59 + if (last == v) {
  60 + timer.stop();
  61 + c.complete("$v item stream objs time: ${timer.elapsedMicroseconds}ms");
  62 + }
  63 + });
  64 +
  65 + for (var i = 0; i < times; i++) {
  66 + value.add(i);
  67 + }
  68 +
  69 + return c.future;
  70 +}
  71 +
  72 +void main() async {
  73 + print(await getValue());
  74 + print(await valueNotifier());
  75 + print(await getStream());
  76 + times = 30000;
  77 + print(await getValue());
  78 + print(await valueNotifier());
  79 + print(await getStream());
  80 +}
  81 +
  82 +typedef VoidCallback = void Function();
@@ -11,29 +11,7 @@ class Mock { @@ -11,29 +11,7 @@ class Mock {
11 11
12 class DisposableController with GetLifeCycle { 12 class DisposableController with GetLifeCycle {
13 DisposableController() { 13 DisposableController() {
14 - onStart.callback = _onStart;  
15 - onDelete.callback = _onDelete;  
16 - }  
17 -  
18 - // Internal callback that starts the cycle of this controller.  
19 - void _onStart() {  
20 - if (initialized) return;  
21 - onInit();  
22 - }  
23 -  
24 - // Internal callback that starts the cycle of this controller.  
25 - void _onDelete() {  
26 - if (isClosed) return;  
27 - isClosed = true;  
28 - onClose();  
29 - }  
30 -  
31 - bool initialized = false;  
32 -  
33 - bool isClosed = false;  
34 -  
35 - void onInit() async {  
36 - initialized = true; 14 + initLifeCycle();
37 } 15 }
38 } 16 }
39 17
@@ -73,7 +73,6 @@ void main() { @@ -73,7 +73,6 @@ void main() {
73 var expected = ''; 73 var expected = '';
74 void logFunction(String prefix, dynamic value, String info, 74 void logFunction(String prefix, dynamic value, String info,
75 {bool isError = false}) { 75 {bool isError = false}) {
76 - print('algo');  
77 expected = '$prefix $value $info'.trim(); 76 expected = '$prefix $value $info'.trim();
78 } 77 }
79 78
@@ -239,14 +239,12 @@ void main() { @@ -239,14 +239,12 @@ void main() {
239 '(455) 443-8171', 239 '(455) 443-8171',
240 '(915) 685-8658', 240 '(915) 685-8658',
241 '(572) 207-1898', 241 '(572) 207-1898',
242 -  
243 - // TODO those are failing, but they shouldn't  
244 - // '(81) 6 2499-9538',  
245 - // '(31) 32304-4263',  
246 - // '(64) 25242-6375',  
247 - // '(41) 19308-7925',  
248 - // '(67) 61684-0395',  
249 - // '(60) 54706-3569', 242 + '(81) 6 2499-9538',
  243 + '(31) 32304-4263',
  244 + '(64) 25242-6375',
  245 + '(41) 19308-7925',
  246 + '(67) 61684-0395',
  247 + '(60) 54706-3569',
250 '(31) 33110055', 248 '(31) 33110055',
251 '(11) 3344-5599', 249 '(11) 3344-5599',
252 '(31) 977447788', 250 '(31) 977447788',