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