Showing
24 changed files
with
295 additions
and
162 deletions
@@ -20,6 +20,10 @@ version: 1.0.0+1 | @@ -20,6 +20,10 @@ version: 1.0.0+1 | ||
20 | environment: | 20 | environment: |
21 | sdk: ">=2.12.0 <3.0.0" | 21 | sdk: ">=2.12.0 <3.0.0" |
22 | 22 | ||
23 | +dependency_overrides: | ||
24 | + get: | ||
25 | + path: ../ | ||
26 | + | ||
23 | dependencies: | 27 | dependencies: |
24 | flutter: | 28 | flutter: |
25 | sdk: flutter | 29 | sdk: flutter |
@@ -33,6 +37,7 @@ dependencies: | @@ -33,6 +37,7 @@ dependencies: | ||
33 | dev_dependencies: | 37 | dev_dependencies: |
34 | flutter_test: | 38 | flutter_test: |
35 | sdk: flutter | 39 | sdk: flutter |
40 | + get_test: 4.0.1 | ||
36 | 41 | ||
37 | # For information on the generic Dart part of this file, see the | 42 | # For information on the generic Dart part of this file, see the |
38 | # following page: https://dart.dev/tools/pub/pubspec | 43 | # following page: https://dart.dev/tools/pub/pubspec |
example/test/widget_test.dart
deleted
100644 → 0
1 | - |
1 | import 'dart:async'; | 1 | import 'dart:async'; |
2 | 2 | ||
3 | -import 'package:get/get.dart'; | ||
4 | import 'package:async/async.dart'; | 3 | import 'package:async/async.dart'; |
4 | +import 'package:get/get.dart'; | ||
5 | 5 | ||
6 | class SplashService extends GetxService { | 6 | class SplashService extends GetxService { |
7 | final welcomeStr = ['GetX', 'Rules!']; | 7 | final welcomeStr = ['GetX', 'Rules!']; |
1 | -import 'package:example_nav2/app/modules/splash/controllers/splash_service.dart'; | ||
2 | -import 'package:example_nav2/app/modules/splash/views/splash_view.dart'; | ||
3 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
4 | import 'package:get/get.dart'; | 2 | import 'package:get/get.dart'; |
5 | 3 | ||
4 | +import 'app/modules/splash/controllers/splash_service.dart'; | ||
5 | +import 'app/modules/splash/views/splash_view.dart'; | ||
6 | import 'app/routes/app_pages.dart'; | 6 | import 'app/routes/app_pages.dart'; |
7 | import 'services/auth_service.dart'; | 7 | import 'services/auth_service.dart'; |
8 | 8 |
@@ -76,3 +76,11 @@ mixin GetLifeCycleMixin { | @@ -76,3 +76,11 @@ mixin GetLifeCycleMixin { | ||
76 | 76 | ||
77 | /// Allow track difference between GetxServices and GetxControllers | 77 | /// Allow track difference between GetxServices and GetxControllers |
78 | mixin GetxServiceMixin {} | 78 | mixin GetxServiceMixin {} |
79 | + | ||
80 | +/// Unlike GetxController, which serves to control events on each of its pages, | ||
81 | +/// GetxService is not automatically disposed (nor can be removed with | ||
82 | +/// Get.delete()). | ||
83 | +/// It is ideal for situations where, once started, that service will | ||
84 | +/// remain in memory, such as Auth control for example. Only way to remove | ||
85 | +/// it is Get.reset(). | ||
86 | +abstract class GetxService with GetLifeCycleMixin, GetxServiceMixin {} |
@@ -2,9 +2,9 @@ import 'dart:async'; | @@ -2,9 +2,9 @@ import 'dart:async'; | ||
2 | 2 | ||
3 | import 'package:flutter/foundation.dart'; | 3 | import 'package:flutter/foundation.dart'; |
4 | import 'package:flutter/material.dart'; | 4 | import 'package:flutter/material.dart'; |
5 | + | ||
5 | import '../../../get.dart'; | 6 | import '../../../get.dart'; |
6 | import '../../../get_state_manager/src/simple/list_notifier.dart'; | 7 | import '../../../get_state_manager/src/simple/list_notifier.dart'; |
7 | -import 'get_navigator.dart'; | ||
8 | 8 | ||
9 | /// Enables the user to customize the intended pop behavior | 9 | /// Enables the user to customize the intended pop behavior |
10 | /// | 10 | /// |
@@ -4,6 +4,21 @@ import '../../../get.dart'; | @@ -4,6 +4,21 @@ import '../../../get.dart'; | ||
4 | import '../router_report.dart'; | 4 | import '../router_report.dart'; |
5 | import 'get_transition_mixin.dart'; | 5 | import 'get_transition_mixin.dart'; |
6 | 6 | ||
7 | +@optionalTypeArgs | ||
8 | +mixin RouteReportMixin<T extends StatefulWidget> on State<T> { | ||
9 | + @override | ||
10 | + void initState() { | ||
11 | + super.initState(); | ||
12 | + RouterReportManager.instance.reportCurrentRoute(this); | ||
13 | + } | ||
14 | + | ||
15 | + @override | ||
16 | + void dispose() { | ||
17 | + super.dispose(); | ||
18 | + RouterReportManager.instance.reportRouteDispose(this); | ||
19 | + } | ||
20 | +} | ||
21 | + | ||
7 | mixin PageRouteReportMixin<T> on Route<T> { | 22 | mixin PageRouteReportMixin<T> on Route<T> { |
8 | @override | 23 | @override |
9 | void install() { | 24 | void install() { |
1 | +import 'package:flutter/material.dart'; | ||
2 | + | ||
3 | +import '../router_report.dart'; | ||
4 | +import 'default_route.dart'; | ||
5 | + | ||
6 | +class RouteReport extends StatefulWidget { | ||
7 | + RouteReport({Key? key, required this.builder}) : super(key: key); | ||
8 | + final WidgetBuilder builder; | ||
9 | + | ||
10 | + @override | ||
11 | + _RouteReportState createState() => _RouteReportState(); | ||
12 | +} | ||
13 | + | ||
14 | +class _RouteReportState extends State<RouteReport> with RouteReportMixin { | ||
15 | + @override | ||
16 | + void initState() { | ||
17 | + RouterReportManager.instance.reportCurrentRoute(this); | ||
18 | + super.initState(); | ||
19 | + } | ||
20 | + | ||
21 | + @override | ||
22 | + void dispose() { | ||
23 | + RouterReportManager.instance.reportRouteDispose(this); | ||
24 | + super.dispose(); | ||
25 | + } | ||
26 | + | ||
27 | + @override | ||
28 | + Widget build(BuildContext context) { | ||
29 | + return widget.builder(context); | ||
30 | + } | ||
31 | +} |
@@ -102,9 +102,7 @@ mixin RxObjectMixin<T> on GetListenable<T> { | @@ -102,9 +102,7 @@ mixin RxObjectMixin<T> on GetListenable<T> { | ||
102 | sentToStream = false; | 102 | sentToStream = false; |
103 | if (value == val && !firstRebuild) return; | 103 | if (value == val && !firstRebuild) return; |
104 | firstRebuild = false; | 104 | firstRebuild = false; |
105 | - // _value = val; | ||
106 | sentToStream = true; | 105 | sentToStream = true; |
107 | - //TODO: Check this | ||
108 | super.value = val; | 106 | super.value = val; |
109 | } | 107 | } |
110 | 108 | ||
@@ -121,7 +119,6 @@ mixin RxObjectMixin<T> on GetListenable<T> { | @@ -121,7 +119,6 @@ mixin RxObjectMixin<T> on GetListenable<T> { | ||
121 | cancelOnError: cancelOnError, | 119 | cancelOnError: cancelOnError, |
122 | ); | 120 | ); |
123 | 121 | ||
124 | - //TODO: Change to refresh???? | ||
125 | subject.add(value); | 122 | subject.add(value); |
126 | 123 | ||
127 | return subscription; | 124 | return subscription; |
@@ -140,53 +137,6 @@ mixin RxObjectMixin<T> on GetListenable<T> { | @@ -140,53 +137,6 @@ mixin RxObjectMixin<T> on GetListenable<T> { | ||
140 | } | 137 | } |
141 | } | 138 | } |
142 | 139 | ||
143 | -//class RxNotifier<T> = RxInterface<T> with NotifyManager<T>; | ||
144 | - | ||
145 | -// mixin NotifyManager<T> { | ||
146 | -// GetStream<T> subject = GetStream<T>(); | ||
147 | -// final _subscriptions = <GetStream, List<StreamSubscription>>{}; | ||
148 | - | ||
149 | -// bool get canUpdate => _subscriptions.isNotEmpty; | ||
150 | - | ||
151 | -// /// This is an internal method. | ||
152 | -// /// Subscribe to changes on the inner stream. | ||
153 | -// void addListener(GetStream<T> rxGetx) { | ||
154 | -// if (!_subscriptions.containsKey(rxGetx)) { | ||
155 | -// final subs = rxGetx.listen((data) { | ||
156 | -// if (!subject.isClosed) subject.add(data); | ||
157 | -// }); | ||
158 | -// final listSubscriptions = | ||
159 | -// _subscriptions[rxGetx] ??= <StreamSubscription>[]; | ||
160 | -// listSubscriptions.add(subs); | ||
161 | -// } | ||
162 | -// } | ||
163 | - | ||
164 | -// StreamSubscription<T> listen( | ||
165 | -// void Function(T) onData, { | ||
166 | -// Function? onError, | ||
167 | -// void Function()? onDone, | ||
168 | -// bool? cancelOnError, | ||
169 | -// }) => | ||
170 | -// subject.listen( | ||
171 | -// onData, | ||
172 | -// onError: onError, | ||
173 | -// onDone: onDone, | ||
174 | -// cancelOnError: cancelOnError ?? false, | ||
175 | -// ); | ||
176 | - | ||
177 | -// /// Closes the subscriptions for this Rx, releasing the resources. | ||
178 | -// void close() { | ||
179 | -// _subscriptions.forEach((getStream, _subscriptions) { | ||
180 | -// for (final subscription in _subscriptions) { | ||
181 | -// subscription.cancel(); | ||
182 | -// } | ||
183 | -// }); | ||
184 | - | ||
185 | -// _subscriptions.clear(); | ||
186 | -// subject.close(); | ||
187 | -// } | ||
188 | -// } | ||
189 | - | ||
190 | /// Base Rx class that manages all the stream logic for any Type. | 140 | /// Base Rx class that manages all the stream logic for any Type. |
191 | abstract class _RxImpl<T> extends GetListenable<T> with RxObjectMixin<T> { | 141 | abstract class _RxImpl<T> extends GetListenable<T> with RxObjectMixin<T> { |
192 | _RxImpl(T initial) : super(initial); | 142 | _RxImpl(T initial) : super(initial); |
@@ -2,33 +2,15 @@ part of rx_types; | @@ -2,33 +2,15 @@ part of rx_types; | ||
2 | 2 | ||
3 | /// This class is the foundation for all reactive (Rx) classes that makes Get | 3 | /// This class is the foundation for all reactive (Rx) classes that makes Get |
4 | /// so powerful. | 4 | /// so powerful. |
5 | -/// This interface is the contract that _RxImpl]<T> uses in all it's | 5 | +/// This interface is the contract that [_RxImpl]<T> uses in all it's |
6 | /// subclass. | 6 | /// subclass. |
7 | -abstract class RxInterface<T> { | ||
8 | - //bool get canUpdate; | ||
9 | - | ||
10 | - /// Adds a listener to stream | ||
11 | - void addListener(VoidCallback listener); | ||
12 | - | 7 | +abstract class RxInterface<T> implements ValueListenable<T> { |
13 | /// Close the Rx Variable | 8 | /// Close the Rx Variable |
14 | void close(); | 9 | void close(); |
15 | 10 | ||
16 | /// Calls `callback` with current value, when the value changes. | 11 | /// Calls `callback` with current value, when the value changes. |
17 | StreamSubscription<T> listen(void Function(T event) onData, | 12 | StreamSubscription<T> listen(void Function(T event) onData, |
18 | {Function? onError, void Function()? onDone, bool? cancelOnError}); | 13 | {Function? onError, void Function()? onDone, bool? cancelOnError}); |
19 | - | ||
20 | - /// Avoids an unsafe usage of the `proxy` | ||
21 | - // static T notifyChildren<T>(RxNotifier observer, ValueGetter<T> builder) { | ||
22 | - // final _observer = RxInterface.proxy; | ||
23 | - // RxInterface.proxy = observer; | ||
24 | - // final result = builder(); | ||
25 | - // if (!observer.canUpdate) { | ||
26 | - // RxInterface.proxy = _observer; | ||
27 | - // throw ObxError(); | ||
28 | - // } | ||
29 | - // RxInterface.proxy = _observer; | ||
30 | - // return result; | ||
31 | - // } | ||
32 | } | 14 | } |
33 | 15 | ||
34 | class ObxError { | 16 | class ObxError { |
1 | library get_state_manager; | 1 | library get_state_manager; |
2 | 2 | ||
3 | -export 'src/rx_flutter/rx_disposable.dart'; | ||
4 | export 'src/rx_flutter/rx_getx_widget.dart'; | 3 | export 'src/rx_flutter/rx_getx_widget.dart'; |
5 | export 'src/rx_flutter/rx_notifier.dart'; | 4 | export 'src/rx_flutter/rx_notifier.dart'; |
6 | export 'src/rx_flutter/rx_obx_widget.dart'; | 5 | export 'src/rx_flutter/rx_obx_widget.dart'; |
@@ -9,5 +8,4 @@ export 'src/simple/get_controllers.dart'; | @@ -9,5 +8,4 @@ export 'src/simple/get_controllers.dart'; | ||
9 | export 'src/simple/get_responsive.dart'; | 8 | export 'src/simple/get_responsive.dart'; |
10 | export 'src/simple/get_state.dart'; | 9 | export 'src/simple/get_state.dart'; |
11 | export 'src/simple/get_view.dart'; | 10 | export 'src/simple/get_view.dart'; |
12 | -export 'src/simple/mixin_state.dart'; | ||
13 | export 'src/simple/simple_builder.dart'; | 11 | export 'src/simple/simple_builder.dart'; |
1 | -import '../../../get_instance/src/lifecycle.dart'; | ||
2 | - | ||
3 | -/// Unlike GetxController, which serves to control events on each of its pages, | ||
4 | -/// GetxService is not automatically disposed (nor can be removed with | ||
5 | -/// Get.delete()). | ||
6 | -/// It is ideal for situations where, once started, that service will | ||
7 | -/// remain in memory, such as Auth control for example. Only way to remove | ||
8 | -/// it is Get.reset(). | ||
9 | -abstract class GetxService with GetLifeCycleMixin, GetxServiceMixin {} | ||
10 | - | ||
11 | -// abstract class DisposableInterface with GetLifeCycleMixin {} |
@@ -113,20 +113,25 @@ class GetXState<T extends GetLifeCycleMixin> extends State<GetX<T>> { | @@ -113,20 +113,25 @@ class GetXState<T extends GetLifeCycleMixin> extends State<GetX<T>> { | ||
113 | disposer(); | 113 | disposer(); |
114 | } | 114 | } |
115 | 115 | ||
116 | + disposers.clear(); | ||
117 | + | ||
116 | controller = null; | 118 | controller = null; |
117 | _isCreator = null; | 119 | _isCreator = null; |
118 | super.dispose(); | 120 | super.dispose(); |
119 | } | 121 | } |
120 | 122 | ||
121 | void _update() { | 123 | void _update() { |
122 | - setState(() {}); | 124 | + if (mounted) { |
125 | + setState(() {}); | ||
126 | + } | ||
123 | } | 127 | } |
124 | 128 | ||
125 | final disposers = <Disposer>[]; | 129 | final disposers = <Disposer>[]; |
126 | 130 | ||
127 | @override | 131 | @override |
128 | - Widget build(BuildContext context) => NotifierManager.instance | ||
129 | - .exchange(disposers, _update, () => widget.builder(controller!)); | 132 | + Widget build(BuildContext context) => Notifier.instance.append( |
133 | + NotifyData(disposers: disposers, updater: _update), | ||
134 | + () => widget.builder(controller!)); | ||
130 | 135 | ||
131 | @override | 136 | @override |
132 | void debugFillProperties(DiagnosticPropertiesBuilder properties) { | 137 | void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
@@ -3,6 +3,7 @@ import 'dart:async'; | @@ -3,6 +3,7 @@ import 'dart:async'; | ||
3 | import 'package:flutter/foundation.dart'; | 3 | import 'package:flutter/foundation.dart'; |
4 | import 'package:flutter/material.dart'; | 4 | import 'package:flutter/material.dart'; |
5 | 5 | ||
6 | +import '../../../get_rx/src/rx_types/rx_types.dart'; | ||
6 | import '../../../instance_manager.dart'; | 7 | import '../../../instance_manager.dart'; |
7 | import '../../get_state_manager.dart'; | 8 | import '../../get_state_manager.dart'; |
8 | import '../simple/list_notifier.dart'; | 9 | import '../simple/list_notifier.dart'; |
@@ -78,8 +79,7 @@ mixin StateMixin<T> on ListNotifier { | @@ -78,8 +79,7 @@ mixin StateMixin<T> on ListNotifier { | ||
78 | } | 79 | } |
79 | } | 80 | } |
80 | 81 | ||
81 | -class GetListenable<T> extends ListNotifierSingle | ||
82 | - implements ValueListenable<T> { | 82 | +class GetListenable<T> extends ListNotifierSingle implements RxInterface<T> { |
83 | GetListenable(T val) : _value = val; | 83 | GetListenable(T val) : _value = val; |
84 | 84 | ||
85 | StreamController<T>? _controller; | 85 | StreamController<T>? _controller; |
@@ -96,6 +96,7 @@ class GetListenable<T> extends ListNotifierSingle | @@ -96,6 +96,7 @@ class GetListenable<T> extends ListNotifierSingle | ||
96 | _controller?.add(_value); | 96 | _controller?.add(_value); |
97 | } | 97 | } |
98 | 98 | ||
99 | + @override | ||
99 | @mustCallSuper | 100 | @mustCallSuper |
100 | void close() { | 101 | void close() { |
101 | removeListener(_streamListener); | 102 | removeListener(_streamListener); |
@@ -132,6 +133,7 @@ class GetListenable<T> extends ListNotifierSingle | @@ -132,6 +133,7 @@ class GetListenable<T> extends ListNotifierSingle | ||
132 | return value; | 133 | return value; |
133 | } | 134 | } |
134 | 135 | ||
136 | + @override | ||
135 | StreamSubscription<T> listen( | 137 | StreamSubscription<T> listen( |
136 | void Function(T)? onData, { | 138 | void Function(T)? onData, { |
137 | Function? onError, | 139 | Function? onError, |
@@ -188,6 +190,8 @@ class Value<T> extends ListNotifier | @@ -188,6 +190,8 @@ class Value<T> extends ListNotifier | ||
188 | dynamic toJson() => (value as dynamic)?.toJson(); | 190 | dynamic toJson() => (value as dynamic)?.toJson(); |
189 | } | 191 | } |
190 | 192 | ||
193 | +/// GetNotifier has a native status and state implementation, with the | ||
194 | +/// Get Lifecycle | ||
191 | abstract class GetNotifier<T> extends Value<T> with GetLifeCycleMixin { | 195 | abstract class GetNotifier<T> extends Value<T> with GetLifeCycleMixin { |
192 | GetNotifier(T initial) : super(initial); | 196 | GetNotifier(T initial) : super(initial); |
193 | } | 197 | } |
@@ -198,6 +202,7 @@ extension StateExt<T> on StateMixin<T> { | @@ -198,6 +202,7 @@ extension StateExt<T> on StateMixin<T> { | ||
198 | Widget Function(String? error)? onError, | 202 | Widget Function(String? error)? onError, |
199 | Widget? onLoading, | 203 | Widget? onLoading, |
200 | Widget? onEmpty, | 204 | Widget? onEmpty, |
205 | + WidgetBuilder? onCustom, | ||
201 | }) { | 206 | }) { |
202 | return Observer(builder: (_) { | 207 | return Observer(builder: (_) { |
203 | if (status.isLoading) { | 208 | if (status.isLoading) { |
@@ -210,6 +215,11 @@ extension StateExt<T> on StateMixin<T> { | @@ -210,6 +215,11 @@ extension StateExt<T> on StateMixin<T> { | ||
210 | return onEmpty != null | 215 | return onEmpty != null |
211 | ? onEmpty | 216 | ? onEmpty |
212 | : SizedBox.shrink(); // Also can be widget(null); but is risky | 217 | : SizedBox.shrink(); // Also can be widget(null); but is risky |
218 | + } else if (status.isSuccess) { | ||
219 | + return widget(value); | ||
220 | + } else if (status.isCustom) { | ||
221 | + return onCustom?.call(_) ?? | ||
222 | + SizedBox.shrink(); // Also can be widget(null); but is risky | ||
213 | } | 223 | } |
214 | return widget(value); | 224 | return widget(value); |
215 | }); | 225 | }); |
@@ -246,6 +256,7 @@ extension StatusDataExt<T> on GetState<T> { | @@ -246,6 +256,7 @@ extension StatusDataExt<T> on GetState<T> { | ||
246 | bool get isSuccess => this is SuccessState; | 256 | bool get isSuccess => this is SuccessState; |
247 | bool get isError => this is ErrorState; | 257 | bool get isError => this is ErrorState; |
248 | bool get isEmpty => this is EmptyState; | 258 | bool get isEmpty => this is EmptyState; |
259 | + bool get isCustom => !isLoading && !isSuccess && !isError && !isEmpty; | ||
249 | String get errorMessage { | 260 | String get errorMessage { |
250 | final isError = this is ErrorState; | 261 | final isError = this is ErrorState; |
251 | if (isError) { | 262 | if (isError) { |
@@ -26,6 +26,8 @@ abstract class GetxController extends ListNotifier with GetLifeCycleMixin { | @@ -26,6 +26,8 @@ abstract class GetxController extends ListNotifier with GetLifeCycleMixin { | ||
26 | } | 26 | } |
27 | } | 27 | } |
28 | 28 | ||
29 | +/// this mixin allow to fetch data when the scroll is at the bottom or on the | ||
30 | +/// top | ||
29 | mixin ScrollMixin on GetLifeCycleMixin { | 31 | mixin ScrollMixin on GetLifeCycleMixin { |
30 | final ScrollController scroll = ScrollController(); | 32 | final ScrollController scroll = ScrollController(); |
31 | 33 | ||
@@ -59,8 +61,10 @@ mixin ScrollMixin on GetLifeCycleMixin { | @@ -59,8 +61,10 @@ mixin ScrollMixin on GetLifeCycleMixin { | ||
59 | } | 61 | } |
60 | } | 62 | } |
61 | 63 | ||
64 | + /// this method is called when the scroll is at the bottom | ||
62 | Future<void> onEndScroll(); | 65 | Future<void> onEndScroll(); |
63 | 66 | ||
67 | + /// this method is called when the scroll is at the top | ||
64 | Future<void> onTopScroll(); | 68 | Future<void> onTopScroll(); |
65 | 69 | ||
66 | @override | 70 | @override |
@@ -70,13 +74,17 @@ mixin ScrollMixin on GetLifeCycleMixin { | @@ -70,13 +74,17 @@ mixin ScrollMixin on GetLifeCycleMixin { | ||
70 | } | 74 | } |
71 | } | 75 | } |
72 | 76 | ||
77 | +/// A clean controller to be used with only Rx variables | ||
73 | abstract class RxController with GetLifeCycleMixin {} | 78 | abstract class RxController with GetLifeCycleMixin {} |
74 | 79 | ||
80 | +/// A recommended way to use Getx with Future fetching | ||
75 | abstract class StateController<T> extends GetxController with StateMixin<T> {} | 81 | abstract class StateController<T> extends GetxController with StateMixin<T> {} |
76 | 82 | ||
83 | +/// A controller with super lifecycles (including native lifecycles) and StateMixins | ||
77 | abstract class SuperController<T> extends FullLifeCycleController | 84 | abstract class SuperController<T> extends FullLifeCycleController |
78 | with FullLifeCycleMixin, StateMixin<T> {} | 85 | with FullLifeCycleMixin, StateMixin<T> {} |
79 | 86 | ||
87 | +/// A controller with super lifecycles (including native lifecycles) | ||
80 | abstract class FullLifeCycleController extends GetxController | 88 | abstract class FullLifeCycleController extends GetxController |
81 | with | 89 | with |
82 | // ignore: prefer_mixin | 90 | // ignore: prefer_mixin |
@@ -116,8 +124,8 @@ mixin FullLifeCycleMixin on FullLifeCycleController { | @@ -116,8 +124,8 @@ mixin FullLifeCycleMixin on FullLifeCycleController { | ||
116 | } | 124 | } |
117 | } | 125 | } |
118 | 126 | ||
119 | - void onResumed(); | ||
120 | - void onPaused(); | ||
121 | - void onInactive(); | ||
122 | - void onDetached(); | 127 | + void onResumed() {} |
128 | + void onPaused() {} | ||
129 | + void onInactive() {} | ||
130 | + void onDetached() {} | ||
123 | } | 131 | } |
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; | @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; | ||
2 | 2 | ||
3 | import '../../../instance_manager.dart'; | 3 | import '../../../instance_manager.dart'; |
4 | import '../../get_state_manager.dart'; | 4 | import '../../get_state_manager.dart'; |
5 | +import 'list_notifier.dart'; | ||
5 | 6 | ||
6 | typedef InitBuilder<T> = T Function(); | 7 | typedef InitBuilder<T> = T Function(); |
7 | 8 | ||
@@ -37,7 +38,7 @@ class GetBuilder<T extends GetxController> extends StatelessWidget { | @@ -37,7 +38,7 @@ class GetBuilder<T extends GetxController> extends StatelessWidget { | ||
37 | final void Function(BindElement<T> state)? initState, | 38 | final void Function(BindElement<T> state)? initState, |
38 | dispose, | 39 | dispose, |
39 | didChangeDependencies; | 40 | didChangeDependencies; |
40 | - final void Function(BindWrapper<T> oldWidget, BindElement<T> state)? | 41 | + final void Function(Binder<T> oldWidget, BindElement<T> state)? |
41 | didUpdateWidget; | 42 | didUpdateWidget; |
42 | final T? init; | 43 | final T? init; |
43 | 44 | ||
@@ -59,7 +60,7 @@ class GetBuilder<T extends GetxController> extends StatelessWidget { | @@ -59,7 +60,7 @@ class GetBuilder<T extends GetxController> extends StatelessWidget { | ||
59 | 60 | ||
60 | @override | 61 | @override |
61 | Widget build(BuildContext context) { | 62 | Widget build(BuildContext context) { |
62 | - return BindWrapper( | 63 | + return Binder( |
63 | init: init == null ? null : () => init!, | 64 | init: init == null ? null : () => init!, |
64 | global: global, | 65 | global: global, |
65 | autoRemove: autoRemove, | 66 | autoRemove: autoRemove, |
@@ -108,7 +109,7 @@ abstract class Bind<T> extends StatelessWidget { | @@ -108,7 +109,7 @@ abstract class Bind<T> extends StatelessWidget { | ||
108 | final void Function(BindElement<T> state)? initState, | 109 | final void Function(BindElement<T> state)? initState, |
109 | dispose, | 110 | dispose, |
110 | didChangeDependencies; | 111 | didChangeDependencies; |
111 | - final void Function(BindWrapper<T> oldWidget, BindElement<T> state)? | 112 | + final void Function(Binder<T> oldWidget, BindElement<T> state)? |
112 | didUpdateWidget; | 113 | didUpdateWidget; |
113 | 114 | ||
114 | final Widget? child; | 115 | final Widget? child; |
@@ -193,8 +194,7 @@ abstract class Bind<T> extends StatelessWidget { | @@ -193,8 +194,7 @@ abstract class Bind<T> extends StatelessWidget { | ||
193 | void Function(BindElement<T> state)? initState, | 194 | void Function(BindElement<T> state)? initState, |
194 | void Function(BindElement<T> state)? dispose, | 195 | void Function(BindElement<T> state)? dispose, |
195 | void Function(BindElement<T> state)? didChangeDependencies, | 196 | void Function(BindElement<T> state)? didChangeDependencies, |
196 | - void Function(BindWrapper<T> oldWidget, BindElement<T> state)? | ||
197 | - didUpdateWidget, | 197 | + void Function(Binder<T> oldWidget, BindElement<T> state)? didUpdateWidget, |
198 | }) => | 198 | }) => |
199 | _FactoryBind<T>( | 199 | _FactoryBind<T>( |
200 | // key: key, | 200 | // key: key, |
@@ -218,7 +218,7 @@ abstract class Bind<T> extends StatelessWidget { | @@ -218,7 +218,7 @@ abstract class Bind<T> extends StatelessWidget { | ||
218 | // Object Function(T value)? filter, | 218 | // Object Function(T value)? filter, |
219 | }) { | 219 | }) { |
220 | final inheritedElement = | 220 | final inheritedElement = |
221 | - context.getElementForInheritedWidgetOfExactType<BindWrapper<T>>() | 221 | + context.getElementForInheritedWidgetOfExactType<Binder<T>>() |
222 | as BindElement<T>?; | 222 | as BindElement<T>?; |
223 | 223 | ||
224 | if (inheritedElement == null) { | 224 | if (inheritedElement == null) { |
@@ -265,7 +265,7 @@ class _FactoryBind<T> extends Bind<T> { | @@ -265,7 +265,7 @@ class _FactoryBind<T> extends Bind<T> { | ||
265 | dispose, | 265 | dispose, |
266 | didChangeDependencies; | 266 | didChangeDependencies; |
267 | @override | 267 | @override |
268 | - final void Function(BindWrapper<T> oldWidget, BindElement<T> state)? | 268 | + final void Function(Binder<T> oldWidget, BindElement<T> state)? |
269 | didUpdateWidget; | 269 | didUpdateWidget; |
270 | 270 | ||
271 | @override | 271 | @override |
@@ -307,7 +307,7 @@ class _FactoryBind<T> extends Bind<T> { | @@ -307,7 +307,7 @@ class _FactoryBind<T> extends Bind<T> { | ||
307 | 307 | ||
308 | @override | 308 | @override |
309 | Widget build(BuildContext context) { | 309 | Widget build(BuildContext context) { |
310 | - return BindWrapper<T>( | 310 | + return Binder<T>( |
311 | init: init, | 311 | init: init, |
312 | global: global, | 312 | global: global, |
313 | autoRemove: autoRemove, | 313 | autoRemove: autoRemove, |
@@ -340,12 +340,12 @@ class Binds extends StatelessWidget { | @@ -340,12 +340,12 @@ class Binds extends StatelessWidget { | ||
340 | binds.reversed.fold(child, (acc, e) => e._copyWithChild(acc)); | 340 | binds.reversed.fold(child, (acc, e) => e._copyWithChild(acc)); |
341 | } | 341 | } |
342 | 342 | ||
343 | -class BindWrapper<T> extends InheritedWidget { | 343 | +class Binder<T> extends InheritedWidget { |
344 | /// Create an inherited widget that updates its dependents when [controller] | 344 | /// Create an inherited widget that updates its dependents when [controller] |
345 | /// sends notifications. | 345 | /// sends notifications. |
346 | /// | 346 | /// |
347 | /// The [child] argument is required | 347 | /// The [child] argument is required |
348 | - const BindWrapper({ | 348 | + const Binder({ |
349 | Key? key, | 349 | Key? key, |
350 | required Widget child, | 350 | required Widget child, |
351 | this.init, | 351 | this.init, |
@@ -371,11 +371,11 @@ class BindWrapper<T> extends InheritedWidget { | @@ -371,11 +371,11 @@ class BindWrapper<T> extends InheritedWidget { | ||
371 | final void Function(BindElement<T> state)? initState, | 371 | final void Function(BindElement<T> state)? initState, |
372 | dispose, | 372 | dispose, |
373 | didChangeDependencies; | 373 | didChangeDependencies; |
374 | - final void Function(BindWrapper<T> oldWidget, BindElement<T> state)? | 374 | + final void Function(Binder<T> oldWidget, BindElement<T> state)? |
375 | didUpdateWidget; | 375 | didUpdateWidget; |
376 | 376 | ||
377 | @override | 377 | @override |
378 | - bool updateShouldNotify(BindWrapper<T> oldWidget) { | 378 | + bool updateShouldNotify(Binder<T> oldWidget) { |
379 | return oldWidget.id != id || | 379 | return oldWidget.id != id || |
380 | oldWidget.global != global || | 380 | oldWidget.global != global || |
381 | oldWidget.autoRemove != autoRemove || | 381 | oldWidget.autoRemove != autoRemove || |
@@ -389,10 +389,12 @@ class BindWrapper<T> extends InheritedWidget { | @@ -389,10 +389,12 @@ class BindWrapper<T> extends InheritedWidget { | ||
389 | /// The BindElement is responsible for injecting dependencies into the widget | 389 | /// The BindElement is responsible for injecting dependencies into the widget |
390 | /// tree so that they can be observed | 390 | /// tree so that they can be observed |
391 | class BindElement<T> extends InheritedElement { | 391 | class BindElement<T> extends InheritedElement { |
392 | - BindElement(BindWrapper<T> widget) : super(widget) { | 392 | + BindElement(Binder<T> widget) : super(widget) { |
393 | initState(); | 393 | initState(); |
394 | } | 394 | } |
395 | 395 | ||
396 | + final disposers = <Disposer>[]; | ||
397 | + | ||
396 | InitBuilder<T>? _controllerBuilder; | 398 | InitBuilder<T>? _controllerBuilder; |
397 | 399 | ||
398 | T? _controller; | 400 | T? _controller; |
@@ -486,6 +488,12 @@ class BindElement<T> extends InheritedElement { | @@ -486,6 +488,12 @@ class BindElement<T> extends InheritedElement { | ||
486 | } | 488 | } |
487 | } | 489 | } |
488 | 490 | ||
491 | + for (final disposer in disposers) { | ||
492 | + disposer(); | ||
493 | + } | ||
494 | + | ||
495 | + disposers.clear(); | ||
496 | + | ||
489 | _remove?.call(); | 497 | _remove?.call(); |
490 | _controller = null; | 498 | _controller = null; |
491 | _isCreator = null; | 499 | _isCreator = null; |
@@ -497,12 +505,12 @@ class BindElement<T> extends InheritedElement { | @@ -497,12 +505,12 @@ class BindElement<T> extends InheritedElement { | ||
497 | } | 505 | } |
498 | 506 | ||
499 | @override | 507 | @override |
500 | - BindWrapper<T> get widget => super.widget as BindWrapper<T>; | 508 | + Binder<T> get widget => super.widget as Binder<T>; |
501 | 509 | ||
502 | var _dirty = false; | 510 | var _dirty = false; |
503 | 511 | ||
504 | @override | 512 | @override |
505 | - void update(BindWrapper<T> newWidget) { | 513 | + void update(Binder<T> newWidget) { |
506 | final oldNotifier = widget.id; | 514 | final oldNotifier = widget.id; |
507 | final newNotifier = newWidget.id; | 515 | final newNotifier = newWidget.id; |
508 | if (oldNotifier != newNotifier && _wasStarted) { | 516 | if (oldNotifier != newNotifier && _wasStarted) { |
@@ -523,7 +531,11 @@ class BindElement<T> extends InheritedElement { | @@ -523,7 +531,11 @@ class BindElement<T> extends InheritedElement { | ||
523 | if (_dirty) { | 531 | if (_dirty) { |
524 | notifyClients(widget); | 532 | notifyClients(widget); |
525 | } | 533 | } |
534 | + // return Notifier.instance.notifyAppend( | ||
535 | + // NotifyData( | ||
536 | + // disposers: disposers, updater: getUpdate, throwException: false), | ||
526 | return super.build(); | 537 | return super.build(); |
538 | + //); | ||
527 | } | 539 | } |
528 | 540 | ||
529 | void getUpdate() { | 541 | void getUpdate() { |
@@ -532,7 +544,7 @@ class BindElement<T> extends InheritedElement { | @@ -532,7 +544,7 @@ class BindElement<T> extends InheritedElement { | ||
532 | } | 544 | } |
533 | 545 | ||
534 | @override | 546 | @override |
535 | - void notifyClients(BindWrapper<T> oldWidget) { | 547 | + void notifyClients(Binder<T> oldWidget) { |
536 | super.notifyClients(oldWidget); | 548 | super.notifyClients(oldWidget); |
537 | _dirty = false; | 549 | _dirty = false; |
538 | } | 550 | } |
@@ -12,10 +12,14 @@ typedef GetStateUpdate = void Function(); | @@ -12,10 +12,14 @@ typedef GetStateUpdate = void Function(); | ||
12 | class ListNotifier extends Listenable | 12 | class ListNotifier extends Listenable |
13 | with ListNotifierSingleMixin, ListNotifierGroupMixin {} | 13 | with ListNotifierSingleMixin, ListNotifierGroupMixin {} |
14 | 14 | ||
15 | +/// A Notifier with single listeners | ||
15 | class ListNotifierSingle = ListNotifier with ListNotifierSingleMixin; | 16 | class ListNotifierSingle = ListNotifier with ListNotifierSingleMixin; |
16 | 17 | ||
18 | +/// A notifier with group of listeners identified by id | ||
17 | class ListNotifierGroup = ListNotifier with ListNotifierGroupMixin; | 19 | class ListNotifierGroup = ListNotifier with ListNotifierGroupMixin; |
18 | 20 | ||
21 | +/// This mixin add to Listenable the addListener, removerListener and | ||
22 | +/// containsListener implementation | ||
19 | mixin ListNotifierSingleMixin on Listenable { | 23 | mixin ListNotifierSingleMixin on Listenable { |
20 | List<GetStateUpdate?>? _updaters = <GetStateUpdate?>[]; | 24 | List<GetStateUpdate?>? _updaters = <GetStateUpdate?>[]; |
21 | 25 | ||
@@ -44,12 +48,12 @@ mixin ListNotifierSingleMixin on Listenable { | @@ -44,12 +48,12 @@ mixin ListNotifierSingleMixin on Listenable { | ||
44 | 48 | ||
45 | @protected | 49 | @protected |
46 | void reportRead() { | 50 | void reportRead() { |
47 | - NotifierManager.instance.notify(this); | 51 | + Notifier.instance.read(this); |
48 | } | 52 | } |
49 | 53 | ||
50 | @protected | 54 | @protected |
51 | void reportAdd(VoidCallback disposer) { | 55 | void reportAdd(VoidCallback disposer) { |
52 | - NotifierManager.instance.reportAdd(disposer); | 56 | + Notifier.instance.add(disposer); |
53 | } | 57 | } |
54 | 58 | ||
55 | void _notifyUpdate() { | 59 | void _notifyUpdate() { |
@@ -96,7 +100,7 @@ mixin ListNotifierGroupMixin on Listenable { | @@ -96,7 +100,7 @@ mixin ListNotifierGroupMixin on Listenable { | ||
96 | @protected | 100 | @protected |
97 | void notifyGroupChildrens(Object id) { | 101 | void notifyGroupChildrens(Object id) { |
98 | assert(_debugAssertNotDisposed()); | 102 | assert(_debugAssertNotDisposed()); |
99 | - NotifierManager.instance.notify(_updatersGroupIds![id]!); | 103 | + Notifier.instance.read(_updatersGroupIds![id]!); |
100 | } | 104 | } |
101 | 105 | ||
102 | bool containsId(Object id) { | 106 | bool containsId(Object id) { |
@@ -148,44 +152,47 @@ mixin ListNotifierGroupMixin on Listenable { | @@ -148,44 +152,47 @@ mixin ListNotifierGroupMixin on Listenable { | ||
148 | } | 152 | } |
149 | } | 153 | } |
150 | 154 | ||
151 | -class NotifierManager { | ||
152 | - NotifierManager._(); | 155 | +class Notifier { |
156 | + Notifier._(); | ||
153 | 157 | ||
154 | - static NotifierManager? _instance; | 158 | + static Notifier? _instance; |
159 | + static Notifier get instance => _instance ??= Notifier._(); | ||
155 | 160 | ||
156 | - static NotifierManager get instance => _instance ??= NotifierManager._(); | 161 | + NotifyData? _notifyData; |
157 | 162 | ||
158 | - GetStateUpdate? _setter; | ||
159 | - List<VoidCallback>? _remove; | ||
160 | - | ||
161 | - void reportAdd(VoidCallback listener) { | ||
162 | - _remove?.add(listener); | 163 | + void add(VoidCallback listener) { |
164 | + _notifyData?.disposers.add(listener); | ||
163 | } | 165 | } |
164 | 166 | ||
165 | - void notify(ListNotifierSingleMixin _updaters) { | ||
166 | - final listener = _setter; | ||
167 | - if (listener != null) { | ||
168 | - if (!_updaters.containsListener(listener)) { | ||
169 | - _updaters.addListener(listener); | ||
170 | - reportAdd(() => _updaters.removeListener(listener)); | ||
171 | - } | 167 | + void read(ListNotifierSingleMixin _updaters) { |
168 | + final listener = _notifyData?.updater; | ||
169 | + if (listener != null && !_updaters.containsListener(listener)) { | ||
170 | + _updaters.addListener(listener); | ||
171 | + add(() => _updaters.removeListener(listener)); | ||
172 | } | 172 | } |
173 | } | 173 | } |
174 | 174 | ||
175 | - T exchange<T>(List<VoidCallback> disposers, GetStateUpdate setState, | ||
176 | - T Function() builder) { | ||
177 | - _remove = disposers; | ||
178 | - _setter = setState; | 175 | + T append<T>(NotifyData data, T Function() builder) { |
176 | + _notifyData = data; | ||
179 | final result = builder(); | 177 | final result = builder(); |
180 | - if (disposers.isEmpty) { | 178 | + if (data.disposers.isEmpty && data.throwException) { |
181 | throw ObxError(); | 179 | throw ObxError(); |
182 | } | 180 | } |
183 | - _remove = null; | ||
184 | - _setter = null; | 181 | + _notifyData = data; |
185 | return result; | 182 | return result; |
186 | } | 183 | } |
187 | } | 184 | } |
188 | 185 | ||
186 | +class NotifyData { | ||
187 | + const NotifyData( | ||
188 | + {required this.updater, | ||
189 | + required this.disposers, | ||
190 | + this.throwException = true}); | ||
191 | + final GetStateUpdate updater; | ||
192 | + final List<VoidCallback> disposers; | ||
193 | + final bool throwException; | ||
194 | +} | ||
195 | + | ||
189 | class ObxError { | 196 | class ObxError { |
190 | const ObxError(); | 197 | const ObxError(); |
191 | @override | 198 | @override |
1 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
2 | 2 | ||
3 | -import '../../get_state_manager.dart'; | 3 | +import '../rx_flutter/rx_obx_widget.dart'; |
4 | +import 'get_controllers.dart'; | ||
5 | +import 'get_state.dart'; | ||
4 | 6 | ||
5 | class MixinBuilder<T extends GetxController> extends StatelessWidget { | 7 | class MixinBuilder<T extends GetxController> extends StatelessWidget { |
6 | @required | 8 | @required |
@@ -11,7 +13,7 @@ class MixinBuilder<T extends GetxController> extends StatelessWidget { | @@ -11,7 +13,7 @@ class MixinBuilder<T extends GetxController> extends StatelessWidget { | ||
11 | final void Function(BindElement<T> state)? initState, | 13 | final void Function(BindElement<T> state)? initState, |
12 | dispose, | 14 | dispose, |
13 | didChangeDependencies; | 15 | didChangeDependencies; |
14 | - final void Function(BindWrapper<T> oldWidget, BindElement<T> state)? | 16 | + final void Function(Binder<T> oldWidget, BindElement<T> state)? |
15 | didUpdateWidget; | 17 | didUpdateWidget; |
16 | final T? init; | 18 | final T? init; |
17 | 19 |
@@ -45,7 +45,6 @@ class _ValueBuilderState<T> extends State<ValueBuilder<T>> { | @@ -45,7 +45,6 @@ class _ValueBuilderState<T> extends State<ValueBuilder<T>> { | ||
45 | T value; | 45 | T value; |
46 | _ValueBuilderState(this.value); | 46 | _ValueBuilderState(this.value); |
47 | 47 | ||
48 | - | ||
49 | @override | 48 | @override |
50 | Widget build(BuildContext context) => widget.builder(value, updater); | 49 | Widget build(BuildContext context) => widget.builder(value, updater); |
51 | 50 | ||
@@ -92,17 +91,27 @@ abstract class ObxStatelessWidget extends StatelessWidget { | @@ -92,17 +91,27 @@ abstract class ObxStatelessWidget extends StatelessWidget { | ||
92 | 91 | ||
93 | /// a Component that can track changes in a reactive variable | 92 | /// a Component that can track changes in a reactive variable |
94 | mixin ObserverComponent on ComponentElement { | 93 | mixin ObserverComponent on ComponentElement { |
95 | - final disposers = <Disposer>[]; | 94 | + List<Disposer>? disposers = <Disposer>[]; |
95 | + | ||
96 | + void getUpdate() { | ||
97 | + if (disposers != null) { | ||
98 | + markNeedsBuild(); | ||
99 | + } | ||
100 | + } | ||
96 | 101 | ||
97 | @override | 102 | @override |
98 | - Widget build() => | ||
99 | - NotifierManager.instance.exchange(disposers, markNeedsBuild, super.build); | 103 | + Widget build() { |
104 | + return Notifier.instance.append( | ||
105 | + NotifyData(disposers: disposers!, updater: getUpdate), super.build); | ||
106 | + } | ||
100 | 107 | ||
101 | @override | 108 | @override |
102 | void unmount() { | 109 | void unmount() { |
103 | super.unmount(); | 110 | super.unmount(); |
104 | - for (final disposer in disposers) { | 111 | + for (final disposer in disposers!) { |
105 | disposer(); | 112 | disposer(); |
106 | } | 113 | } |
114 | + disposers!.clear(); | ||
115 | + disposers = null; | ||
107 | } | 116 | } |
108 | } | 117 | } |
1 | import 'package:collection/collection.dart'; | 1 | import 'package:collection/collection.dart'; |
2 | import 'package:flutter/material.dart'; | 2 | import 'package:flutter/material.dart'; |
3 | 3 | ||
4 | -extension ContextExtensionss on BuildContext { | 4 | +extension ContextExt on BuildContext { |
5 | /// The same of [MediaQuery.of(context).size] | 5 | /// The same of [MediaQuery.of(context).size] |
6 | Size get mediaQuerySize => MediaQuery.of(this).size; | 6 | Size get mediaQuerySize => MediaQuery.of(this).size; |
7 | 7 | ||
@@ -105,8 +105,8 @@ extension ContextExtensionss on BuildContext { | @@ -105,8 +105,8 @@ extension ContextExtensionss on BuildContext { | ||
105 | /// True if the width is higher than 600p | 105 | /// True if the width is higher than 600p |
106 | bool get isPhoneOrWider => width >= 600; | 106 | bool get isPhoneOrWider => width >= 600; |
107 | 107 | ||
108 | - /// same as [isPhoneOrLess] | ||
109 | - bool get isPhone => isPhoneOrLess; | 108 | + /// True if the shortestSide is smaller than 600p |
109 | + bool get isPhone => (mediaQueryShortestSide < 600); | ||
110 | 110 | ||
111 | /// True if the width is smaller than 600p | 111 | /// True if the width is smaller than 600p |
112 | bool get isSmallTabletOrLess => width <= 600; | 112 | bool get isSmallTabletOrLess => width <= 600; |
@@ -114,8 +114,11 @@ extension ContextExtensionss on BuildContext { | @@ -114,8 +114,11 @@ extension ContextExtensionss on BuildContext { | ||
114 | /// True if the width is higher than 600p | 114 | /// True if the width is higher than 600p |
115 | bool get isSmallTabletOrWider => width >= 600; | 115 | bool get isSmallTabletOrWider => width >= 600; |
116 | 116 | ||
117 | - /// same as [isSmallTabletOrLess] | ||
118 | - bool get isSmallTablet => isSmallTabletOrLess; | 117 | + /// True if the shortestSide is largest than 600p |
118 | + bool get isSmallTablet => (mediaQueryShortestSide >= 600); | ||
119 | + | ||
120 | + /// True if the shortestSide is largest than 720p | ||
121 | + bool get isLargeTablet => (mediaQueryShortestSide >= 720); | ||
119 | 122 | ||
120 | /// True if the width is smaller than 720p | 123 | /// True if the width is smaller than 720p |
121 | bool get isLargeTabletOrLess => width <= 720; | 124 | bool get isLargeTabletOrLess => width <= 720; |
@@ -123,11 +126,8 @@ extension ContextExtensionss on BuildContext { | @@ -123,11 +126,8 @@ extension ContextExtensionss on BuildContext { | ||
123 | /// True if the width is higher than 720p | 126 | /// True if the width is higher than 720p |
124 | bool get isLargeTabletOrWider => width >= 720; | 127 | bool get isLargeTabletOrWider => width >= 720; |
125 | 128 | ||
126 | - /// same as [isLargeTabletOrLess] | ||
127 | - bool get isLargeTablet => isLargeTabletOrLess; | ||
128 | - | ||
129 | /// True if the current device is Tablet | 129 | /// True if the current device is Tablet |
130 | - bool get isTablet => isSmallTablet; | 130 | + bool get isTablet => isSmallTablet || isLargeTablet; |
131 | 131 | ||
132 | /// True if the width is smaller than 1200p | 132 | /// True if the width is smaller than 1200p |
133 | bool get isDesktopOrLess => width <= 1200; | 133 | bool get isDesktopOrLess => width <= 1200; |
1 | import '../get_utils/get_utils.dart'; | 1 | import '../get_utils/get_utils.dart'; |
2 | 2 | ||
3 | extension GetDynamicUtils on dynamic { | 3 | extension GetDynamicUtils on dynamic { |
4 | - @Deprecated('isNull is deprecated and cannot be used, use "==" operator') | ||
5 | - bool get isNull => GetUtils.isNull(this); | ||
6 | - | ||
7 | bool? get isBlank => GetUtils.isBlank(this); | 4 | bool? get isBlank => GetUtils.isBlank(this); |
8 | 5 | ||
9 | @Deprecated( | 6 | @Deprecated( |
1 | import '../get_utils/get_utils.dart'; | 1 | import '../get_utils/get_utils.dart'; |
2 | 2 | ||
3 | extension GetStringUtils on String { | 3 | extension GetStringUtils on String { |
4 | + /// Discover if the String is a valid number | ||
4 | bool get isNum => GetUtils.isNum(this); | 5 | bool get isNum => GetUtils.isNum(this); |
5 | 6 | ||
7 | + /// Discover if the String is numeric only | ||
6 | bool get isNumericOnly => GetUtils.isNumericOnly(this); | 8 | bool get isNumericOnly => GetUtils.isNumericOnly(this); |
7 | 9 | ||
10 | + String numericOnly({bool firstWordOnly = false}) => | ||
11 | + GetUtils.numericOnly(this, firstWordOnly: firstWordOnly); | ||
12 | + | ||
13 | + /// Discover if the String is alphanumeric only | ||
8 | bool get isAlphabetOnly => GetUtils.isAlphabetOnly(this); | 14 | bool get isAlphabetOnly => GetUtils.isAlphabetOnly(this); |
9 | 15 | ||
16 | + /// Discover if the String is a boolean | ||
10 | bool get isBool => GetUtils.isBool(this); | 17 | bool get isBool => GetUtils.isBool(this); |
11 | 18 | ||
19 | + /// Discover if the String is a vector | ||
12 | bool get isVectorFileName => GetUtils.isVector(this); | 20 | bool get isVectorFileName => GetUtils.isVector(this); |
13 | 21 | ||
22 | + /// Discover if the String is a ImageFileName | ||
14 | bool get isImageFileName => GetUtils.isImage(this); | 23 | bool get isImageFileName => GetUtils.isImage(this); |
15 | 24 | ||
25 | + /// Discover if the String is a AudioFileName | ||
16 | bool get isAudioFileName => GetUtils.isAudio(this); | 26 | bool get isAudioFileName => GetUtils.isAudio(this); |
17 | 27 | ||
28 | + /// Discover if the String is a VideoFileName | ||
18 | bool get isVideoFileName => GetUtils.isVideo(this); | 29 | bool get isVideoFileName => GetUtils.isVideo(this); |
19 | 30 | ||
31 | + /// Discover if the String is a TxtFileName | ||
20 | bool get isTxtFileName => GetUtils.isTxt(this); | 32 | bool get isTxtFileName => GetUtils.isTxt(this); |
21 | 33 | ||
34 | + /// Discover if the String is a Document Word | ||
22 | bool get isDocumentFileName => GetUtils.isWord(this); | 35 | bool get isDocumentFileName => GetUtils.isWord(this); |
23 | 36 | ||
37 | + /// Discover if the String is a Document Excel | ||
24 | bool get isExcelFileName => GetUtils.isExcel(this); | 38 | bool get isExcelFileName => GetUtils.isExcel(this); |
25 | 39 | ||
40 | + /// Discover if the String is a Document Powerpoint | ||
26 | bool get isPPTFileName => GetUtils.isPPT(this); | 41 | bool get isPPTFileName => GetUtils.isPPT(this); |
27 | 42 | ||
43 | + /// Discover if the String is a APK File | ||
28 | bool get isAPKFileName => GetUtils.isAPK(this); | 44 | bool get isAPKFileName => GetUtils.isAPK(this); |
29 | 45 | ||
46 | + /// Discover if the String is a PDF file | ||
30 | bool get isPDFFileName => GetUtils.isPDF(this); | 47 | bool get isPDFFileName => GetUtils.isPDF(this); |
31 | 48 | ||
49 | + /// Discover if the String is a HTML file | ||
32 | bool get isHTMLFileName => GetUtils.isHTML(this); | 50 | bool get isHTMLFileName => GetUtils.isHTML(this); |
33 | 51 | ||
52 | + /// Discover if the String is a URL file | ||
34 | bool get isURL => GetUtils.isURL(this); | 53 | bool get isURL => GetUtils.isURL(this); |
35 | 54 | ||
55 | + /// Discover if the String is a Email | ||
36 | bool get isEmail => GetUtils.isEmail(this); | 56 | bool get isEmail => GetUtils.isEmail(this); |
37 | 57 | ||
58 | + /// Discover if the String is a Phone Number | ||
38 | bool get isPhoneNumber => GetUtils.isPhoneNumber(this); | 59 | bool get isPhoneNumber => GetUtils.isPhoneNumber(this); |
39 | 60 | ||
61 | + /// Discover if the String is a DateTime | ||
40 | bool get isDateTime => GetUtils.isDateTime(this); | 62 | bool get isDateTime => GetUtils.isDateTime(this); |
41 | 63 | ||
64 | + /// Discover if the String is a MD5 Hash | ||
42 | bool get isMD5 => GetUtils.isMD5(this); | 65 | bool get isMD5 => GetUtils.isMD5(this); |
43 | 66 | ||
67 | + /// Discover if the String is a SHA1 Hash | ||
44 | bool get isSHA1 => GetUtils.isSHA1(this); | 68 | bool get isSHA1 => GetUtils.isSHA1(this); |
45 | 69 | ||
70 | + /// Discover if the String is a SHA256 Hash | ||
46 | bool get isSHA256 => GetUtils.isSHA256(this); | 71 | bool get isSHA256 => GetUtils.isSHA256(this); |
47 | 72 | ||
73 | + /// Discover if the String is a bynary value | ||
48 | bool get isBinary => GetUtils.isBinary(this); | 74 | bool get isBinary => GetUtils.isBinary(this); |
49 | 75 | ||
76 | + /// Discover if the String is a ipv4 | ||
50 | bool get isIPv4 => GetUtils.isIPv4(this); | 77 | bool get isIPv4 => GetUtils.isIPv4(this); |
51 | 78 | ||
52 | bool get isIPv6 => GetUtils.isIPv6(this); | 79 | bool get isIPv6 => GetUtils.isIPv6(this); |
53 | 80 | ||
81 | + /// Discover if the String is a Hexadecimal | ||
54 | bool get isHexadecimal => GetUtils.isHexadecimal(this); | 82 | bool get isHexadecimal => GetUtils.isHexadecimal(this); |
55 | 83 | ||
84 | + /// Discover if the String is a palindrom | ||
56 | bool get isPalindrom => GetUtils.isPalindrom(this); | 85 | bool get isPalindrom => GetUtils.isPalindrom(this); |
57 | 86 | ||
87 | + /// Discover if the String is a passport number | ||
58 | bool get isPassport => GetUtils.isPassport(this); | 88 | bool get isPassport => GetUtils.isPassport(this); |
59 | 89 | ||
90 | + /// Discover if the String is a currency | ||
60 | bool get isCurrency => GetUtils.isCurrency(this); | 91 | bool get isCurrency => GetUtils.isCurrency(this); |
61 | 92 | ||
93 | + /// Discover if the String is a CPF number | ||
62 | bool get isCpf => GetUtils.isCpf(this); | 94 | bool get isCpf => GetUtils.isCpf(this); |
63 | 95 | ||
96 | + /// Discover if the String is a CNPJ number | ||
64 | bool get isCnpj => GetUtils.isCnpj(this); | 97 | bool get isCnpj => GetUtils.isCnpj(this); |
65 | 98 | ||
99 | + /// Discover if the String is a case insensitive | ||
66 | bool isCaseInsensitiveContains(String b) => | 100 | bool isCaseInsensitiveContains(String b) => |
67 | GetUtils.isCaseInsensitiveContains(this, b); | 101 | GetUtils.isCaseInsensitiveContains(this, b); |
68 | 102 | ||
103 | + /// Discover if the String is a case sensitive and contains any value | ||
69 | bool isCaseInsensitiveContainsAny(String b) => | 104 | bool isCaseInsensitiveContainsAny(String b) => |
70 | GetUtils.isCaseInsensitiveContainsAny(this, b); | 105 | GetUtils.isCaseInsensitiveContainsAny(this, b); |
71 | 106 | ||
107 | + /// capitalize the String | ||
72 | String? get capitalize => GetUtils.capitalize(this); | 108 | String? get capitalize => GetUtils.capitalize(this); |
73 | 109 | ||
110 | + /// Capitalize the first letter of the String | ||
74 | String? get capitalizeFirst => GetUtils.capitalizeFirst(this); | 111 | String? get capitalizeFirst => GetUtils.capitalizeFirst(this); |
75 | 112 | ||
113 | + /// remove all whitespace from the String | ||
76 | String get removeAllWhitespace => GetUtils.removeAllWhitespace(this); | 114 | String get removeAllWhitespace => GetUtils.removeAllWhitespace(this); |
77 | 115 | ||
116 | + /// converter the String | ||
78 | String? get camelCase => GetUtils.camelCase(this); | 117 | String? get camelCase => GetUtils.camelCase(this); |
79 | 118 | ||
119 | + /// Discover if the String is a valid URL | ||
80 | String? get paramCase => GetUtils.paramCase(this); | 120 | String? get paramCase => GetUtils.paramCase(this); |
81 | 121 | ||
82 | - String numericOnly({bool firstWordOnly = false}) => | ||
83 | - GetUtils.numericOnly(this, firstWordOnly: firstWordOnly); | ||
84 | - | 122 | + /// add segments to the String |
85 | String createPath([Iterable? segments]) { | 123 | String createPath([Iterable? segments]) { |
86 | final path = startsWith('/') ? this : '/$this'; | 124 | final path = startsWith('/') ? this : '/$this'; |
87 | return GetUtils.createPath(path, segments); | 125 | return GetUtils.createPath(path, segments); |
1 | +import 'package:flutter/material.dart'; | ||
2 | + | ||
3 | +class OtimizedListView<T> extends StatelessWidget { | ||
4 | + final List<T> list; | ||
5 | + final Axis scrollDirection; | ||
6 | + final bool reverse; | ||
7 | + final ScrollController? controller; | ||
8 | + final bool? primary; | ||
9 | + final ScrollPhysics? physics; | ||
10 | + final bool shrinkWrap; | ||
11 | + final Widget onEmpty; | ||
12 | + final int lenght; | ||
13 | + final Widget Function(BuildContext context, ValueKey key, T item) builder; | ||
14 | + const OtimizedListView({ | ||
15 | + Key? key, | ||
16 | + required this.list, | ||
17 | + required this.builder, | ||
18 | + this.scrollDirection = Axis.vertical, | ||
19 | + this.reverse = false, | ||
20 | + this.controller, | ||
21 | + this.primary, | ||
22 | + this.physics, | ||
23 | + this.onEmpty = const SizedBox.shrink(), | ||
24 | + this.shrinkWrap = false, | ||
25 | + }) : lenght = list.length, | ||
26 | + super(key: key); | ||
27 | + @override | ||
28 | + Widget build(BuildContext context) { | ||
29 | + if (list.isEmpty) return onEmpty; | ||
30 | + | ||
31 | + return CustomScrollView( | ||
32 | + controller: controller, | ||
33 | + reverse: reverse, | ||
34 | + scrollDirection: scrollDirection, | ||
35 | + primary: primary, | ||
36 | + physics: physics, | ||
37 | + shrinkWrap: shrinkWrap, | ||
38 | + slivers: <Widget>[ | ||
39 | + SliverList( | ||
40 | + delegate: SliverChildBuilderDelegate( | ||
41 | + (context, i) { | ||
42 | + final item = list[i]; | ||
43 | + final key = ValueKey(item); | ||
44 | + return builder(context, key, item); | ||
45 | + }, | ||
46 | + childCount: list.length, | ||
47 | + addAutomaticKeepAlives: true, | ||
48 | + findChildIndexCallback: (key) { | ||
49 | + return list.indexWhere((m) => m == (key as ValueKey<T>).value); | ||
50 | + }, | ||
51 | + ), | ||
52 | + ), | ||
53 | + ], | ||
54 | + ); | ||
55 | + } | ||
56 | +} |
1 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
2 | import 'package:flutter_test/flutter_test.dart'; | 2 | import 'package:flutter_test/flutter_test.dart'; |
3 | import 'package:get/get.dart'; | 3 | import 'package:get/get.dart'; |
4 | +import 'package:get/get_state_manager/src/simple/mixin_builder.dart'; | ||
4 | 5 | ||
5 | void main() { | 6 | void main() { |
6 | - testWidgets("MixinBuilder smoke test", (tester) async { | 7 | + testWidgets("MixinBuilder with reactive and not reactive", (tester) async { |
7 | await tester.pumpWidget( | 8 | await tester.pumpWidget( |
8 | MaterialApp( | 9 | MaterialApp( |
9 | home: MixinBuilder<Controller>( | 10 | home: MixinBuilder<Controller>( |
@@ -35,6 +36,10 @@ void main() { | @@ -35,6 +36,10 @@ void main() { | ||
35 | TextButton( | 36 | TextButton( |
36 | child: Text("increment"), | 37 | child: Text("increment"), |
37 | onPressed: () => controller.increment(), | 38 | onPressed: () => controller.increment(), |
39 | + ), | ||
40 | + TextButton( | ||
41 | + child: Text("increment2"), | ||
42 | + onPressed: () => controller.increment2(), | ||
38 | ) | 43 | ) |
39 | ], | 44 | ], |
40 | ); | 45 | ); |
@@ -62,6 +67,12 @@ void main() { | @@ -62,6 +67,12 @@ void main() { | ||
62 | await tester.pump(); | 67 | await tester.pump(); |
63 | 68 | ||
64 | expect(find.text("Count: 2"), findsOneWidget); | 69 | expect(find.text("Count: 2"), findsOneWidget); |
70 | + | ||
71 | + await tester.tap(find.text('increment2')); | ||
72 | + | ||
73 | + await tester.pump(); | ||
74 | + | ||
75 | + expect(find.text("Count2: 1"), findsOneWidget); | ||
65 | }); | 76 | }); |
66 | 77 | ||
67 | // testWidgets( | 78 | // testWidgets( |
-
Please register or login to post a comment