Committed by
GitHub
Merge branch 'master' into master
Showing
35 changed files
with
533 additions
and
285 deletions
No preview for this file type
1 | import 'package:get/get.dart'; | 1 | import 'package:get/get.dart'; |
2 | + | ||
2 | import '../domain/entity/cases_model.dart'; | 3 | import '../domain/entity/cases_model.dart'; |
3 | 4 | ||
4 | // ignore: one_member_abstracts | 5 | // ignore: one_member_abstracts |
@@ -12,6 +13,7 @@ class HomeProvider extends GetConnect implements IHomeProvider { | @@ -12,6 +13,7 @@ class HomeProvider extends GetConnect implements IHomeProvider { | ||
12 | httpClient.defaultDecoder = | 13 | httpClient.defaultDecoder = |
13 | (val) => CasesModel.fromJson(val as Map<String, dynamic>); | 14 | (val) => CasesModel.fromJson(val as Map<String, dynamic>); |
14 | httpClient.baseUrl = 'https://api.covid19api.com'; | 15 | httpClient.baseUrl = 'https://api.covid19api.com'; |
16 | + super.onInit(); | ||
15 | } | 17 | } |
16 | 18 | ||
17 | @override | 19 | @override |
@@ -19,10 +19,10 @@ class HomeController extends SuperController<CasesModel> { | @@ -19,10 +19,10 @@ class HomeController extends SuperController<CasesModel> { | ||
19 | Country getCountryById(String id) { | 19 | Country getCountryById(String id) { |
20 | final index = int.tryParse(id); | 20 | final index = int.tryParse(id); |
21 | if (index != null) { | 21 | if (index != null) { |
22 | - return state!.countries[index]; | 22 | + return state.countries[index]; |
23 | } | 23 | } |
24 | 24 | ||
25 | - return state!.countries.first; | 25 | + return state.countries.first; |
26 | } | 26 | } |
27 | 27 | ||
28 | @override | 28 | @override |
@@ -28,9 +28,9 @@ class CountryView extends GetView<HomeController> { | @@ -28,9 +28,9 @@ class CountryView extends GetView<HomeController> { | ||
28 | ), | 28 | ), |
29 | body: Center( | 29 | body: Center( |
30 | child: ListView.builder( | 30 | child: ListView.builder( |
31 | - itemCount: controller.state!.countries.length, | 31 | + itemCount: controller.state.countries.length, |
32 | itemBuilder: (context, index) { | 32 | itemBuilder: (context, index) { |
33 | - final country = controller.state!.countries[index]; | 33 | + final country = controller.state.countries[index]; |
34 | return ListTile( | 34 | return ListTile( |
35 | onTap: () { | 35 | onTap: () { |
36 | //Get.rootDelegate.toNamed('/home/country'); | 36 | //Get.rootDelegate.toNamed('/home/country'); |
1 | import 'dart:io'; | 1 | import 'dart:io'; |
2 | import 'dart:math'; | 2 | import 'dart:math'; |
3 | + | ||
3 | import 'package:flutter/material.dart'; | 4 | import 'package:flutter/material.dart'; |
4 | import 'package:flutter_test/flutter_test.dart'; | 5 | import 'package:flutter_test/flutter_test.dart'; |
5 | import 'package:get/get.dart'; | 6 | import 'package:get/get.dart'; |
@@ -81,8 +82,8 @@ void main() { | @@ -81,8 +82,8 @@ void main() { | ||
81 | } | 82 | } |
82 | 83 | ||
83 | if (controller.status.isSuccess) { | 84 | if (controller.status.isSuccess) { |
84 | - expect(controller.state!.global.totalDeaths, 100); | ||
85 | - expect(controller.state!.global.totalConfirmed, 200); | 85 | + expect(controller.state.global.totalDeaths, 100); |
86 | + expect(controller.state.global.totalConfirmed, 200); | ||
86 | } | 87 | } |
87 | }); | 88 | }); |
88 | 89 |
@@ -100,9 +100,7 @@ class GetConnect extends GetConnectInterface { | @@ -100,9 +100,7 @@ class GetConnect extends GetConnectInterface { | ||
100 | this.maxAuthRetries = 1, | 100 | this.maxAuthRetries = 1, |
101 | this.allowAutoSignedCert = false, | 101 | this.allowAutoSignedCert = false, |
102 | this.withCredentials = false, | 102 | this.withCredentials = false, |
103 | - }) { | ||
104 | - $configureLifeCycle(); | ||
105 | - } | 103 | + }); |
106 | 104 | ||
107 | bool allowAutoSignedCert; | 105 | bool allowAutoSignedCert; |
108 | String userAgent; | 106 | String userAgent; |
@@ -28,6 +28,7 @@ class GetHttpClient { | @@ -28,6 +28,7 @@ class GetHttpClient { | ||
28 | int maxAuthRetries; | 28 | int maxAuthRetries; |
29 | 29 | ||
30 | bool sendUserAgent; | 30 | bool sendUserAgent; |
31 | + bool sendContentLength; | ||
31 | 32 | ||
32 | Decoder? defaultDecoder; | 33 | Decoder? defaultDecoder; |
33 | 34 | ||
@@ -47,6 +48,7 @@ class GetHttpClient { | @@ -47,6 +48,7 @@ class GetHttpClient { | ||
47 | this.followRedirects = true, | 48 | this.followRedirects = true, |
48 | this.maxRedirects = 5, | 49 | this.maxRedirects = 5, |
49 | this.sendUserAgent = false, | 50 | this.sendUserAgent = false, |
51 | + this.sendContentLength = true, | ||
50 | this.maxAuthRetries = 1, | 52 | this.maxAuthRetries = 1, |
51 | bool allowAutoSignedCert = false, | 53 | bool allowAutoSignedCert = false, |
52 | this.baseUrl, | 54 | this.baseUrl, |
@@ -111,7 +113,7 @@ class GetHttpClient { | @@ -111,7 +113,7 @@ class GetHttpClient { | ||
111 | 113 | ||
112 | if (body is FormData) { | 114 | if (body is FormData) { |
113 | bodyBytes = await body.toBytes(); | 115 | bodyBytes = await body.toBytes(); |
114 | - headers['content-length'] = bodyBytes.length.toString(); | 116 | + _setContentLenght(headers, bodyBytes.length); |
115 | headers['content-type'] = | 117 | headers['content-type'] = |
116 | 'multipart/form-data; boundary=${body.boundary}'; | 118 | 'multipart/form-data; boundary=${body.boundary}'; |
117 | } else if (contentType != null && | 119 | } else if (contentType != null && |
@@ -124,21 +126,21 @@ class GetHttpClient { | @@ -124,21 +126,21 @@ class GetHttpClient { | ||
124 | }); | 126 | }); |
125 | var formData = parts.join('&'); | 127 | var formData = parts.join('&'); |
126 | bodyBytes = utf8.encode(formData); | 128 | bodyBytes = utf8.encode(formData); |
127 | - headers['content-length'] = bodyBytes.length.toString(); | 129 | + _setContentLenght(headers, bodyBytes.length); |
128 | headers['content-type'] = contentType; | 130 | headers['content-type'] = contentType; |
129 | } else if (body is Map || body is List) { | 131 | } else if (body is Map || body is List) { |
130 | var jsonString = json.encode(body); | 132 | var jsonString = json.encode(body); |
131 | - | ||
132 | bodyBytes = utf8.encode(jsonString); | 133 | bodyBytes = utf8.encode(jsonString); |
133 | - headers['content-length'] = bodyBytes.length.toString(); | 134 | + _setContentLenght(headers, bodyBytes.length); |
134 | headers['content-type'] = contentType ?? defaultContentType; | 135 | headers['content-type'] = contentType ?? defaultContentType; |
135 | } else if (body is String) { | 136 | } else if (body is String) { |
136 | bodyBytes = utf8.encode(body); | 137 | bodyBytes = utf8.encode(body); |
137 | - headers['content-length'] = bodyBytes.length.toString(); | 138 | + _setContentLenght(headers, bodyBytes.length); |
139 | + | ||
138 | headers['content-type'] = contentType ?? defaultContentType; | 140 | headers['content-type'] = contentType ?? defaultContentType; |
139 | } else if (body == null) { | 141 | } else if (body == null) { |
142 | + _setContentLenght(headers, 0); | ||
140 | headers['content-type'] = contentType ?? defaultContentType; | 143 | headers['content-type'] = contentType ?? defaultContentType; |
141 | - headers['content-length'] = '0'; | ||
142 | } else { | 144 | } else { |
143 | if (!errorSafety) { | 145 | if (!errorSafety) { |
144 | throw UnexpectedFormat('body cannot be ${body.runtimeType}'); | 146 | throw UnexpectedFormat('body cannot be ${body.runtimeType}'); |
@@ -162,6 +164,12 @@ class GetHttpClient { | @@ -162,6 +164,12 @@ class GetHttpClient { | ||
162 | ); | 164 | ); |
163 | } | 165 | } |
164 | 166 | ||
167 | + void _setContentLenght(Map<String, String> headers, int contentLength) { | ||
168 | + if (sendContentLength) { | ||
169 | + headers['content-length'] = '$contentLength'; | ||
170 | + } | ||
171 | + } | ||
172 | + | ||
165 | Stream<List<int>> _trackProgress( | 173 | Stream<List<int>> _trackProgress( |
166 | List<int> bodyBytes, | 174 | List<int> bodyBytes, |
167 | Progress? uploadProgress, | 175 | Progress? uploadProgress, |
@@ -110,11 +110,12 @@ class BaseWebSocket { | @@ -110,11 +110,12 @@ class BaseWebSocket { | ||
110 | return true; | 110 | return true; |
111 | }; | 111 | }; |
112 | 112 | ||
113 | - var request = await client.getUrl(Uri.parse(url)); | ||
114 | - request.headers.add('Connection', 'Upgrade'); | ||
115 | - request.headers.add('Upgrade', 'websocket'); | ||
116 | - request.headers.add('Sec-WebSocket-Version', '13'); | ||
117 | - request.headers.add('Sec-WebSocket-Key', key.toLowerCase()); | 113 | + var request = await client.getUrl(Uri.parse(url)) |
114 | + ..headers.add('Connection', 'Upgrade') | ||
115 | + ..headers.add('Upgrade', 'websocket') | ||
116 | + ..headers.add('Cache-Control', 'no-cache') | ||
117 | + ..headers.add('Sec-WebSocket-Version', '13') | ||
118 | + ..headers.add('Sec-WebSocket-Key', key.toLowerCase()); | ||
118 | 119 | ||
119 | var response = await request.close(); | 120 | var response = await request.close(); |
120 | // ignore: close_sinks | 121 | // ignore: close_sinks |
@@ -205,7 +205,8 @@ class GetInstance { | @@ -205,7 +205,8 @@ class GetInstance { | ||
205 | if (_singl[key]!.isSingleton!) { | 205 | if (_singl[key]!.isSingleton!) { |
206 | _singl[key]!.isInit = true; | 206 | _singl[key]!.isInit = true; |
207 | if (Get.smartManagement != SmartManagement.onlyBuilder) { | 207 | if (Get.smartManagement != SmartManagement.onlyBuilder) { |
208 | - RouterReportManager.reportDependencyLinkedToRoute(_getKey(S, name)); | 208 | + RouterReportManager.instance |
209 | + .reportDependencyLinkedToRoute(_getKey(S, name)); | ||
209 | } | 210 | } |
210 | } | 211 | } |
211 | } | 212 | } |
@@ -257,7 +258,7 @@ class GetInstance { | @@ -257,7 +258,7 @@ class GetInstance { | ||
257 | Get.log('Instance "$S" with tag "$tag" has been initialized'); | 258 | Get.log('Instance "$S" with tag "$tag" has been initialized'); |
258 | } | 259 | } |
259 | if (!_singl[key]!.isSingleton!) { | 260 | if (!_singl[key]!.isSingleton!) { |
260 | - RouterReportManager.appendRouteByCreate(i); | 261 | + RouterReportManager.instance.appendRouteByCreate(i); |
261 | } | 262 | } |
262 | } | 263 | } |
263 | return i; | 264 | return i; |
@@ -323,7 +324,7 @@ class GetInstance { | @@ -323,7 +324,7 @@ class GetInstance { | ||
323 | {@deprecated bool clearFactory = true, bool clearRouteBindings = true}) { | 324 | {@deprecated bool clearFactory = true, bool clearRouteBindings = true}) { |
324 | // if (clearFactory) _factory.clear(); | 325 | // if (clearFactory) _factory.clear(); |
325 | // deleteAll(force: true); | 326 | // deleteAll(force: true); |
326 | - if (clearRouteBindings) RouterReportManager.clearRouteKeys(); | 327 | + if (clearRouteBindings) RouterReportManager.instance.clearRouteKeys(); |
327 | _singl.clear(); | 328 | _singl.clear(); |
328 | 329 | ||
329 | return true; | 330 | return true; |
1 | -import '../../get_core/get_core.dart'; | ||
2 | - | ||
3 | -/// Special callable class to keep the contract of a regular method, and avoid | ||
4 | -/// overrides if you extend the class that uses it, as Dart has no final | ||
5 | -/// methods. | ||
6 | -/// Used in `DisposableInterface` to avoid the danger of overriding onStart. | ||
7 | -class InternalFinalCallback<T> { | ||
8 | - ValueUpdater<T>? _callback; | ||
9 | - | ||
10 | - InternalFinalCallback({ValueUpdater<T>? callback}) : _callback = callback; | ||
11 | - | ||
12 | - T call() => _callback!.call(); | ||
13 | -} | 1 | +import 'package:flutter/foundation.dart'; |
2 | +import 'package:flutter/scheduler.dart'; | ||
14 | 3 | ||
15 | /// The [GetLifeCycle] | 4 | /// The [GetLifeCycle] |
16 | /// | 5 | /// |
@@ -22,24 +11,10 @@ class InternalFinalCallback<T> { | @@ -22,24 +11,10 @@ class InternalFinalCallback<T> { | ||
22 | /// } | 11 | /// } |
23 | /// ``` | 12 | /// ``` |
24 | mixin GetLifeCycleBase { | 13 | mixin GetLifeCycleBase { |
25 | - /// Called at the exact moment the widget is allocated in memory. | ||
26 | - /// It uses an internal "callable" type, to avoid any @overrides in subclases. | ||
27 | - /// This method should be internal and is required to define the | ||
28 | - /// lifetime cycle of the subclass. | ||
29 | - final onStart = InternalFinalCallback<void>(); | ||
30 | - | ||
31 | - // /// The `configureLifeCycle` works as a constructor for the [GetLifeCycle] | ||
32 | - // /// | ||
33 | - // /// This method must be invoked in the constructor of the implementation | ||
34 | - // void configureLifeCycle() { | ||
35 | - // if (_initialized) return; | ||
36 | - // } | ||
37 | - | ||
38 | - /// Internal callback that starts the cycle of this controller. | ||
39 | - final onDelete = InternalFinalCallback<void>(); | ||
40 | - | ||
41 | /// Called immediately after the widget is allocated in memory. | 14 | /// Called immediately after the widget is allocated in memory. |
42 | /// You might use this to initialize something for the controller. | 15 | /// You might use this to initialize something for the controller. |
16 | + @protected | ||
17 | + @mustCallSuper | ||
43 | void onInit() {} | 18 | void onInit() {} |
44 | 19 | ||
45 | /// Called 1 frame after onInit(). It is the perfect place to enter | 20 | /// Called 1 frame after onInit(). It is the perfect place to enter |
@@ -60,8 +35,14 @@ mixin GetLifeCycleBase { | @@ -60,8 +35,14 @@ mixin GetLifeCycleBase { | ||
60 | /// Checks whether the controller has already been initialized. | 35 | /// Checks whether the controller has already been initialized. |
61 | bool get initialized => _initialized; | 36 | bool get initialized => _initialized; |
62 | 37 | ||
63 | - // Internal callback that starts the cycle of this controller. | ||
64 | - void _onStart() { | 38 | + /// Called at the exact moment the widget is allocated in memory. |
39 | + /// It uses an internal "callable" type, to avoid any @overrides in subclases. | ||
40 | + /// This method should be internal and is required to define the | ||
41 | + /// lifetime cycle of the subclass. | ||
42 | + // @protected | ||
43 | + @mustCallSuper | ||
44 | + void onStart() { | ||
45 | + // _checkIfAlreadyConfigured(); | ||
65 | if (_initialized) return; | 46 | if (_initialized) return; |
66 | onInit(); | 47 | onInit(); |
67 | _initialized = true; | 48 | _initialized = true; |
@@ -72,31 +53,28 @@ mixin GetLifeCycleBase { | @@ -72,31 +53,28 @@ mixin GetLifeCycleBase { | ||
72 | /// Checks whether the controller has already been closed. | 53 | /// Checks whether the controller has already been closed. |
73 | bool get isClosed => _isClosed; | 54 | bool get isClosed => _isClosed; |
74 | 55 | ||
75 | - // Internal callback that starts the cycle of this controller. | ||
76 | - void _onDelete() { | 56 | + // Called when the controller is removed from memory. |
57 | + @mustCallSuper | ||
58 | + void onDelete() { | ||
77 | if (_isClosed) return; | 59 | if (_isClosed) return; |
78 | _isClosed = true; | 60 | _isClosed = true; |
79 | onClose(); | 61 | onClose(); |
80 | } | 62 | } |
81 | 63 | ||
82 | - void $configureLifeCycle() { | ||
83 | - _checkIfAlreadyConfigured(); | ||
84 | - onStart._callback = _onStart; | ||
85 | - onDelete._callback = _onDelete; | ||
86 | - } | ||
87 | - | ||
88 | - void _checkIfAlreadyConfigured() { | ||
89 | - if (_initialized) { | ||
90 | - throw """You can only call configureLifeCycle once. | ||
91 | -The proper place to insert it is in your class's constructor | ||
92 | -that inherits GetLifeCycle."""; | ||
93 | - } | ||
94 | - } | 64 | +// void _checkIfAlreadyConfigured() { |
65 | +// if (_initialized) { | ||
66 | +// throw """You can only call configureLifeCycle once. | ||
67 | +// The proper place to insert it is in your class's constructor | ||
68 | +// that inherits GetLifeCycle."""; | ||
69 | +// } | ||
70 | +// } | ||
95 | } | 71 | } |
96 | 72 | ||
97 | abstract class GetLifeCycle with GetLifeCycleBase { | 73 | abstract class GetLifeCycle with GetLifeCycleBase { |
98 | - GetLifeCycle() { | ||
99 | - $configureLifeCycle(); | 74 | + @override |
75 | + void onInit() { | ||
76 | + SchedulerBinding.instance?.addPostFrameCallback((_) => onReady()); | ||
77 | + super.onInit(); | ||
100 | } | 78 | } |
101 | } | 79 | } |
102 | 80 |
1 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
2 | + | ||
2 | import '../../../get.dart'; | 3 | import '../../../get.dart'; |
3 | import '../router_report.dart'; | 4 | import '../router_report.dart'; |
4 | 5 | ||
@@ -21,7 +22,7 @@ class GetModalBottomSheetRoute<T> extends PopupRoute<T> { | @@ -21,7 +22,7 @@ class GetModalBottomSheetRoute<T> extends PopupRoute<T> { | ||
21 | this.enterBottomSheetDuration = const Duration(milliseconds: 250), | 22 | this.enterBottomSheetDuration = const Duration(milliseconds: 250), |
22 | this.exitBottomSheetDuration = const Duration(milliseconds: 200), | 23 | this.exitBottomSheetDuration = const Duration(milliseconds: 200), |
23 | }) : super(settings: settings) { | 24 | }) : super(settings: settings) { |
24 | - RouterReportManager.reportCurrentRoute(this); | 25 | + RouterReportManager.instance.reportCurrentRoute(this); |
25 | } | 26 | } |
26 | final bool? isPersistent; | 27 | final bool? isPersistent; |
27 | final WidgetBuilder? builder; | 28 | final WidgetBuilder? builder; |
@@ -56,7 +57,7 @@ class GetModalBottomSheetRoute<T> extends PopupRoute<T> { | @@ -56,7 +57,7 @@ class GetModalBottomSheetRoute<T> extends PopupRoute<T> { | ||
56 | 57 | ||
57 | @override | 58 | @override |
58 | void dispose() { | 59 | void dispose() { |
59 | - RouterReportManager.reportRouteDispose(this); | 60 | + RouterReportManager.instance.reportRouteDispose(this); |
60 | super.dispose(); | 61 | super.dispose(); |
61 | } | 62 | } |
62 | 63 |
1 | import 'package:flutter/widgets.dart'; | 1 | import 'package:flutter/widgets.dart'; |
2 | + | ||
2 | import '../router_report.dart'; | 3 | import '../router_report.dart'; |
3 | 4 | ||
4 | class GetDialogRoute<T> extends PopupRoute<T> { | 5 | class GetDialogRoute<T> extends PopupRoute<T> { |
@@ -17,7 +18,7 @@ class GetDialogRoute<T> extends PopupRoute<T> { | @@ -17,7 +18,7 @@ class GetDialogRoute<T> extends PopupRoute<T> { | ||
17 | _transitionDuration = transitionDuration, | 18 | _transitionDuration = transitionDuration, |
18 | _transitionBuilder = transitionBuilder, | 19 | _transitionBuilder = transitionBuilder, |
19 | super(settings: settings) { | 20 | super(settings: settings) { |
20 | - RouterReportManager.reportCurrentRoute(this); | 21 | + RouterReportManager.instance.reportCurrentRoute(this); |
21 | } | 22 | } |
22 | 23 | ||
23 | final RoutePageBuilder widget; | 24 | final RoutePageBuilder widget; |
@@ -28,7 +29,7 @@ class GetDialogRoute<T> extends PopupRoute<T> { | @@ -28,7 +29,7 @@ class GetDialogRoute<T> extends PopupRoute<T> { | ||
28 | 29 | ||
29 | @override | 30 | @override |
30 | void dispose() { | 31 | void dispose() { |
31 | - RouterReportManager.reportRouteDispose(this); | 32 | + RouterReportManager.instance.reportRouteDispose(this); |
32 | super.dispose(); | 33 | super.dispose(); |
33 | } | 34 | } |
34 | 35 |
@@ -511,6 +511,7 @@ extension GetNavigation on GetInterface { | @@ -511,6 +511,7 @@ extension GetNavigation on GetInterface { | ||
511 | Bindings? binding, | 511 | Bindings? binding, |
512 | bool preventDuplicates = true, | 512 | bool preventDuplicates = true, |
513 | bool? popGesture, | 513 | bool? popGesture, |
514 | + bool showCupertinoParallax = true, | ||
514 | double Function(BuildContext context)? gestureWidth, | 515 | double Function(BuildContext context)? gestureWidth, |
515 | }) { | 516 | }) { |
516 | // var routeName = "/${page.runtimeType}"; | 517 | // var routeName = "/${page.runtimeType}"; |
@@ -525,6 +526,7 @@ extension GetNavigation on GetInterface { | @@ -525,6 +526,7 @@ extension GetNavigation on GetInterface { | ||
525 | page: _resolvePage(page, 'to'), | 526 | page: _resolvePage(page, 'to'), |
526 | routeName: routeName, | 527 | routeName: routeName, |
527 | gestureWidth: gestureWidth, | 528 | gestureWidth: gestureWidth, |
529 | + showCupertinoParallax: showCupertinoParallax, | ||
528 | settings: RouteSettings( | 530 | settings: RouteSettings( |
529 | name: routeName, | 531 | name: routeName, |
530 | arguments: arguments, | 532 | arguments: arguments, |
@@ -7,28 +7,30 @@ import '../../get.dart'; | @@ -7,28 +7,30 @@ import '../../get.dart'; | ||
7 | class RouterReportManager<T> { | 7 | class RouterReportManager<T> { |
8 | /// Holds a reference to `Get.reference` when the Instance was | 8 | /// Holds a reference to `Get.reference` when the Instance was |
9 | /// created to manage the memory. | 9 | /// created to manage the memory. |
10 | - static final Map<Route?, List<String>> _routesKey = {}; | 10 | + final Map<T?, List<String>> _routesKey = {}; |
11 | 11 | ||
12 | /// Stores the onClose() references of instances created with `Get.create()` | 12 | /// Stores the onClose() references of instances created with `Get.create()` |
13 | /// using the `Get.reference`. | 13 | /// using the `Get.reference`. |
14 | /// Experimental feature to keep the lifecycle and memory management with | 14 | /// Experimental feature to keep the lifecycle and memory management with |
15 | /// non-singleton instances. | 15 | /// non-singleton instances. |
16 | - static final Map<Route?, HashSet<Function>> _routesByCreate = {}; | 16 | + final Map<T?, HashSet<Function>> _routesByCreate = {}; |
17 | + | ||
18 | + static late final RouterReportManager instance = RouterReportManager(); | ||
17 | 19 | ||
18 | void printInstanceStack() { | 20 | void printInstanceStack() { |
19 | Get.log(_routesKey.toString()); | 21 | Get.log(_routesKey.toString()); |
20 | } | 22 | } |
21 | 23 | ||
22 | - static Route? _current; | 24 | + T? _current; |
23 | 25 | ||
24 | // ignore: use_setters_to_change_properties | 26 | // ignore: use_setters_to_change_properties |
25 | - static void reportCurrentRoute(Route newRoute) { | 27 | + void reportCurrentRoute(T newRoute) { |
26 | _current = newRoute; | 28 | _current = newRoute; |
27 | } | 29 | } |
28 | 30 | ||
29 | /// Links a Class instance [S] (or [tag]) to the current route. | 31 | /// Links a Class instance [S] (or [tag]) to the current route. |
30 | /// Requires usage of `GetMaterialApp`. | 32 | /// Requires usage of `GetMaterialApp`. |
31 | - static void reportDependencyLinkedToRoute(String depedencyKey) { | 33 | + void reportDependencyLinkedToRoute(String depedencyKey) { |
32 | if (_current == null) return; | 34 | if (_current == null) return; |
33 | if (_routesKey.containsKey(_current)) { | 35 | if (_routesKey.containsKey(_current)) { |
34 | _routesKey[_current!]!.add(depedencyKey); | 36 | _routesKey[_current!]!.add(depedencyKey); |
@@ -37,18 +39,18 @@ class RouterReportManager<T> { | @@ -37,18 +39,18 @@ class RouterReportManager<T> { | ||
37 | } | 39 | } |
38 | } | 40 | } |
39 | 41 | ||
40 | - static void clearRouteKeys() { | 42 | + void clearRouteKeys() { |
41 | _routesKey.clear(); | 43 | _routesKey.clear(); |
42 | _routesByCreate.clear(); | 44 | _routesByCreate.clear(); |
43 | } | 45 | } |
44 | 46 | ||
45 | - static void appendRouteByCreate(GetLifeCycleBase i) { | 47 | + void appendRouteByCreate(GetLifeCycleBase i) { |
46 | _routesByCreate[_current] ??= HashSet<Function>(); | 48 | _routesByCreate[_current] ??= HashSet<Function>(); |
47 | // _routesByCreate[Get.reference]!.add(i.onDelete as Function); | 49 | // _routesByCreate[Get.reference]!.add(i.onDelete as Function); |
48 | _routesByCreate[_current]!.add(i.onDelete); | 50 | _routesByCreate[_current]!.add(i.onDelete); |
49 | } | 51 | } |
50 | 52 | ||
51 | - static void reportRouteDispose(Route disposed) { | 53 | + void reportRouteDispose(T disposed) { |
52 | if (Get.smartManagement != SmartManagement.onlyBuilder) { | 54 | if (Get.smartManagement != SmartManagement.onlyBuilder) { |
53 | WidgetsBinding.instance!.addPostFrameCallback((_) { | 55 | WidgetsBinding.instance!.addPostFrameCallback((_) { |
54 | _removeDependencyByRoute(disposed); | 56 | _removeDependencyByRoute(disposed); |
@@ -56,7 +58,7 @@ class RouterReportManager<T> { | @@ -56,7 +58,7 @@ class RouterReportManager<T> { | ||
56 | } | 58 | } |
57 | } | 59 | } |
58 | 60 | ||
59 | - static void reportRouteWillDispose(Route disposed) { | 61 | + void reportRouteWillDispose(T disposed) { |
60 | final keysToRemove = <String>[]; | 62 | final keysToRemove = <String>[]; |
61 | 63 | ||
62 | _routesKey[disposed]?.forEach(keysToRemove.add); | 64 | _routesKey[disposed]?.forEach(keysToRemove.add); |
@@ -85,7 +87,7 @@ class RouterReportManager<T> { | @@ -85,7 +87,7 @@ class RouterReportManager<T> { | ||
85 | /// using `Get.smartManagement` as [SmartManagement.full] or | 87 | /// using `Get.smartManagement` as [SmartManagement.full] or |
86 | /// [SmartManagement.keepFactory] | 88 | /// [SmartManagement.keepFactory] |
87 | /// Meant for internal usage of `GetPageRoute` and `GetDialogRoute` | 89 | /// Meant for internal usage of `GetPageRoute` and `GetDialogRoute` |
88 | - static void _removeDependencyByRoute(Route routeName) { | 90 | + void _removeDependencyByRoute(T routeName) { |
89 | final keysToRemove = <String>[]; | 91 | final keysToRemove = <String>[]; |
90 | 92 | ||
91 | _routesKey[routeName]?.forEach(keysToRemove.add); | 93 | _routesKey[routeName]?.forEach(keysToRemove.add); |
@@ -8,18 +8,20 @@ mixin PageRouteReportMixin<T> on Route<T> { | @@ -8,18 +8,20 @@ mixin PageRouteReportMixin<T> on Route<T> { | ||
8 | @override | 8 | @override |
9 | void install() { | 9 | void install() { |
10 | super.install(); | 10 | super.install(); |
11 | - RouterReportManager.reportCurrentRoute(this); | 11 | + RouterReportManager.instance.reportCurrentRoute(this); |
12 | } | 12 | } |
13 | 13 | ||
14 | @override | 14 | @override |
15 | void dispose() { | 15 | void dispose() { |
16 | super.dispose(); | 16 | super.dispose(); |
17 | - RouterReportManager.reportRouteDispose(this); | 17 | + RouterReportManager.instance.reportRouteDispose(this); |
18 | } | 18 | } |
19 | } | 19 | } |
20 | 20 | ||
21 | -class GetPageRoute<T> extends PageRoute<T> | ||
22 | - with GetPageRouteTransitionMixin<T>, PageRouteReportMixin { | 21 | +class GetPageRoute<T> extends PageRoute<T> //MaterialPageRoute<T> |
22 | + with | ||
23 | + GetPageRouteTransitionMixin<T>, | ||
24 | + PageRouteReportMixin { | ||
23 | /// Creates a page route for use in an iOS designed app. | 25 | /// Creates a page route for use in an iOS designed app. |
24 | /// | 26 | /// |
25 | /// The [builder], [maintainState], and [fullscreenDialog] arguments must not | 27 | /// The [builder], [maintainState], and [fullscreenDialog] arguments must not |
@@ -47,7 +49,11 @@ class GetPageRoute<T> extends PageRoute<T> | @@ -47,7 +49,11 @@ class GetPageRoute<T> extends PageRoute<T> | ||
47 | this.maintainState = true, | 49 | this.maintainState = true, |
48 | bool fullscreenDialog = false, | 50 | bool fullscreenDialog = false, |
49 | this.middlewares, | 51 | this.middlewares, |
50 | - }) : super(settings: settings, fullscreenDialog: fullscreenDialog); | 52 | + }) : super( |
53 | + settings: settings, | ||
54 | + fullscreenDialog: fullscreenDialog, | ||
55 | + // builder: (context) => Container(), | ||
56 | + ); | ||
51 | 57 | ||
52 | @override | 58 | @override |
53 | final Duration transitionDuration; | 59 | final Duration transitionDuration; |
@@ -322,7 +322,6 @@ Cannot read the previousTitle for a route that has not yet been installed''', | @@ -322,7 +322,6 @@ Cannot read the previousTitle for a route that has not yet been installed''', | ||
322 | bool canTransitionTo(TransitionRoute<dynamic> nextRoute) { | 322 | bool canTransitionTo(TransitionRoute<dynamic> nextRoute) { |
323 | // Don't perform outgoing animation if the next route is a | 323 | // Don't perform outgoing animation if the next route is a |
324 | // fullscreen dialog. | 324 | // fullscreen dialog. |
325 | - | ||
326 | return (nextRoute is GetPageRouteTransitionMixin && | 325 | return (nextRoute is GetPageRouteTransitionMixin && |
327 | !nextRoute.fullscreenDialog && | 326 | !nextRoute.fullscreenDialog && |
328 | nextRoute.showCupertinoParallax) || | 327 | nextRoute.showCupertinoParallax) || |
lib/get_navigation/src/routes/modules.dart
0 → 100644
1 | +// import 'package:flutter/material.dart'; | ||
2 | +// import 'package:get/get_navigation/src/router_report.dart'; | ||
3 | +// import 'package:get/instance_manager.dart'; | ||
4 | + | ||
5 | +// class Dependencies { | ||
6 | +// void lazyPut<S>(InstanceBuilderCallback<S> builder, | ||
7 | +// {String? tag, bool fenix = false}) { | ||
8 | +// GetInstance().lazyPut<S>(builder, tag: tag, fenix: fenix); | ||
9 | +// } | ||
10 | + | ||
11 | +// S call<S>() { | ||
12 | +// return find<S>(); | ||
13 | +// } | ||
14 | + | ||
15 | +// Future<S> putAsync<S>(AsyncInstanceBuilderCallback<S> builder, | ||
16 | +// {String? tag, bool permanent = false}) async => | ||
17 | +// GetInstance().putAsync<S>(builder, tag: tag, permanent: permanent); | ||
18 | + | ||
19 | +// void create<S>(InstanceBuilderCallback<S> builder, | ||
20 | +// {String? tag, bool permanent = true}) => | ||
21 | +// GetInstance().create<S>(builder, tag: tag, permanent: permanent); | ||
22 | + | ||
23 | +// S find<S>({String? tag}) => GetInstance().find<S>(tag: tag); | ||
24 | + | ||
25 | +// S put<S>(S dependency, | ||
26 | +// {String? tag, | ||
27 | +// bool permanent = false, | ||
28 | +// InstanceBuilderCallback<S>? builder}) => | ||
29 | +// GetInstance().put<S>(dependency, tag: tag, permanent: permanent); | ||
30 | + | ||
31 | +// Future<bool> delete<S>({String? tag, bool force = false}) async => | ||
32 | +// GetInstance().delete<S>(tag: tag, force: force); | ||
33 | + | ||
34 | +// Future<void> deleteAll({bool force = false}) async => | ||
35 | +// GetInstance().deleteAll(force: force); | ||
36 | + | ||
37 | +// void reloadAll({bool force = false}) => GetInstance().reloadAll(force: force); | ||
38 | + | ||
39 | +// void reload<S>({String? tag, String? key, bool force = false}) => | ||
40 | +// GetInstance().reload<S>(tag: tag, key: key, force: force); | ||
41 | + | ||
42 | +// bool isRegistered<S>({String? tag}) => | ||
43 | +// GetInstance().isRegistered<S>(tag: tag); | ||
44 | + | ||
45 | +// bool isPrepared<S>({String? tag}) => GetInstance().isPrepared<S>(tag: tag); | ||
46 | + | ||
47 | +// void replace<P>(P child, {String? tag}) { | ||
48 | +// final info = GetInstance().getInstanceInfo<P>(tag: tag); | ||
49 | +// final permanent = (info.isPermanent ?? false); | ||
50 | +// delete<P>(tag: tag, force: permanent); | ||
51 | +// put(child, tag: tag, permanent: permanent); | ||
52 | +// } | ||
53 | + | ||
54 | +// void lazyReplace<P>(InstanceBuilderCallback<P> builder, | ||
55 | +// {String? tag, bool? fenix}) { | ||
56 | +// final info = GetInstance().getInstanceInfo<P>(tag: tag); | ||
57 | +// final permanent = (info.isPermanent ?? false); | ||
58 | +// delete<P>(tag: tag, force: permanent); | ||
59 | +// lazyPut(builder, tag: tag, fenix: fenix ?? permanent); | ||
60 | +// } | ||
61 | +// } | ||
62 | + | ||
63 | +// abstract class Module extends StatefulWidget { | ||
64 | +// Module({Key? key}) : super(key: key); | ||
65 | + | ||
66 | +// Widget view(BuildContext context); | ||
67 | + | ||
68 | +// void dependencies(Dependencies i); | ||
69 | + | ||
70 | +// @override | ||
71 | +// _ModuleState createState() => _ModuleState(); | ||
72 | +// } | ||
73 | + | ||
74 | +// class _ModuleState extends State<Module> { | ||
75 | +// @override | ||
76 | +// void initState() { | ||
77 | +// RouterReportManager.instance.reportCurrentRoute(this); | ||
78 | +// widget.dependencies(Dependencies()); | ||
79 | +// super.initState(); | ||
80 | +// } | ||
81 | + | ||
82 | +// @override | ||
83 | +// void dispose() { | ||
84 | +// RouterReportManager.instance.reportRouteDispose(this); | ||
85 | +// super.dispose(); | ||
86 | +// } | ||
87 | + | ||
88 | +// @override | ||
89 | +// Widget build(BuildContext context) { | ||
90 | +// return widget.view(context); | ||
91 | +// } | ||
92 | +// } |
@@ -52,7 +52,7 @@ class GetObserver extends NavigatorObserver { | @@ -52,7 +52,7 @@ class GetObserver extends NavigatorObserver { | ||
52 | Get.log("CLOSE TO ROUTE ${currentRoute.name}"); | 52 | Get.log("CLOSE TO ROUTE ${currentRoute.name}"); |
53 | } | 53 | } |
54 | if (previousRoute != null) { | 54 | if (previousRoute != null) { |
55 | - RouterReportManager.reportCurrentRoute(previousRoute); | 55 | + RouterReportManager.instance.reportCurrentRoute(previousRoute); |
56 | } | 56 | } |
57 | 57 | ||
58 | // Here we use a 'inverse didPush set', meaning that we use | 58 | // Here we use a 'inverse didPush set', meaning that we use |
@@ -97,7 +97,7 @@ class GetObserver extends NavigatorObserver { | @@ -97,7 +97,7 @@ class GetObserver extends NavigatorObserver { | ||
97 | Get.log("GOING TO ROUTE ${newRoute.name}"); | 97 | Get.log("GOING TO ROUTE ${newRoute.name}"); |
98 | } | 98 | } |
99 | 99 | ||
100 | - RouterReportManager.reportCurrentRoute(route); | 100 | + RouterReportManager.instance.reportCurrentRoute(route); |
101 | _routeSend?.update((value) { | 101 | _routeSend?.update((value) { |
102 | // Only PageRoute is allowed to change current value | 102 | // Only PageRoute is allowed to change current value |
103 | if (route is PageRoute) { | 103 | if (route is PageRoute) { |
@@ -142,7 +142,7 @@ class GetObserver extends NavigatorObserver { | @@ -142,7 +142,7 @@ class GetObserver extends NavigatorObserver { | ||
142 | }); | 142 | }); |
143 | 143 | ||
144 | if (route is GetPageRoute) { | 144 | if (route is GetPageRoute) { |
145 | - RouterReportManager.reportRouteWillDispose(route); | 145 | + RouterReportManager.instance.reportRouteWillDispose(route); |
146 | } | 146 | } |
147 | routing?.call(_routeSend); | 147 | routing?.call(_routeSend); |
148 | } | 148 | } |
@@ -158,7 +158,7 @@ class GetObserver extends NavigatorObserver { | @@ -158,7 +158,7 @@ class GetObserver extends NavigatorObserver { | ||
158 | Get.log("NEW ROUTE $newName"); | 158 | Get.log("NEW ROUTE $newName"); |
159 | 159 | ||
160 | if (newRoute != null) { | 160 | if (newRoute != null) { |
161 | - RouterReportManager.reportCurrentRoute(newRoute); | 161 | + RouterReportManager.instance.reportCurrentRoute(newRoute); |
162 | } | 162 | } |
163 | 163 | ||
164 | _routeSend?.update((value) { | 164 | _routeSend?.update((value) { |
@@ -178,7 +178,7 @@ class GetObserver extends NavigatorObserver { | @@ -178,7 +178,7 @@ class GetObserver extends NavigatorObserver { | ||
178 | value.isDialog = currentRoute.isDialog ? false : value.isDialog; | 178 | value.isDialog = currentRoute.isDialog ? false : value.isDialog; |
179 | }); | 179 | }); |
180 | if (oldRoute is GetPageRoute) { | 180 | if (oldRoute is GetPageRoute) { |
181 | - RouterReportManager.reportRouteWillDispose(oldRoute); | 181 | + RouterReportManager.instance.reportRouteWillDispose(oldRoute); |
182 | } | 182 | } |
183 | 183 | ||
184 | routing?.call(_routeSend); | 184 | routing?.call(_routeSend); |
@@ -87,11 +87,19 @@ class SnackbarController { | @@ -87,11 +87,19 @@ class SnackbarController { | ||
87 | } | 87 | } |
88 | } | 88 | } |
89 | 89 | ||
90 | + bool _isTesting = false; | ||
91 | + | ||
90 | void _configureOverlay() { | 92 | void _configureOverlay() { |
91 | - _overlayState = Overlay.of(Get.overlayContext!); | 93 | + final overlayContext = Get.overlayContext; |
94 | + _isTesting = overlayContext == null; | ||
95 | + _overlayState = | ||
96 | + _isTesting ? OverlayState() : Overlay.of(Get.overlayContext!); | ||
92 | _overlayEntries.clear(); | 97 | _overlayEntries.clear(); |
93 | _overlayEntries.addAll(_createOverlayEntries(_getBodyWidget())); | 98 | _overlayEntries.addAll(_createOverlayEntries(_getBodyWidget())); |
94 | - _overlayState!.insertAll(_overlayEntries); | 99 | + if (!_isTesting) { |
100 | + _overlayState!.insertAll(_overlayEntries); | ||
101 | + } | ||
102 | + | ||
95 | _configureSnackBarDisplay(); | 103 | _configureSnackBarDisplay(); |
96 | } | 104 | } |
97 | 105 | ||
@@ -316,8 +324,10 @@ class SnackbarController { | @@ -316,8 +324,10 @@ class SnackbarController { | ||
316 | } | 324 | } |
317 | 325 | ||
318 | void _removeOverlay() { | 326 | void _removeOverlay() { |
319 | - for (var element in _overlayEntries) { | ||
320 | - element.remove(); | 327 | + if (!_isTesting) { |
328 | + for (var element in _overlayEntries) { | ||
329 | + element.remove(); | ||
330 | + } | ||
321 | } | 331 | } |
322 | 332 | ||
323 | assert(!_transitionCompleter.isCompleted, | 333 | assert(!_transitionCompleter.isCompleted, |
@@ -14,6 +14,22 @@ class GetStream<T> { | @@ -14,6 +14,22 @@ class GetStream<T> { | ||
14 | FutureOr<void> Function()? onCancel; | 14 | FutureOr<void> Function()? onCancel; |
15 | 15 | ||
16 | GetStream({this.onListen, this.onPause, this.onResume, this.onCancel}); | 16 | GetStream({this.onListen, this.onPause, this.onResume, this.onCancel}); |
17 | + | ||
18 | + factory GetStream.fromValue(T value, | ||
19 | + {Function()? onListen, | ||
20 | + Function()? onPause, | ||
21 | + Function()? onResume, | ||
22 | + FutureOr<void> Function()? onCancel}) { | ||
23 | + final valuedStream = GetStream<T>( | ||
24 | + onListen: onListen, | ||
25 | + onPause: onPause, | ||
26 | + onResume: onResume, | ||
27 | + onCancel: onCancel) | ||
28 | + .._value = value; | ||
29 | + | ||
30 | + return valuedStream; | ||
31 | + } | ||
32 | + | ||
17 | List<LightSubscription<T>>? _onData = <LightSubscription<T>>[]; | 33 | List<LightSubscription<T>>? _onData = <LightSubscription<T>>[]; |
18 | 34 | ||
19 | bool? _isBusy = false; | 35 | bool? _isBusy = false; |
@@ -87,9 +103,12 @@ class GetStream<T> { | @@ -87,9 +103,12 @@ class GetStream<T> { | ||
87 | _isBusy = false; | 103 | _isBusy = false; |
88 | } | 104 | } |
89 | 105 | ||
90 | - T? _value; | 106 | + late T _value; |
91 | 107 | ||
92 | - T? get value => _value; | 108 | + T get value { |
109 | + RxInterface.proxy?.addListener(this); | ||
110 | + return _value; | ||
111 | + } | ||
93 | 112 | ||
94 | void add(T event) { | 113 | void add(T event) { |
95 | assert(!isClosed, 'You cannot add event to closed Stream'); | 114 | assert(!isClosed, 'You cannot add event to closed Stream'); |
@@ -109,7 +128,7 @@ class GetStream<T> { | @@ -109,7 +128,7 @@ class GetStream<T> { | ||
109 | _notifyDone(); | 128 | _notifyDone(); |
110 | _onData = null; | 129 | _onData = null; |
111 | _isBusy = null; | 130 | _isBusy = null; |
112 | - _value = null; | 131 | + // _value = null; |
113 | } | 132 | } |
114 | 133 | ||
115 | LightSubscription<T> listen(void Function(T event) onData, | 134 | LightSubscription<T> listen(void Function(T event) onData, |
@@ -2,7 +2,10 @@ library rx_stream; | @@ -2,7 +2,10 @@ library rx_stream; | ||
2 | 2 | ||
3 | import 'dart:async'; | 3 | import 'dart:async'; |
4 | 4 | ||
5 | +import 'package:get/get_state_manager/src/simple/list_notifier.dart'; | ||
6 | + | ||
5 | import '../rx_typedefs/rx_typedefs.dart'; | 7 | import '../rx_typedefs/rx_typedefs.dart'; |
8 | +import '../rx_types/rx_types.dart'; | ||
6 | 9 | ||
7 | part 'get_stream.dart'; | 10 | part 'get_stream.dart'; |
8 | part 'mini_stream.dart'; | 11 | part 'mini_stream.dart'; |
@@ -5,7 +5,7 @@ part of rx_types; | @@ -5,7 +5,7 @@ part of rx_types; | ||
5 | /// of those `Widgets` and Rx values. | 5 | /// of those `Widgets` and Rx values. |
6 | 6 | ||
7 | mixin RxObjectMixin<T> on NotifyManager<T> { | 7 | mixin RxObjectMixin<T> on NotifyManager<T> { |
8 | - late T _value; | 8 | + //late T _value; |
9 | 9 | ||
10 | /// Makes a direct update of [value] adding it to the Stream | 10 | /// Makes a direct update of [value] adding it to the Stream |
11 | /// useful when you make use of Rx for custom Types to referesh your UI. | 11 | /// useful when you make use of Rx for custom Types to referesh your UI. |
@@ -91,24 +91,25 @@ mixin RxObjectMixin<T> on NotifyManager<T> { | @@ -91,24 +91,25 @@ mixin RxObjectMixin<T> on NotifyManager<T> { | ||
91 | 91 | ||
92 | @override | 92 | @override |
93 | // ignore: avoid_equals_and_hash_code_on_mutable_classes | 93 | // ignore: avoid_equals_and_hash_code_on_mutable_classes |
94 | - int get hashCode => _value.hashCode; | 94 | + int get hashCode => value.hashCode; |
95 | 95 | ||
96 | /// Updates the [value] and adds it to the stream, updating the observer | 96 | /// Updates the [value] and adds it to the stream, updating the observer |
97 | /// Widget, only if it's different from the previous value. | 97 | /// Widget, only if it's different from the previous value. |
98 | set value(T val) { | 98 | set value(T val) { |
99 | if (subject.isClosed) return; | 99 | if (subject.isClosed) return; |
100 | sentToStream = false; | 100 | sentToStream = false; |
101 | - if (_value == val && !firstRebuild) return; | 101 | + if (value == val && !firstRebuild) return; |
102 | firstRebuild = false; | 102 | firstRebuild = false; |
103 | - _value = val; | 103 | + // _value = val; |
104 | sentToStream = true; | 104 | sentToStream = true; |
105 | - subject.add(_value); | 105 | + subject.add(val); |
106 | } | 106 | } |
107 | 107 | ||
108 | /// Returns the current [value] | 108 | /// Returns the current [value] |
109 | T get value { | 109 | T get value { |
110 | - RxInterface.proxy?.addListener(subject); | ||
111 | - return _value; | 110 | + return subject.value; |
111 | + //RxInterface.proxy?.addListener(subject); | ||
112 | + // return _value; | ||
112 | } | 113 | } |
113 | 114 | ||
114 | Stream<T> get stream => subject.stream; | 115 | Stream<T> get stream => subject.stream; |
@@ -192,7 +193,7 @@ mixin NotifyManager<T> { | @@ -192,7 +193,7 @@ mixin NotifyManager<T> { | ||
192 | /// Base Rx class that manages all the stream logic for any Type. | 193 | /// Base Rx class that manages all the stream logic for any Type. |
193 | abstract class _RxImpl<T> extends RxNotifier<T> with RxObjectMixin<T> { | 194 | abstract class _RxImpl<T> extends RxNotifier<T> with RxObjectMixin<T> { |
194 | _RxImpl(T initial) { | 195 | _RxImpl(T initial) { |
195 | - _value = initial; | 196 | + subject = GetStream.fromValue(initial); |
196 | } | 197 | } |
197 | 198 | ||
198 | void addError(Object error, [StackTrace? stackTrace]) { | 199 | void addError(Object error, [StackTrace? stackTrace]) { |
@@ -222,8 +223,8 @@ abstract class _RxImpl<T> extends RxNotifier<T> with RxObjectMixin<T> { | @@ -222,8 +223,8 @@ abstract class _RxImpl<T> extends RxNotifier<T> with RxObjectMixin<T> { | ||
222 | /// print( person ); | 223 | /// print( person ); |
223 | /// ``` | 224 | /// ``` |
224 | void update(void fn(T? val)) { | 225 | void update(void fn(T? val)) { |
225 | - fn(_value); | ||
226 | - subject.add(_value); | 226 | + fn(value); |
227 | + subject.add(value); | ||
227 | } | 228 | } |
228 | 229 | ||
229 | /// Following certain practices on Rx data, we might want to react to certain | 230 | /// Following certain practices on Rx data, we might want to react to certain |
@@ -295,7 +296,7 @@ extension RxBoolExt on Rx<bool> { | @@ -295,7 +296,7 @@ extension RxBoolExt on Rx<bool> { | ||
295 | /// not really a dart thing since we have '..' operator | 296 | /// not really a dart thing since we have '..' operator |
296 | // ignore: avoid_returning_this | 297 | // ignore: avoid_returning_this |
297 | Rx<bool> toggle() { | 298 | Rx<bool> toggle() { |
298 | - subject.add(_value = !_value); | 299 | + subject.add(!value); |
299 | return this; | 300 | return this; |
300 | } | 301 | } |
301 | } | 302 | } |
@@ -327,8 +328,8 @@ extension RxnBoolExt on Rx<bool?> { | @@ -327,8 +328,8 @@ extension RxnBoolExt on Rx<bool?> { | ||
327 | /// not really a dart thing since we have '..' operator | 328 | /// not really a dart thing since we have '..' operator |
328 | // ignore: avoid_returning_this | 329 | // ignore: avoid_returning_this |
329 | Rx<bool?>? toggle() { | 330 | Rx<bool?>? toggle() { |
330 | - if (_value != null) { | ||
331 | - subject.add(_value = !_value!); | 331 | + if (value != null) { |
332 | + subject.add(!value!); | ||
332 | return this; | 333 | return this; |
333 | } | 334 | } |
334 | } | 335 | } |
1 | part of rx_types; | 1 | part of rx_types; |
2 | 2 | ||
3 | extension RxStringExt on Rx<String> { | 3 | extension RxStringExt on Rx<String> { |
4 | - String operator +(String val) => _value + val; | 4 | + String operator +(String val) => value + val; |
5 | 5 | ||
6 | int compareTo(String other) { | 6 | int compareTo(String other) { |
7 | return value.compareTo(other); | 7 | return value.compareTo(other); |
@@ -125,7 +125,7 @@ extension RxStringExt on Rx<String> { | @@ -125,7 +125,7 @@ extension RxStringExt on Rx<String> { | ||
125 | } | 125 | } |
126 | 126 | ||
127 | extension RxnStringExt on Rx<String?> { | 127 | extension RxnStringExt on Rx<String?> { |
128 | - String operator +(String val) => (_value ?? '') + val; | 128 | + String operator +(String val) => (value ?? '') + val; |
129 | 129 | ||
130 | int? compareTo(String other) { | 130 | int? compareTo(String other) { |
131 | return value?.compareTo(other); | 131 | return value?.compareTo(other); |
@@ -5,7 +5,7 @@ class RxList<E> extends ListMixin<E> | @@ -5,7 +5,7 @@ class RxList<E> extends ListMixin<E> | ||
5 | with NotifyManager<List<E>>, RxObjectMixin<List<E>> | 5 | with NotifyManager<List<E>>, RxObjectMixin<List<E>> |
6 | implements RxInterface<List<E>> { | 6 | implements RxInterface<List<E>> { |
7 | RxList([List<E> initial = const []]) { | 7 | RxList([List<E> initial = const []]) { |
8 | - _value = List.from(initial); | 8 | + subject = GetStream.fromValue(List.from(initial)); |
9 | } | 9 | } |
10 | 10 | ||
11 | factory RxList.filled(int length, E fill, {bool growable = false}) { | 11 | factory RxList.filled(int length, E fill, {bool growable = false}) { |
@@ -42,7 +42,7 @@ class RxList<E> extends ListMixin<E> | @@ -42,7 +42,7 @@ class RxList<E> extends ListMixin<E> | ||
42 | 42 | ||
43 | @override | 43 | @override |
44 | void operator []=(int index, E val) { | 44 | void operator []=(int index, E val) { |
45 | - _value[index] = val; | 45 | + value[index] = val; |
46 | refresh(); | 46 | refresh(); |
47 | } | 47 | } |
48 | 48 | ||
@@ -62,25 +62,25 @@ class RxList<E> extends ListMixin<E> | @@ -62,25 +62,25 @@ class RxList<E> extends ListMixin<E> | ||
62 | 62 | ||
63 | @override | 63 | @override |
64 | void add(E item) { | 64 | void add(E item) { |
65 | - _value.add(item); | 65 | + value.add(item); |
66 | refresh(); | 66 | refresh(); |
67 | } | 67 | } |
68 | 68 | ||
69 | @override | 69 | @override |
70 | void addAll(Iterable<E> item) { | 70 | void addAll(Iterable<E> item) { |
71 | - _value.addAll(item); | 71 | + value.addAll(item); |
72 | refresh(); | 72 | refresh(); |
73 | } | 73 | } |
74 | 74 | ||
75 | @override | 75 | @override |
76 | void removeWhere(bool test(E element)) { | 76 | void removeWhere(bool test(E element)) { |
77 | - _value.removeWhere(test); | 77 | + value.removeWhere(test); |
78 | refresh(); | 78 | refresh(); |
79 | } | 79 | } |
80 | 80 | ||
81 | @override | 81 | @override |
82 | void retainWhere(bool test(E element)) { | 82 | void retainWhere(bool test(E element)) { |
83 | - _value.retainWhere(test); | 83 | + value.retainWhere(test); |
84 | refresh(); | 84 | refresh(); |
85 | } | 85 | } |
86 | 86 | ||
@@ -91,18 +91,18 @@ class RxList<E> extends ListMixin<E> | @@ -91,18 +91,18 @@ class RxList<E> extends ListMixin<E> | ||
91 | @protected | 91 | @protected |
92 | List<E> get value { | 92 | List<E> get value { |
93 | RxInterface.proxy?.addListener(subject); | 93 | RxInterface.proxy?.addListener(subject); |
94 | - return _value; | 94 | + return subject.value; |
95 | } | 95 | } |
96 | 96 | ||
97 | @override | 97 | @override |
98 | set length(int newLength) { | 98 | set length(int newLength) { |
99 | - _value.length = newLength; | 99 | + value.length = newLength; |
100 | refresh(); | 100 | refresh(); |
101 | } | 101 | } |
102 | 102 | ||
103 | @override | 103 | @override |
104 | void insertAll(int index, Iterable<E> iterable) { | 104 | void insertAll(int index, Iterable<E> iterable) { |
105 | - _value.insertAll(index, iterable); | 105 | + value.insertAll(index, iterable); |
106 | refresh(); | 106 | refresh(); |
107 | } | 107 | } |
108 | 108 | ||
@@ -121,7 +121,7 @@ class RxList<E> extends ListMixin<E> | @@ -121,7 +121,7 @@ class RxList<E> extends ListMixin<E> | ||
121 | 121 | ||
122 | @override | 122 | @override |
123 | void sort([int compare(E a, E b)?]) { | 123 | void sort([int compare(E a, E b)?]) { |
124 | - _value.sort(compare); | 124 | + value.sort(compare); |
125 | refresh(); | 125 | refresh(); |
126 | } | 126 | } |
127 | } | 127 | } |
@@ -4,7 +4,7 @@ class RxMap<K, V> extends MapMixin<K, V> | @@ -4,7 +4,7 @@ class RxMap<K, V> extends MapMixin<K, V> | ||
4 | with NotifyManager<Map<K, V>>, RxObjectMixin<Map<K, V>> | 4 | with NotifyManager<Map<K, V>>, RxObjectMixin<Map<K, V>> |
5 | implements RxInterface<Map<K, V>> { | 5 | implements RxInterface<Map<K, V>> { |
6 | RxMap([Map<K, V> initial = const {}]) { | 6 | RxMap([Map<K, V> initial = const {}]) { |
7 | - _value = Map.from(initial); | 7 | + subject = GetStream.fromValue(Map.from(initial)); |
8 | } | 8 | } |
9 | 9 | ||
10 | factory RxMap.from(Map<K, V> other) { | 10 | factory RxMap.from(Map<K, V> other) { |
@@ -32,14 +32,14 @@ class RxMap<K, V> extends MapMixin<K, V> | @@ -32,14 +32,14 @@ class RxMap<K, V> extends MapMixin<K, V> | ||
32 | } | 32 | } |
33 | 33 | ||
34 | @override | 34 | @override |
35 | - void operator []=(K key, V value) { | ||
36 | - _value[key] = value; | 35 | + void operator []=(K key, V val) { |
36 | + value[key] = val; | ||
37 | refresh(); | 37 | refresh(); |
38 | } | 38 | } |
39 | 39 | ||
40 | @override | 40 | @override |
41 | void clear() { | 41 | void clear() { |
42 | - _value.clear(); | 42 | + value.clear(); |
43 | refresh(); | 43 | refresh(); |
44 | } | 44 | } |
45 | 45 | ||
@@ -48,7 +48,7 @@ class RxMap<K, V> extends MapMixin<K, V> | @@ -48,7 +48,7 @@ class RxMap<K, V> extends MapMixin<K, V> | ||
48 | 48 | ||
49 | @override | 49 | @override |
50 | V? remove(Object? key) { | 50 | V? remove(Object? key) { |
51 | - final val = _value.remove(key); | 51 | + final val = value.remove(key); |
52 | refresh(); | 52 | refresh(); |
53 | return val; | 53 | return val; |
54 | } | 54 | } |
@@ -56,8 +56,9 @@ class RxMap<K, V> extends MapMixin<K, V> | @@ -56,8 +56,9 @@ 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 | - RxInterface.proxy?.addListener(subject); | ||
60 | - return _value; | 59 | + return subject.value; |
60 | + // RxInterface.proxy?.addListener(subject); | ||
61 | + // return _value; | ||
61 | } | 62 | } |
62 | } | 63 | } |
63 | 64 | ||
@@ -82,7 +83,7 @@ extension MapExtension<K, V> on Map<K, V> { | @@ -82,7 +83,7 @@ extension MapExtension<K, V> on Map<K, V> { | ||
82 | if (this is RxMap) { | 83 | if (this is RxMap) { |
83 | final map = (this as RxMap); | 84 | final map = (this as RxMap); |
84 | // map._value; | 85 | // map._value; |
85 | - map._value.clear(); | 86 | + map.value.clear(); |
86 | this[key] = val; | 87 | this[key] = val; |
87 | } else { | 88 | } else { |
88 | clear(); | 89 | clear(); |
@@ -92,12 +93,12 @@ extension MapExtension<K, V> on Map<K, V> { | @@ -92,12 +93,12 @@ extension MapExtension<K, V> on Map<K, V> { | ||
92 | 93 | ||
93 | void assignAll(Map<K, V> val) { | 94 | void assignAll(Map<K, V> val) { |
94 | if (val is RxMap && this is RxMap) { | 95 | if (val is RxMap && this is RxMap) { |
95 | - if ((val as RxMap)._value == (this as RxMap)._value) return; | 96 | + if ((val as RxMap).value == (this as RxMap).value) return; |
96 | } | 97 | } |
97 | if (this is RxMap) { | 98 | if (this is RxMap) { |
98 | final map = (this as RxMap); | 99 | final map = (this as RxMap); |
99 | - if (map._value == val) return; | ||
100 | - map._value = val; | 100 | + if (map.value == val) return; |
101 | + map.value = val; | ||
101 | map.refresh(); | 102 | map.refresh(); |
102 | } else { | 103 | } else { |
103 | if (this == val) return; | 104 | if (this == val) return; |
@@ -4,7 +4,7 @@ class RxSet<E> extends SetMixin<E> | @@ -4,7 +4,7 @@ class RxSet<E> extends SetMixin<E> | ||
4 | with NotifyManager<Set<E>>, RxObjectMixin<Set<E>> | 4 | with NotifyManager<Set<E>>, RxObjectMixin<Set<E>> |
5 | implements RxInterface<Set<E>> { | 5 | implements RxInterface<Set<E>> { |
6 | RxSet([Set<E> initial = const {}]) { | 6 | RxSet([Set<E> initial = const {}]) { |
7 | - _value = Set.from(initial); | 7 | + subject = GetStream.fromValue(Set.from(initial)); |
8 | } | 8 | } |
9 | 9 | ||
10 | /// Special override to push() element(s) in a reactive way | 10 | /// Special override to push() element(s) in a reactive way |
@@ -23,21 +23,22 @@ class RxSet<E> extends SetMixin<E> | @@ -23,21 +23,22 @@ 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 | - RxInterface.proxy?.addListener(subject); | ||
27 | - return _value; | 26 | + return subject.value; |
27 | + // RxInterface.proxy?.addListener(subject); | ||
28 | + // return _value; | ||
28 | } | 29 | } |
29 | 30 | ||
30 | @override | 31 | @override |
31 | @protected | 32 | @protected |
32 | set value(Set<E> val) { | 33 | set value(Set<E> val) { |
33 | - if (_value == val) return; | ||
34 | - _value = val; | 34 | + if (value == val) return; |
35 | + value = val; | ||
35 | refresh(); | 36 | refresh(); |
36 | } | 37 | } |
37 | 38 | ||
38 | @override | 39 | @override |
39 | bool add(E value) { | 40 | bool add(E value) { |
40 | - final hasAdded = _value.add(value); | 41 | + final hasAdded = value.add(value); |
41 | if (hasAdded) { | 42 | if (hasAdded) { |
42 | refresh(); | 43 | refresh(); |
43 | } | 44 | } |
@@ -62,7 +63,7 @@ class RxSet<E> extends SetMixin<E> | @@ -62,7 +63,7 @@ class RxSet<E> extends SetMixin<E> | ||
62 | 63 | ||
63 | @override | 64 | @override |
64 | bool remove(Object? item) { | 65 | bool remove(Object? item) { |
65 | - var hasRemoved = _value.remove(item); | 66 | + var hasRemoved = value.remove(item); |
66 | if (hasRemoved) { | 67 | if (hasRemoved) { |
67 | refresh(); | 68 | refresh(); |
68 | } | 69 | } |
@@ -76,31 +77,31 @@ class RxSet<E> extends SetMixin<E> | @@ -76,31 +77,31 @@ class RxSet<E> extends SetMixin<E> | ||
76 | 77 | ||
77 | @override | 78 | @override |
78 | void addAll(Iterable<E> item) { | 79 | void addAll(Iterable<E> item) { |
79 | - _value.addAll(item); | 80 | + value.addAll(item); |
80 | refresh(); | 81 | refresh(); |
81 | } | 82 | } |
82 | 83 | ||
83 | @override | 84 | @override |
84 | void clear() { | 85 | void clear() { |
85 | - _value.clear(); | 86 | + value.clear(); |
86 | refresh(); | 87 | refresh(); |
87 | } | 88 | } |
88 | 89 | ||
89 | @override | 90 | @override |
90 | void removeAll(Iterable<Object?> elements) { | 91 | void removeAll(Iterable<Object?> elements) { |
91 | - _value.removeAll(elements); | 92 | + value.removeAll(elements); |
92 | refresh(); | 93 | refresh(); |
93 | } | 94 | } |
94 | 95 | ||
95 | @override | 96 | @override |
96 | void retainAll(Iterable<Object?> elements) { | 97 | void retainAll(Iterable<Object?> elements) { |
97 | - _value.retainAll(elements); | 98 | + value.retainAll(elements); |
98 | refresh(); | 99 | refresh(); |
99 | } | 100 | } |
100 | 101 | ||
101 | @override | 102 | @override |
102 | void retainWhere(bool Function(E) E) { | 103 | void retainWhere(bool Function(E) E) { |
103 | - _value.retainWhere(E); | 104 | + value.retainWhere(E); |
104 | refresh(); | 105 | refresh(); |
105 | } | 106 | } |
106 | } | 107 | } |
@@ -4,6 +4,7 @@ import 'dart:async'; | @@ -4,6 +4,7 @@ import 'dart:async'; | ||
4 | import 'dart:collection'; | 4 | import 'dart:collection'; |
5 | 5 | ||
6 | import 'package:flutter/foundation.dart'; | 6 | import 'package:flutter/foundation.dart'; |
7 | +import 'package:get/get_state_manager/src/simple/list_notifier.dart'; | ||
7 | import '../rx_stream/rx_stream.dart'; | 8 | import '../rx_stream/rx_stream.dart'; |
8 | import '../rx_typedefs/rx_typedefs.dart'; | 9 | import '../rx_typedefs/rx_typedefs.dart'; |
9 | 10 |
@@ -14,9 +14,6 @@ typedef GetXControllerBuilder<T extends DisposableInterface> = Widget Function( | @@ -14,9 +14,6 @@ typedef GetXControllerBuilder<T extends DisposableInterface> = Widget Function( | ||
14 | class GetX<T extends DisposableInterface> extends StatefulWidget { | 14 | class GetX<T extends DisposableInterface> extends StatefulWidget { |
15 | final GetXControllerBuilder<T> builder; | 15 | final GetXControllerBuilder<T> builder; |
16 | final bool global; | 16 | final bool global; |
17 | - | ||
18 | - // final Stream Function(T) stream; | ||
19 | - // final StreamController Function(T) streamController; | ||
20 | final bool autoRemove; | 17 | final bool autoRemove; |
21 | final bool assignId; | 18 | final bool assignId; |
22 | final void Function(GetXState<T> state)? initState, | 19 | final void Function(GetXState<T> state)? initState, |
@@ -7,7 +7,7 @@ import '../../get_state_manager.dart'; | @@ -7,7 +7,7 @@ import '../../get_state_manager.dart'; | ||
7 | import '../simple/list_notifier.dart'; | 7 | import '../simple/list_notifier.dart'; |
8 | 8 | ||
9 | mixin StateMixin<T> on ListNotifierMixin { | 9 | mixin StateMixin<T> on ListNotifierMixin { |
10 | - T? _value; | 10 | + late T _value; |
11 | RxStatus? _status; | 11 | RxStatus? _status; |
12 | 12 | ||
13 | bool _isNullOrEmpty(dynamic val) { | 13 | bool _isNullOrEmpty(dynamic val) { |
@@ -32,23 +32,23 @@ mixin StateMixin<T> on ListNotifierMixin { | @@ -32,23 +32,23 @@ mixin StateMixin<T> on ListNotifierMixin { | ||
32 | return _status ??= _status = RxStatus.loading(); | 32 | return _status ??= _status = RxStatus.loading(); |
33 | } | 33 | } |
34 | 34 | ||
35 | - T? get state => value; | 35 | + T get state => value; |
36 | 36 | ||
37 | @protected | 37 | @protected |
38 | - T? get value { | 38 | + T get value { |
39 | notifyChildrens(); | 39 | notifyChildrens(); |
40 | return _value; | 40 | return _value; |
41 | } | 41 | } |
42 | 42 | ||
43 | @protected | 43 | @protected |
44 | - set value(T? newValue) { | 44 | + set value(T newValue) { |
45 | if (_value == newValue) return; | 45 | if (_value == newValue) return; |
46 | _value = newValue; | 46 | _value = newValue; |
47 | refresh(); | 47 | refresh(); |
48 | } | 48 | } |
49 | 49 | ||
50 | @protected | 50 | @protected |
51 | - void change(T? newState, {RxStatus? status}) { | 51 | + void change(T newState, {RxStatus? status}) { |
52 | var _canUpdate = false; | 52 | var _canUpdate = false; |
53 | if (status != null) { | 53 | if (status != null) { |
54 | _status = status; | 54 | _status = status; |
@@ -82,13 +82,13 @@ class Value<T> extends ListNotifier | @@ -82,13 +82,13 @@ class Value<T> extends ListNotifier | ||
82 | } | 82 | } |
83 | 83 | ||
84 | @override | 84 | @override |
85 | - T? get value { | 85 | + T get value { |
86 | notifyChildrens(); | 86 | notifyChildrens(); |
87 | return _value; | 87 | return _value; |
88 | } | 88 | } |
89 | 89 | ||
90 | @override | 90 | @override |
91 | - set value(T? newValue) { | 91 | + set value(T newValue) { |
92 | if (_value == newValue) return; | 92 | if (_value == newValue) return; |
93 | _value = newValue; | 93 | _value = newValue; |
94 | refresh(); | 94 | refresh(); |
@@ -119,9 +119,7 @@ extension ReactiveT<T> on T { | @@ -119,9 +119,7 @@ extension ReactiveT<T> on T { | ||
119 | typedef Condition = bool Function(); | 119 | typedef Condition = bool Function(); |
120 | 120 | ||
121 | abstract class GetNotifier<T> extends Value<T> with GetLifeCycleBase { | 121 | abstract class GetNotifier<T> extends Value<T> with GetLifeCycleBase { |
122 | - GetNotifier(T initial) : super(initial) { | ||
123 | - $configureLifeCycle(); | ||
124 | - } | 122 | + GetNotifier(T initial) : super(initial); |
125 | 123 | ||
126 | @override | 124 | @override |
127 | @mustCallSuper | 125 | @mustCallSuper |
@@ -194,3 +192,44 @@ class RxStatus { | @@ -194,3 +192,44 @@ class RxStatus { | ||
194 | } | 192 | } |
195 | 193 | ||
196 | typedef NotifierBuilder<T> = Widget Function(T state); | 194 | typedef NotifierBuilder<T> = Widget Function(T state); |
195 | + | ||
196 | +abstract class GState<T> { | ||
197 | + const GState(); | ||
198 | + factory GState.loading() => GLoading(); | ||
199 | + factory GState.error(String message) => GError(message); | ||
200 | + factory GState.empty() => GEmpty(); | ||
201 | + factory GState.success(T data) => GSuccess(data); | ||
202 | +} | ||
203 | + | ||
204 | +class GLoading<T> extends GState<T> {} | ||
205 | + | ||
206 | +class GSuccess<T> extends GState<T> { | ||
207 | + final T data; | ||
208 | + | ||
209 | + GSuccess(this.data); | ||
210 | +} | ||
211 | + | ||
212 | +class GError<T, S> extends GState<T> { | ||
213 | + final S? error; | ||
214 | + GError([this.error]); | ||
215 | +} | ||
216 | + | ||
217 | +class GEmpty<T> extends GState<T> {} | ||
218 | + | ||
219 | +extension StatusDataExt<T> on GState<T> { | ||
220 | + bool get isLoading => this is GLoading; | ||
221 | + bool get isSuccess => this is GSuccess; | ||
222 | + bool get isError => this is GError; | ||
223 | + bool get isEmpty => this is GEmpty; | ||
224 | + String get errorMessage { | ||
225 | + final isError = this is GError; | ||
226 | + if (isError) { | ||
227 | + final err = this as GError; | ||
228 | + if (err.error != null && err.error is String) { | ||
229 | + return err.error as String; | ||
230 | + } | ||
231 | + } | ||
232 | + | ||
233 | + return ''; | ||
234 | + } | ||
235 | +} |
1 | import 'dart:async'; | 1 | import 'dart:async'; |
2 | + | ||
2 | import 'package:flutter/foundation.dart'; | 3 | import 'package:flutter/foundation.dart'; |
3 | import 'package:flutter/widgets.dart'; | 4 | import 'package:flutter/widgets.dart'; |
5 | + | ||
4 | import '../../../get_rx/src/rx_types/rx_types.dart'; | 6 | import '../../../get_rx/src/rx_types/rx_types.dart'; |
5 | 7 | ||
6 | typedef WidgetCallback = Widget Function(); | 8 | typedef WidgetCallback = Widget Function(); |
@@ -54,6 +56,15 @@ class _ObxState extends State<ObxWidget> { | @@ -54,6 +56,15 @@ class _ObxState extends State<ObxWidget> { | ||
54 | RxInterface.notifyChildren(_observer, widget.build); | 56 | RxInterface.notifyChildren(_observer, widget.build); |
55 | } | 57 | } |
56 | 58 | ||
59 | + | ||
60 | + | ||
61 | + | ||
62 | + | ||
63 | + | ||
64 | + | ||
65 | + | ||
66 | + | ||
67 | + | ||
57 | /// The simplest reactive widget in GetX. | 68 | /// The simplest reactive widget in GetX. |
58 | /// | 69 | /// |
59 | /// Just pass your Rx variable in the root scope of the callback to have it | 70 | /// Just pass your Rx variable in the root scope of the callback to have it |
1 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
2 | + | ||
2 | import '../../../get_instance/src/get_instance.dart'; | 3 | import '../../../get_instance/src/get_instance.dart'; |
3 | import '../../../instance_manager.dart'; | 4 | import '../../../instance_manager.dart'; |
4 | import '../../get_state_manager.dart'; | 5 | import '../../get_state_manager.dart'; |
5 | -import 'list_notifier.dart'; | ||
6 | - | ||
7 | -/// Complies with `GetStateUpdater` | ||
8 | -/// | ||
9 | -/// This mixin's function represents a `GetStateUpdater`, and might be used | ||
10 | -/// by `GetBuilder()`, `SimpleBuilder()` (or similar) to comply | ||
11 | -/// with [GetStateUpdate] signature. REPLACING the [StateSetter]. | ||
12 | -/// Avoids the potential (but extremely unlikely) issue of having | ||
13 | -/// the Widget in a dispose() state, and abstracts the | ||
14 | -/// API from the ugly fn((){}). | ||
15 | -mixin GetStateUpdaterMixin<T extends StatefulWidget> on State<T> { | ||
16 | - // To avoid the creation of an anonym function to be GC later. | ||
17 | - // ignore: prefer_function_declarations_over_variables | ||
18 | - | ||
19 | - /// Experimental method to replace setState((){}); | ||
20 | - /// Used with GetStateUpdate. | ||
21 | - void getUpdate() { | ||
22 | - if (mounted) setState(() {}); | ||
23 | - } | ||
24 | -} | ||
25 | 6 | ||
26 | typedef GetControllerBuilder<T extends DisposableInterface> = Widget Function( | 7 | typedef GetControllerBuilder<T extends DisposableInterface> = Widget Function( |
27 | T controller); | 8 | T controller); |
28 | 9 | ||
29 | -// class _InheritedGetxController<T extends GetxController> | ||
30 | -// extends InheritedWidget { | ||
31 | -// final T model; | ||
32 | -// final int version; | ||
33 | - | ||
34 | -// _InheritedGetxController({ | ||
35 | -// Key key, | ||
36 | -// @required Widget child, | ||
37 | -// @required this.model, | ||
38 | -// }) : version = model.notifierVersion, | ||
39 | -// super(key: key, child: child); | ||
40 | - | ||
41 | -// @override | ||
42 | -// bool updateShouldNotify(_InheritedGetxController<T> oldWidget) => | ||
43 | -// (oldWidget.version != version); | ||
44 | -// } | 10 | +extension WatchExt on BuildContext { |
11 | + T listen<T extends GetxController>() { | ||
12 | + return Scope.of(this, rebuild: true); | ||
13 | + } | ||
14 | +} | ||
15 | + | ||
16 | +extension ReadExt on BuildContext { | ||
17 | + T find<T extends GetxController>() { | ||
18 | + return Scope.of(this); | ||
19 | + } | ||
20 | +} | ||
45 | 21 | ||
46 | -// extension WatchEtx on GetxController { | ||
47 | -// T watch<T extends GetxController>() { | ||
48 | -// final instance = Get.find<T>(); | ||
49 | -// _GetBuilderState._currentState.watch(instance.update); | ||
50 | -// return instance; | 22 | +// extension FilterExt on BuildContext { |
23 | +// T filter<T extends GetxController>(Object Function(T value)? filter) { | ||
24 | +// return Scope.of(this, filter: filter, rebuild: true); | ||
51 | // } | 25 | // } |
52 | // } | 26 | // } |
53 | 27 | ||
54 | -class GetBuilder<T extends GetxController> extends StatefulWidget { | 28 | +class GetBuilder<T extends GetxController> extends StatelessWidget { |
55 | final GetControllerBuilder<T> builder; | 29 | final GetControllerBuilder<T> builder; |
56 | final bool global; | 30 | final bool global; |
57 | final Object? id; | 31 | final Object? id; |
@@ -59,10 +33,10 @@ class GetBuilder<T extends GetxController> extends StatefulWidget { | @@ -59,10 +33,10 @@ class GetBuilder<T extends GetxController> extends StatefulWidget { | ||
59 | final bool autoRemove; | 33 | final bool autoRemove; |
60 | final bool assignId; | 34 | final bool assignId; |
61 | final Object Function(T value)? filter; | 35 | final Object Function(T value)? filter; |
62 | - final void Function(GetBuilderState<T> state)? initState, | 36 | + final void Function(ScopeElement<T> state)? initState, |
63 | dispose, | 37 | dispose, |
64 | didChangeDependencies; | 38 | didChangeDependencies; |
65 | - final void Function(GetBuilder oldWidget, GetBuilderState<T> state)? | 39 | + final void Function(Scope<T> oldWidget, ScopeElement<T> state)? |
66 | didUpdateWidget; | 40 | didUpdateWidget; |
67 | final T? init; | 41 | final T? init; |
68 | 42 | ||
@@ -82,40 +56,127 @@ class GetBuilder<T extends GetxController> extends StatefulWidget { | @@ -82,40 +56,127 @@ class GetBuilder<T extends GetxController> extends StatefulWidget { | ||
82 | this.didUpdateWidget, | 56 | this.didUpdateWidget, |
83 | }) : super(key: key); | 57 | }) : super(key: key); |
84 | 58 | ||
85 | - // static T of<T extends GetxController>( | ||
86 | - // BuildContext context, { | ||
87 | - // bool rebuild = false, | ||
88 | - // }) { | ||
89 | - // var widget = rebuild | ||
90 | - // ? context | ||
91 | - // .dependOnInheritedWidgetOfExactType<_InheritedGetxController<T>>() | ||
92 | - // : context | ||
93 | - // .getElementForInheritedWidgetOfExactType< | ||
94 | - // _InheritedGetxController<T>>() | ||
95 | - // ?.widget; | ||
96 | - | ||
97 | - // if (widget == null) { | ||
98 | - // throw 'Error: Could not find the correct dependency.'; | ||
99 | - // } else { | ||
100 | - // return (widget as _InheritedGetxController<T>).model; | ||
101 | - // } | ||
102 | - // } | 59 | + @override |
60 | + Widget build(BuildContext context) { | ||
61 | + return Scope<T>( | ||
62 | + init: init, | ||
63 | + global: global, | ||
64 | + autoRemove: autoRemove, | ||
65 | + assignId: assignId, | ||
66 | + initState: initState, | ||
67 | + filter: filter, | ||
68 | + tag: tag, | ||
69 | + dispose: dispose, | ||
70 | + id: id, | ||
71 | + didChangeDependencies: didChangeDependencies, | ||
72 | + didUpdateWidget: didUpdateWidget, | ||
73 | + child: Builder(builder: (context) { | ||
74 | + final controller = Scope.of<T>(context, rebuild: true); | ||
75 | + return builder(controller); | ||
76 | + }), | ||
77 | + ); | ||
78 | + // return widget.builder(controller!); | ||
79 | + } | ||
80 | +} | ||
81 | + | ||
82 | +class Scope<T extends GetxController> extends InheritedWidget { | ||
83 | + /// Create an inherited widget that updates its dependents when [controller] | ||
84 | + /// sends notifications. | ||
85 | + /// | ||
86 | + /// The [child] argument is required | ||
87 | + const Scope({ | ||
88 | + Key? key, | ||
89 | + required Widget child, | ||
90 | + this.init, | ||
91 | + this.global = true, | ||
92 | + this.autoRemove = true, | ||
93 | + this.assignId = false, | ||
94 | + this.initState, | ||
95 | + this.filter, | ||
96 | + this.tag, | ||
97 | + this.dispose, | ||
98 | + this.id, | ||
99 | + this.didChangeDependencies, | ||
100 | + this.didUpdateWidget, | ||
101 | + }) : super(key: key, child: child); | ||
102 | + | ||
103 | + /// The [Listenable] object to which to listen. | ||
104 | + /// | ||
105 | + /// Whenever this object sends change notifications, the dependents of this | ||
106 | + /// widget are triggered. | ||
107 | + /// | ||
108 | + /// By default, whenever the [controller] is changed (including when changing to | ||
109 | + /// or from null), if the old controller is not equal to the new controller (as | ||
110 | + /// determined by the `==` operator), notifications are sent. This behavior | ||
111 | + /// can be overridden by overriding [updateShouldNotify]. | ||
112 | + /// | ||
113 | + /// While the [controller] is null, no notifications are sent, since the null | ||
114 | + /// object cannot itself send notifications. | ||
115 | + final T? init; | ||
116 | + | ||
117 | + final bool global; | ||
118 | + final Object? id; | ||
119 | + final String? tag; | ||
120 | + final bool autoRemove; | ||
121 | + final bool assignId; | ||
122 | + final Object Function(T value)? filter; | ||
123 | + final void Function(ScopeElement<T> state)? initState, | ||
124 | + dispose, | ||
125 | + didChangeDependencies; | ||
126 | + final void Function(Scope<T> oldWidget, ScopeElement<T> state)? | ||
127 | + didUpdateWidget; | ||
128 | + | ||
129 | + static T of<T extends GetxController>( | ||
130 | + BuildContext context, { | ||
131 | + bool rebuild = false, | ||
132 | + // Object Function(T value)? filter, | ||
133 | + }) { | ||
134 | + final inheritedElement = context | ||
135 | + .getElementForInheritedWidgetOfExactType<Scope<T>>() as ScopeElement<T>; | ||
136 | + | ||
137 | + if (rebuild) { | ||
138 | + // var newFilter = filter?.call(inheritedElement.controller!); | ||
139 | + // if (newFilter != null) { | ||
140 | + // context.dependOnInheritedElement(inheritedElement, aspect: newFilter); | ||
141 | + // } else { | ||
142 | + context.dependOnInheritedElement(inheritedElement); | ||
143 | + // } | ||
144 | + } | ||
145 | + | ||
146 | + var widget = inheritedElement.controller; | ||
147 | + | ||
148 | + if (widget == null) { | ||
149 | + throw 'Error: Could not find the correct dependency.'; | ||
150 | + } else { | ||
151 | + return widget; | ||
152 | + } | ||
153 | + } | ||
103 | 154 | ||
104 | @override | 155 | @override |
105 | - GetBuilderState<T> createState() => GetBuilderState<T>(); | 156 | + bool updateShouldNotify(Scope<T> oldWidget) { |
157 | + return oldWidget.id != id || | ||
158 | + oldWidget.global != global || | ||
159 | + oldWidget.autoRemove != autoRemove || | ||
160 | + oldWidget.assignId != assignId; | ||
161 | + } | ||
162 | + | ||
163 | + @override | ||
164 | + InheritedElement createElement() => ScopeElement<T>(this); | ||
106 | } | 165 | } |
107 | 166 | ||
108 | -class GetBuilderState<T extends GetxController> extends State<GetBuilder<T>> | ||
109 | - with GetStateUpdaterMixin { | 167 | +/// The ScopeElement is responsible for injecting dependencies into the widget |
168 | +/// tree so that they can be observed | ||
169 | +class ScopeElement<T extends GetxController> extends InheritedElement { | ||
170 | + ScopeElement(Scope<T> widget) : super(widget) { | ||
171 | + initState(); | ||
172 | + } | ||
173 | + | ||
110 | T? controller; | 174 | T? controller; |
111 | bool? _isCreator = false; | 175 | bool? _isCreator = false; |
112 | VoidCallback? _remove; | 176 | VoidCallback? _remove; |
113 | Object? _filter; | 177 | Object? _filter; |
114 | 178 | ||
115 | - @override | ||
116 | void initState() { | 179 | void initState() { |
117 | - // _GetBuilderState._currentState = this; | ||
118 | - super.initState(); | ||
119 | widget.initState?.call(this); | 180 | widget.initState?.call(this); |
120 | 181 | ||
121 | var isRegistered = GetInstance().isRegistered<T>(tag: widget.tag); | 182 | var isRegistered = GetInstance().isRegistered<T>(tag: widget.tag); |
@@ -169,9 +230,7 @@ class GetBuilderState<T extends GetxController> extends State<GetBuilder<T>> | @@ -169,9 +230,7 @@ class GetBuilderState<T extends GetxController> extends State<GetBuilder<T>> | ||
169 | } | 230 | } |
170 | } | 231 | } |
171 | 232 | ||
172 | - @override | ||
173 | void dispose() { | 233 | void dispose() { |
174 | - super.dispose(); | ||
175 | widget.dispose?.call(this); | 234 | widget.dispose?.call(this); |
176 | if (_isCreator! || widget.assignId) { | 235 | if (_isCreator! || widget.assignId) { |
177 | if (widget.autoRemove && GetInstance().isRegistered<T>(tag: widget.tag)) { | 236 | if (widget.autoRemove && GetInstance().isRegistered<T>(tag: widget.tag)) { |
@@ -188,39 +247,49 @@ class GetBuilderState<T extends GetxController> extends State<GetBuilder<T>> | @@ -188,39 +247,49 @@ class GetBuilderState<T extends GetxController> extends State<GetBuilder<T>> | ||
188 | } | 247 | } |
189 | 248 | ||
190 | @override | 249 | @override |
250 | + Scope<T> get widget => super.widget as Scope<T>; | ||
251 | + | ||
252 | + var _dirty = false; | ||
253 | + | ||
254 | + @override | ||
255 | + void update(Scope<T> newWidget) { | ||
256 | + final oldNotifier = widget.id; | ||
257 | + final newNotifier = newWidget.id; | ||
258 | + if (oldNotifier != newNotifier) { | ||
259 | + _subscribeToController(); | ||
260 | + } | ||
261 | + widget.didUpdateWidget?.call(widget, this); | ||
262 | + super.update(newWidget); | ||
263 | + } | ||
264 | + | ||
265 | + @override | ||
191 | void didChangeDependencies() { | 266 | void didChangeDependencies() { |
192 | super.didChangeDependencies(); | 267 | super.didChangeDependencies(); |
193 | widget.didChangeDependencies?.call(this); | 268 | widget.didChangeDependencies?.call(this); |
194 | } | 269 | } |
195 | 270 | ||
196 | @override | 271 | @override |
197 | - void didUpdateWidget(GetBuilder oldWidget) { | ||
198 | - super.didUpdateWidget(oldWidget as GetBuilder<T>); | ||
199 | - // to avoid conflicts when modifying a "grouped" id list. | ||
200 | - if (oldWidget.id != widget.id) { | ||
201 | - _subscribeToController(); | 272 | + Widget build() { |
273 | + if (_dirty) { | ||
274 | + notifyClients(widget); | ||
202 | } | 275 | } |
203 | - widget.didUpdateWidget?.call(oldWidget, this); | 276 | + return super.build(); |
204 | } | 277 | } |
205 | 278 | ||
206 | - @override | ||
207 | - Widget build(BuildContext context) { | ||
208 | - // return _InheritedGetxController<T>( | ||
209 | - // model: controller, | ||
210 | - // child: widget.builder(controller), | ||
211 | - // ); | ||
212 | - return widget.builder(controller!); | 279 | + void getUpdate() { |
280 | + _dirty = true; | ||
281 | + markNeedsBuild(); | ||
213 | } | 282 | } |
214 | -} | ||
215 | 283 | ||
216 | -// extension FindExt on BuildContext { | ||
217 | -// T find<T extends GetxController>() { | ||
218 | -// return GetBuilder.of<T>(this, rebuild: false); | ||
219 | -// } | ||
220 | -// } | 284 | + @override |
285 | + void notifyClients(Scope<T> oldWidget) { | ||
286 | + super.notifyClients(oldWidget); | ||
287 | + _dirty = false; | ||
288 | + } | ||
221 | 289 | ||
222 | -// extension ObserverEtx on BuildContext { | ||
223 | -// T obs<T extends GetxController>() { | ||
224 | -// return GetBuilder.of<T>(this, rebuild: true); | ||
225 | -// } | ||
226 | -// } | 290 | + @override |
291 | + void unmount() { | ||
292 | + dispose(); | ||
293 | + super.unmount(); | ||
294 | + } | ||
295 | +} |
@@ -159,15 +159,11 @@ class TaskManager { | @@ -159,15 +159,11 @@ class TaskManager { | ||
159 | } | 159 | } |
160 | } | 160 | } |
161 | 161 | ||
162 | - Widget exchange( | ||
163 | - List<VoidCallback> disposers, | ||
164 | - GetStateUpdate setState, | ||
165 | - Widget Function(BuildContext) builder, | ||
166 | - BuildContext context, | ||
167 | - ) { | 162 | + T exchange<T>(List<VoidCallback> disposers, GetStateUpdate setState, |
163 | + T Function() builder) { | ||
168 | _remove = disposers; | 164 | _remove = disposers; |
169 | _setter = setState; | 165 | _setter = setState; |
170 | - final result = builder(context); | 166 | + final result = builder(); |
171 | _remove = null; | 167 | _remove = null; |
172 | _setter = null; | 168 | _setter = null; |
173 | return result; | 169 | return result; |
@@ -8,8 +8,11 @@ class MixinBuilder<T extends GetxController> extends StatelessWidget { | @@ -8,8 +8,11 @@ class MixinBuilder<T extends GetxController> extends StatelessWidget { | ||
8 | final bool global; | 8 | final bool global; |
9 | final String? id; | 9 | final String? id; |
10 | final bool autoRemove; | 10 | final bool autoRemove; |
11 | - final void Function(State state)? initState, dispose, didChangeDependencies; | ||
12 | - final void Function(GetBuilder oldWidget, State state)? didUpdateWidget; | 11 | + final void Function(ScopeElement<T> state)? initState, |
12 | + dispose, | ||
13 | + didChangeDependencies; | ||
14 | + final void Function(Scope<T> oldWidget, ScopeElement<T> state)? | ||
15 | + didUpdateWidget; | ||
13 | final T? init; | 16 | final T? init; |
14 | 17 | ||
15 | const MixinBuilder({ | 18 | const MixinBuilder({ |
1 | import 'dart:async'; | 1 | import 'dart:async'; |
2 | + | ||
2 | import 'package:flutter/widgets.dart'; | 3 | import 'package:flutter/widgets.dart'; |
3 | -import 'get_state.dart'; | 4 | + |
4 | import 'list_notifier.dart'; | 5 | import 'list_notifier.dart'; |
5 | 6 | ||
6 | typedef ValueBuilderUpdateCallback<T> = void Function(T snapshot); | 7 | typedef ValueBuilderUpdateCallback<T> = void Function(T snapshot); |
@@ -74,35 +75,39 @@ class _ValueBuilderState<T> extends State<ValueBuilder<T?>> { | @@ -74,35 +75,39 @@ class _ValueBuilderState<T> extends State<ValueBuilder<T?>> { | ||
74 | } | 75 | } |
75 | } | 76 | } |
76 | 77 | ||
78 | +class ObxElement = StatelessElement with ObserverComponent; | ||
79 | + | ||
77 | // It's a experimental feature | 80 | // It's a experimental feature |
78 | -class SimpleBuilder extends StatefulWidget { | ||
79 | - final Widget Function(BuildContext) builder; | 81 | +class SimpleBuilder extends ObxStatelessWidget { |
82 | + final WidgetBuilder builder; | ||
80 | 83 | ||
81 | const SimpleBuilder({Key? key, required this.builder}) : super(key: key); | 84 | const SimpleBuilder({Key? key, required this.builder}) : super(key: key); |
82 | 85 | ||
83 | @override | 86 | @override |
84 | - _SimpleBuilderState createState() => _SimpleBuilderState(); | 87 | + Widget build(BuildContext context) => builder(context); |
85 | } | 88 | } |
86 | 89 | ||
87 | -class _SimpleBuilderState extends State<SimpleBuilder> | ||
88 | - with GetStateUpdaterMixin { | 90 | +/// A StatelessWidget than can listen reactive changes. |
91 | +abstract class ObxStatelessWidget extends StatelessWidget { | ||
92 | + /// Initializes [key] for subclasses. | ||
93 | + const ObxStatelessWidget({Key? key}) : super(key: key); | ||
94 | + @override | ||
95 | + StatelessElement createElement() => ObxElement(this); | ||
96 | +} | ||
97 | + | ||
98 | +/// a Component that can track changes in a reactive variable | ||
99 | +mixin ObserverComponent on ComponentElement { | ||
89 | final disposers = <Disposer>[]; | 100 | final disposers = <Disposer>[]; |
90 | 101 | ||
91 | @override | 102 | @override |
92 | - void dispose() { | ||
93 | - super.dispose(); | 103 | + Widget build() => |
104 | + TaskManager.instance.exchange(disposers, markNeedsBuild, super.build); | ||
105 | + | ||
106 | + @override | ||
107 | + void unmount() { | ||
108 | + super.unmount(); | ||
94 | for (final disposer in disposers) { | 109 | for (final disposer in disposers) { |
95 | disposer(); | 110 | disposer(); |
96 | } | 111 | } |
97 | } | 112 | } |
98 | - | ||
99 | - @override | ||
100 | - Widget build(BuildContext context) { | ||
101 | - return TaskManager.instance.exchange( | ||
102 | - disposers, | ||
103 | - getUpdate, | ||
104 | - widget.builder, | ||
105 | - context, | ||
106 | - ); | ||
107 | - } | ||
108 | } | 113 | } |
test/.DS_Store
0 → 100644
No preview for this file type
-
Please register or login to post a comment