Committed by
GitHub
Merge pull request #1540 from kranfix/refactor/rx_interface_notify_children
Refactor/rx interface notify children
Showing
19 changed files
with
57 additions
and
86 deletions
@@ -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'; |
@@ -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. |
-
Please register or login to post a comment