Jonny Borges
Committed by GitHub

Merge pull request #1540 from kranfix/refactor/rx_interface_notify_children

Refactor/rx interface notify children
@@ -80,3 +80,6 @@ example/macos/Flutter/ephemeral/Flutter-Generated.xcconfig @@ -80,3 +80,6 @@ example/macos/Flutter/ephemeral/Flutter-Generated.xcconfig
80 example/macos/Flutter/ephemeral/ 80 example/macos/Flutter/ephemeral/
81 81
82 example/macos/Flutter/GeneratedPluginRegistrant.swift 82 example/macos/Flutter/GeneratedPluginRegistrant.swift
  83 +
  84 +# Coverage files
  85 +coverage/
1 -import 'package:example_nav2/app/modules/home/controllers/home_controller.dart';  
2 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
3 -  
4 import 'package:get/get.dart'; 2 import 'package:get/get.dart';
5 3
  4 +import '../controllers/home_controller.dart';
  5 +
6 class DashboardView extends GetView<HomeController> { 6 class DashboardView extends GetView<HomeController> {
7 @override 7 @override
8 Widget build(BuildContext context) { 8 Widget build(BuildContext context) {
1 -import 'package:example_nav2/app/models/demo_product.dart';  
2 import 'package:get/get.dart'; 1 import 'package:get/get.dart';
3 2
  3 +import '../../../models/demo_product.dart';
  4 +
4 class ProductsController extends GetxController { 5 class ProductsController extends GetxController {
5 final products = <DemoProduct>[].obs; 6 final products = <DemoProduct>[].obs;
6 7
1 -import 'package:example_nav2/app/routes/app_pages.dart';  
2 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
3 -  
4 import 'package:get/get.dart'; 2 import 'package:get/get.dart';
5 3
  4 +import '../../../routes/app_pages.dart';
6 import '../controllers/products_controller.dart'; 5 import '../controllers/products_controller.dart';
7 6
8 class ProductsView extends GetView<ProductsController> { 7 class ProductsView extends GetView<ProductsController> {
1 -import 'package:example_nav2/app/routes/app_pages.dart';  
2 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
3 import 'package:get/get.dart'; 2 import 'package:get/get.dart';
4 3
  4 +import '../../../routes/app_pages.dart';
  5 +
5 class DrawerWidget extends StatelessWidget { 6 class DrawerWidget extends StatelessWidget {
6 const DrawerWidget({ 7 const DrawerWidget({
7 Key? key, 8 Key? key,
1 -import 'package:example_nav2/app/modules/root/bindings/root_binding.dart';  
2 -import 'package:example_nav2/app/modules/root/views/root_view.dart';  
3 import 'package:get/get.dart'; 1 import 'package:get/get.dart';
4 import 'package:get/get_navigation/src/nav2/router_outlet.dart'; 2 import 'package:get/get_navigation/src/nav2/router_outlet.dart';
  3 +
5 import '../modules/home/bindings/home_binding.dart'; 4 import '../modules/home/bindings/home_binding.dart';
6 import '../modules/home/views/home_view.dart'; 5 import '../modules/home/views/home_view.dart';
7 import '../modules/product_details/bindings/product_details_binding.dart'; 6 import '../modules/product_details/bindings/product_details_binding.dart';
@@ -10,6 +9,8 @@ import '../modules/products/bindings/products_binding.dart'; @@ -10,6 +9,8 @@ import '../modules/products/bindings/products_binding.dart';
10 import '../modules/products/views/products_view.dart'; 9 import '../modules/products/views/products_view.dart';
11 import '../modules/profile/bindings/profile_binding.dart'; 10 import '../modules/profile/bindings/profile_binding.dart';
12 import '../modules/profile/views/profile_view.dart'; 11 import '../modules/profile/views/profile_view.dart';
  12 +import '../modules/root/bindings/root_binding.dart';
  13 +import '../modules/root/views/root_view.dart';
13 import '../modules/settings/bindings/settings_binding.dart'; 14 import '../modules/settings/bindings/settings_binding.dart';
14 import '../modules/settings/views/settings_view.dart'; 15 import '../modules/settings/views/settings_view.dart';
15 16
1 import 'package:flutter/widgets.dart'; 1 import 'package:flutter/widgets.dart';
2 -import '../../get_navigation/src/nav2/get_router_delegate.dart';  
3 -import '../../get_navigation/src/routes/get_route.dart';  
4 2
5 import 'log.dart'; 3 import 'log.dart';
6 import 'smart_management.dart'; 4 import 'smart_management.dart';
1 import 'dart:async'; 1 import 'dart:async';
2 import 'dart:collection'; 2 import 'dart:collection';
3 3
4 -import 'package:flutter/widgets.dart';  
5 -  
6 import '../../get_core/get_core.dart'; 4 import '../../get_core/get_core.dart';
7 5
8 import 'lifecycle.dart'; 6 import 'lifecycle.dart';
@@ -449,8 +449,10 @@ extension ExtensionBottomSheet on GetInterface { @@ -449,8 +449,10 @@ extension ExtensionBottomSheet on GetInterface {
449 modalBarrierColor: barrierColor, 449 modalBarrierColor: barrierColor,
450 settings: settings, 450 settings: settings,
451 enableDrag: enableDrag, 451 enableDrag: enableDrag,
452 - enterBottomSheetDuration: enterBottomSheetDuration ?? const Duration(milliseconds: 250),  
453 - exitBottomSheetDuration: exitBottomSheetDuration ?? const Duration(milliseconds: 200), 452 + enterBottomSheetDuration:
  453 + enterBottomSheetDuration ?? const Duration(milliseconds: 250),
  454 + exitBottomSheetDuration:
  455 + exitBottomSheetDuration ?? const Duration(milliseconds: 200),
454 )); 456 ));
455 } 457 }
456 } 458 }
1 import 'package:flutter/widgets.dart'; 1 import 'package:flutter/widgets.dart';
2 2
3 -import 'package:get/get.dart'; 3 +import '../../../get.dart';
4 4
5 /// This config enables us to navigate directly to a sub-url 5 /// This config enables us to navigate directly to a sub-url
6 class GetNavConfig extends RouteInformation { 6 class GetNavConfig extends RouteInformation {
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
2 -import 'package:get/get_navigation/src/nav2/get_router_delegate.dart'; 2 +
3 import '../../../get.dart'; 3 import '../../../get.dart';
  4 +import 'get_router_delegate.dart';
4 5
5 class RouterOutlet<TDelegate extends RouterDelegate<T>, T extends Object> 6 class RouterOutlet<TDelegate extends RouterDelegate<T>, T extends Object>
6 extends StatefulWidget { 7 extends StatefulWidget {
@@ -5,7 +5,6 @@ import 'package:flutter/material.dart'; @@ -5,7 +5,6 @@ import 'package:flutter/material.dart';
5 import '../../../get_core/get_core.dart'; 5 import '../../../get_core/get_core.dart';
6 import '../../../get_instance/get_instance.dart'; 6 import '../../../get_instance/get_instance.dart';
7 import '../../../get_state_manager/get_state_manager.dart'; 7 import '../../../get_state_manager/get_state_manager.dart';
8 -import '../../../get_state_manager/src/simple/list_notifier.dart';  
9 import '../../../get_utils/get_utils.dart'; 8 import '../../../get_utils/get_utils.dart';
10 import '../../get_navigation.dart'; 9 import '../../get_navigation.dart';
11 import 'root_controller.dart'; 10 import 'root_controller.dart';
@@ -105,9 +105,7 @@ mixin RxObjectMixin<T> on NotifyManager<T> { @@ -105,9 +105,7 @@ mixin RxObjectMixin<T> on NotifyManager<T> {
105 105
106 /// Returns the current [value] 106 /// Returns the current [value]
107 T get value { 107 T get value {
108 - if (RxInterface.proxy != null) {  
109 - RxInterface.proxy!.addListener(subject);  
110 - } 108 + RxInterface.proxy?.addListener(subject);
111 return _value; 109 return _value;
112 } 110 }
113 111
@@ -18,4 +18,23 @@ abstract class RxInterface<T> { @@ -18,4 +18,23 @@ abstract class RxInterface<T> {
18 /// Calls [callback] with current value, when the value changes. 18 /// Calls [callback] with current value, when the value changes.
19 StreamSubscription<T> listen(void Function(T event) onData, 19 StreamSubscription<T> listen(void Function(T event) onData,
20 {Function? onError, void Function()? onDone, bool? cancelOnError}); 20 {Function? onError, void Function()? onDone, bool? cancelOnError});
  21 +
  22 + /// 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 + throw """
  29 + [Get] the improper use of a GetX has been detected.
  30 + You should only use GetX or Obx for the specific widget that will be updated.
  31 + If you are seeing this error, you probably did not insert any observable variables into GetX/Obx
  32 + or insert them outside the scope that GetX considers suitable for an update
  33 + (example: GetX => HeavyWidget => variableObservable).
  34 + If you need to update a parent widget and a child widget, wrap each one in an Obx/GetX.
  35 + """;
  36 + }
  37 + RxInterface.proxy = _observer;
  38 + return result;
  39 + }
21 } 40 }
@@ -78,9 +78,7 @@ class RxList<E> extends ListMixin<E> @@ -78,9 +78,7 @@ class RxList<E> extends ListMixin<E>
78 @override 78 @override
79 @protected 79 @protected
80 List<E> get value { 80 List<E> get value {
81 - if (RxInterface.proxy != null) {  
82 - RxInterface.proxy!.addListener(subject);  
83 - } 81 + RxInterface.proxy?.addListener(subject);
84 return _value; 82 return _value;
85 } 83 }
86 84
@@ -56,9 +56,7 @@ class RxMap<K, V> extends MapMixin<K, V> @@ -56,9 +56,7 @@ class RxMap<K, V> extends MapMixin<K, V>
56 @override 56 @override
57 @protected 57 @protected
58 Map<K, V> get value { 58 Map<K, V> get value {
59 - if (RxInterface.proxy != null) {  
60 - RxInterface.proxy!.addListener(subject);  
61 - } 59 + RxInterface.proxy?.addListener(subject);
62 return _value; 60 return _value;
63 } 61 }
64 } 62 }
@@ -23,9 +23,7 @@ class RxSet<E> extends SetMixin<E> @@ -23,9 +23,7 @@ class RxSet<E> extends SetMixin<E>
23 @override 23 @override
24 @protected 24 @protected
25 Set<E> get value { 25 Set<E> get value {
26 - if (RxInterface.proxy != null) {  
27 - RxInterface.proxy!.addListener(subject);  
28 - } 26 + RxInterface.proxy?.addListener(subject);
29 return _value; 27 return _value;
30 } 28 }
31 29
@@ -45,10 +45,7 @@ class GetX<T extends DisposableInterface> extends StatefulWidget { @@ -45,10 +45,7 @@ class GetX<T extends DisposableInterface> extends StatefulWidget {
45 } 45 }
46 46
47 class GetXState<T extends DisposableInterface> extends State<GetX<T>> { 47 class GetXState<T extends DisposableInterface> extends State<GetX<T>> {
48 - GetXState() {  
49 - _observer = RxNotifier();  
50 - }  
51 - RxInterface? _observer; 48 + final _observer = RxNotifier();
52 T? controller; 49 T? controller;
53 bool? _isCreator = false; 50 bool? _isCreator = false;
54 late StreamSubscription _subs; 51 late StreamSubscription _subs;
@@ -56,15 +53,11 @@ class GetXState<T extends DisposableInterface> extends State<GetX<T>> { @@ -56,15 +53,11 @@ class GetXState<T extends DisposableInterface> extends State<GetX<T>> {
56 @override 53 @override
57 void initState() { 54 void initState() {
58 // var isPrepared = GetInstance().isPrepared<T>(tag: widget.tag); 55 // var isPrepared = GetInstance().isPrepared<T>(tag: widget.tag);
59 - var isRegistered = GetInstance().isRegistered<T>(tag: widget.tag); 56 + final isRegistered = GetInstance().isRegistered<T>(tag: widget.tag);
60 57
61 if (widget.global) { 58 if (widget.global) {
62 if (isRegistered) { 59 if (isRegistered) {
63 - if (GetInstance().isPrepared<T>(tag: widget.tag)) {  
64 - _isCreator = true;  
65 - } else {  
66 - _isCreator = false;  
67 - } 60 + _isCreator = GetInstance().isPrepared<T>(tag: widget.tag);
68 controller = GetInstance().find<T>(tag: widget.tag); 61 controller = GetInstance().find<T>(tag: widget.tag);
69 } else { 62 } else {
70 controller = widget.init; 63 controller = widget.init;
@@ -80,7 +73,7 @@ class GetXState<T extends DisposableInterface> extends State<GetX<T>> { @@ -80,7 +73,7 @@ class GetXState<T extends DisposableInterface> extends State<GetX<T>> {
80 if (widget.global && Get.smartManagement == SmartManagement.onlyBuilder) { 73 if (widget.global && Get.smartManagement == SmartManagement.onlyBuilder) {
81 controller?.onStart(); 74 controller?.onStart();
82 } 75 }
83 - _subs = _observer!.listen((data) => setState(() {}), cancelOnError: false); 76 + _subs = _observer.listen((data) => setState(() {}), cancelOnError: false);
84 super.initState(); 77 super.initState();
85 } 78 }
86 79
@@ -107,30 +100,15 @@ class GetXState<T extends DisposableInterface> extends State<GetX<T>> { @@ -107,30 +100,15 @@ class GetXState<T extends DisposableInterface> extends State<GetX<T>> {
107 } 100 }
108 } 101 }
109 _subs.cancel(); 102 _subs.cancel();
110 - _observer!.close(); 103 + _observer.close();
111 controller = null; 104 controller = null;
112 _isCreator = null; 105 _isCreator = null;
113 super.dispose(); 106 super.dispose();
114 } 107 }
115 108
116 - Widget get notifyChildren {  
117 - final observer = RxInterface.proxy;  
118 - RxInterface.proxy = _observer;  
119 - final result = widget.builder(controller!);  
120 - if (!_observer!.canUpdate) {  
121 - throw """  
122 - [Get] the improper use of a GetX has been detected.  
123 - You should only use GetX or Obx for the specific widget that will be updated.  
124 - If you are seeing this error, you probably did not insert any observable variables into GetX/Obx  
125 - or insert them outside the scope that GetX considers suitable for an update  
126 - (example: GetX => HeavyWidget => variableObservable).  
127 - If you need to update a parent widget and a child widget, wrap each one in an Obx/GetX.  
128 - """;  
129 - }  
130 - RxInterface.proxy = observer;  
131 - return result;  
132 - }  
133 -  
134 @override 109 @override
135 - Widget build(BuildContext context) => notifyChildren; 110 + Widget build(BuildContext context) => RxInterface.notifyChildren(
  111 + _observer,
  112 + () => widget.builder(controller!),
  113 + );
136 } 114 }
@@ -20,17 +20,13 @@ abstract class ObxWidget extends StatefulWidget { @@ -20,17 +20,13 @@ abstract class ObxWidget extends StatefulWidget {
20 } 20 }
21 21
22 class _ObxState extends State<ObxWidget> { 22 class _ObxState extends State<ObxWidget> {
23 - RxInterface? _observer; 23 + final _observer = RxNotifier();
24 late StreamSubscription subs; 24 late StreamSubscription subs;
25 25
26 - _ObxState() {  
27 - _observer = RxNotifier();  
28 - }  
29 -  
30 @override 26 @override
31 void initState() { 27 void initState() {
32 - subs = _observer!.listen(_updateTree, cancelOnError: false);  
33 super.initState(); 28 super.initState();
  29 + subs = _observer.listen(_updateTree, cancelOnError: false);
34 } 30 }
35 31
36 void _updateTree(_) { 32 void _updateTree(_) {
@@ -42,30 +38,13 @@ class _ObxState extends State<ObxWidget> { @@ -42,30 +38,13 @@ class _ObxState extends State<ObxWidget> {
42 @override 38 @override
43 void dispose() { 39 void dispose() {
44 subs.cancel(); 40 subs.cancel();
45 - _observer!.close(); 41 + _observer.close();
46 super.dispose(); 42 super.dispose();
47 } 43 }
48 44
49 - Widget get notifyChilds {  
50 - final observer = RxInterface.proxy;  
51 - RxInterface.proxy = _observer;  
52 - final result = widget.build();  
53 - if (!_observer!.canUpdate) {  
54 - throw """  
55 - [Get] the improper use of a GetX has been detected.  
56 - You should only use GetX or Obx for the specific widget that will be updated.  
57 - If you are seeing this error, you probably did not insert any observable variables into GetX/Obx  
58 - or insert them outside the scope that GetX considers suitable for an update  
59 - (example: GetX => HeavyWidget => variableObservable).  
60 - If you need to update a parent widget and a child widget, wrap each one in an Obx/GetX.  
61 - """;  
62 - }  
63 - RxInterface.proxy = observer;  
64 - return result;  
65 - }  
66 -  
67 @override 45 @override
68 - Widget build(BuildContext context) => notifyChilds; 46 + Widget build(BuildContext context) =>
  47 + RxInterface.notifyChildren(_observer, widget.build);
69 } 48 }
70 49
71 /// The simplest reactive widget in GetX. 50 /// The simplest reactive widget in GetX.