Showing
15 changed files
with
197 additions
and
56 deletions
@@ -52,11 +52,11 @@ | @@ -52,11 +52,11 @@ | ||
52 | - [ValueBuilder](#valuebuilder) | 52 | - [ValueBuilder](#valuebuilder) |
53 | - [ObxValue](#obxvalue) | 53 | - [ObxValue](#obxvalue) |
54 | - [Useful tips](#useful-tips) | 54 | - [Useful tips](#useful-tips) |
55 | - - [GetView](#getview) | ||
56 | - - [GetResponsiveView](#getresponsiveview) | ||
57 | - - [How to use it](#how-to-use-it) | ||
58 | - - [GetWidget](#getwidget) | ||
59 | - - [GetxService](#getxservice) | 55 | + - [GetView](#getview) |
56 | + - [GetResponsiveView](#getresponsiveview) | ||
57 | + - [How to use it](#how-to-use-it) | ||
58 | + - [GetWidget](#getwidget) | ||
59 | + - [GetxService](#getxservice) | ||
60 | - [Breaking changes from 2.0](#breaking-changes-from-20) | 60 | - [Breaking changes from 2.0](#breaking-changes-from-20) |
61 | - [Why Getx?](#why-getx) | 61 | - [Why Getx?](#why-getx) |
62 | - [Community](#community) | 62 | - [Community](#community) |
@@ -71,19 +71,19 @@ | @@ -71,19 +71,19 @@ | ||
71 | - GetX has 3 basic principles, this means that this is the priority for all resources in the library: **PRODUCTIVITY, PERFORMANCE AND ORGANIZATION.** | 71 | - GetX has 3 basic principles, this means that this is the priority for all resources in the library: **PRODUCTIVITY, PERFORMANCE AND ORGANIZATION.** |
72 | 72 | ||
73 | - **PERFORMANCE:** GetX is focused on performance and minimum consumption of resources. GetX does not use Streams or ChangeNotifier. | 73 | - **PERFORMANCE:** GetX is focused on performance and minimum consumption of resources. GetX does not use Streams or ChangeNotifier. |
74 | - | ||
75 | - - **PRODUCTIVITY:** GetX uses an easy and pleasant syntax. No matter what you want to do, there is always an easier way with Getx. It will save hours of development, and will extract the maximum performance that your application can deliver. | ||
76 | - Generally, the developer should be concerned with removing controllers from memory. With GetX this is not necessary, because resources are removed from memory when they are not used by default. If you want to keep it in memory, you must explicitly declare "permanent: true" in your dependency. That way, in addition to saving time, you are less at risk of having unnecessary dependencies on memory. Dependency loading is also lazy by default. | 74 | + |
75 | + - **PRODUCTIVITY:** GetX uses an easy and pleasant syntax. No matter what you want to do, there is always an easier way with Getx. It will save hours of development, and will extract the maximum performance that your application can deliver. | ||
76 | + Generally, the developer should be concerned with removing controllers from memory. With GetX this is not necessary, because resources are removed from memory when they are not used by default. If you want to keep it in memory, you must explicitly declare "permanent: true" in your dependency. That way, in addition to saving time, you are less at risk of having unnecessary dependencies on memory. Dependency loading is also lazy by default. | ||
77 | 77 | ||
78 | - **ORGANIZATION:** GetX allows the total decoupling of the View, presentation logic, business logic, dependency injection, and navigation. You do not need context to navigate between routes, so you are not dependent on the widget tree (visualization) for this. You don't need context to access your controllers/blocs through an inheritedWidget, so you completely decouple your presentation logic and business logic from your visualization layer. You do not need to inject your Controllers/Models/Blocs classes into your widget tree through multiproviders, for this GetX uses its own dependency injection feature, decoupling the DI from its view completely. | 78 | - **ORGANIZATION:** GetX allows the total decoupling of the View, presentation logic, business logic, dependency injection, and navigation. You do not need context to navigate between routes, so you are not dependent on the widget tree (visualization) for this. You don't need context to access your controllers/blocs through an inheritedWidget, so you completely decouple your presentation logic and business logic from your visualization layer. You do not need to inject your Controllers/Models/Blocs classes into your widget tree through multiproviders, for this GetX uses its own dependency injection feature, decoupling the DI from its view completely. |
79 | - With GetX you know where to find each feature of your application, having clean code by default. This in addition to facilitating maintenance, makes the sharing of modules, something that until then in Flutter was unthinkable, something totally possible. | ||
80 | - BLoC was a starting point for organizing code in Flutter, it separates business logic from visualization. Getx is a natural evolution of this, not only separating the business logic, but the presentation logic. Bonus injection of dependencies and routes are also decoupled, and the data layer is out of it all. You know where everything is, and all of this in an easier way than building a hello world. | ||
81 | - GetX is the easiest, practical and scalable way to build high-performance applications with the Flutter SDK, with a large ecosystem around it that works perfectly together, being easy for beginners, and accurate for experts. It is secure, stable, up-to-date, and offers a huge range of APIs build-in that are not present on default Flutter SDK. | 79 | + With GetX you know where to find each feature of your application, having clean code by default. This in addition to facilitating maintenance, makes the sharing of modules, something that until then in Flutter was unthinkable, something totally possible. |
80 | + BLoC was a starting point for organizing code in Flutter, it separates business logic from visualization. Getx is a natural evolution of this, not only separating the business logic, but the presentation logic. Bonus injection of dependencies and routes are also decoupled, and the data layer is out of it all. You know where everything is, and all of this in an easier way than building a hello world. | ||
81 | + GetX is the easiest, practical and scalable way to build high-performance applications with the Flutter SDK, with a large ecosystem around it that works perfectly together, being easy for beginners, and accurate for experts. It is secure, stable, up-to-date, and offers a huge range of APIs build-in that are not present on default Flutter SDK. | ||
82 | 82 | ||
83 | - GetX is not a bloated. It has a multitude of features that allow you to start programming without worrying about anything, but each of these features are in separate containers, and are only started after use. If you only use State Management, only State Management will be compiled. If you only use routes, nothing from the state management will be compiled. | 83 | - GetX is not a bloated. It has a multitude of features that allow you to start programming without worrying about anything, but each of these features are in separate containers, and are only started after use. If you only use State Management, only State Management will be compiled. If you only use routes, nothing from the state management will be compiled. |
84 | 84 | ||
85 | - Getx has a huge ecosystem, a large community, a large number of collaborators, and will be maintained as long as the Flutter exists. Getx too is capable of running with the same code on Android, iOS, Web, Mac, Linux, Windows, and on your server. | 85 | - Getx has a huge ecosystem, a large community, a large number of collaborators, and will be maintained as long as the Flutter exists. Getx too is capable of running with the same code on Android, iOS, Web, Mac, Linux, Windows, and on your server. |
86 | -**It is possible to fully reuse your code made on the frontend on your backend with [Get Server](https://github.com/jonataslaw/get_server)**. | 86 | + **It is possible to fully reuse your code made on the frontend on your backend with [Get Server](https://github.com/jonataslaw/get_server)**. |
87 | 87 | ||
88 | **In addition, the entire development process can be completely automated, both on the server and on the front end with [Get CLI](https://github.com/jonataslaw/get_cli)**. | 88 | **In addition, the entire development process can be completely automated, both on the server and on the front end with [Get CLI](https://github.com/jonataslaw/get_cli)**. |
89 | 89 | ||
@@ -138,7 +138,7 @@ class Home extends StatelessWidget { | @@ -138,7 +138,7 @@ class Home extends StatelessWidget { | ||
138 | 138 | ||
139 | @override | 139 | @override |
140 | Widget build(context) { | 140 | Widget build(context) { |
141 | - | 141 | + |
142 | // Instantiate your class using Get.put() to make it available for all "child" routes there. | 142 | // Instantiate your class using Get.put() to make it available for all "child" routes there. |
143 | final Controller c = Get.put(Controller()); | 143 | final Controller c = Get.put(Controller()); |
144 | 144 | ||
@@ -341,6 +341,13 @@ Just append `.tr` to the specified key and it will be translated, using the curr | @@ -341,6 +341,13 @@ Just append `.tr` to the specified key and it will be translated, using the curr | ||
341 | Text('title'.tr); | 341 | Text('title'.tr); |
342 | ``` | 342 | ``` |
343 | 343 | ||
344 | +#### Using translation with singular and plural | ||
345 | + | ||
346 | +```dart | ||
347 | +var products = []; | ||
348 | +Text('singularKey'.trPlural('pluralKey', products.length, Args)); | ||
349 | +``` | ||
350 | + | ||
344 | ### Locales | 351 | ### Locales |
345 | 352 | ||
346 | Pass parameters to `GetMaterialApp` to define the locale and translations. | 353 | Pass parameters to `GetMaterialApp` to define the locale and translations. |
@@ -394,9 +401,11 @@ Get.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark()); | @@ -394,9 +401,11 @@ Get.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark()); | ||
394 | When `.darkmode` is activated, it will switch to the _light theme_, and when the _light theme_ becomes active, it will change to _dark theme_. | 401 | When `.darkmode` is activated, it will switch to the _light theme_, and when the _light theme_ becomes active, it will change to _dark theme_. |
395 | 402 | ||
396 | ## GetConnect | 403 | ## GetConnect |
404 | + | ||
397 | GetConnect is an easy way to communicate from your back to your front with http or websockets | 405 | GetConnect is an easy way to communicate from your back to your front with http or websockets |
398 | 406 | ||
399 | ### Default configuration | 407 | ### Default configuration |
408 | + | ||
400 | You can simply extend GetConnect and use the GET/POST/PUT/DELETE/SOCKET methods to communicate with your Rest API or websockets. | 409 | You can simply extend GetConnect and use the GET/POST/PUT/DELETE/SOCKET methods to communicate with your Rest API or websockets. |
401 | 410 | ||
402 | ```dart | 411 | ```dart |
@@ -419,7 +428,9 @@ class UserProvider extends GetConnect { | @@ -419,7 +428,9 @@ class UserProvider extends GetConnect { | ||
419 | } | 428 | } |
420 | } | 429 | } |
421 | ``` | 430 | ``` |
431 | + | ||
422 | ### Custom configuration | 432 | ### Custom configuration |
433 | + | ||
423 | GetConnect is highly customizable You can define base Url, as answer modifiers, as Requests modifiers, define an authenticator, and even the number of attempts in which it will try to authenticate itself, in addition to giving the possibility to define a standard decoder that will transform all your requests into your Models without any additional configuration. | 434 | GetConnect is highly customizable You can define base Url, as answer modifiers, as Requests modifiers, define an authenticator, and even the number of attempts in which it will try to authenticate itself, in addition to giving the possibility to define a standard decoder that will transform all your requests into your Models without any additional configuration. |
424 | 435 | ||
425 | ```dart | 436 | ```dart |
@@ -456,7 +467,7 @@ class HomeProvider extends GetConnect { | @@ -456,7 +467,7 @@ class HomeProvider extends GetConnect { | ||
456 | return request; | 467 | return request; |
457 | }); | 468 | }); |
458 | 469 | ||
459 | - //Autenticator will be called 3 times if HttpStatus is | 470 | + //Autenticator will be called 3 times if HttpStatus is |
460 | //HttpStatus.unauthorized | 471 | //HttpStatus.unauthorized |
461 | httpClient.maxAuthRetries = 3; | 472 | httpClient.maxAuthRetries = 3; |
462 | } | 473 | } |
@@ -485,6 +496,7 @@ final middlewares = [ | @@ -485,6 +496,7 @@ final middlewares = [ | ||
485 | GetMiddleware(priority: -8), | 496 | GetMiddleware(priority: -8), |
486 | ]; | 497 | ]; |
487 | ``` | 498 | ``` |
499 | + | ||
488 | those middlewares will be run in this order **-8 => 2 => 4 => 5** | 500 | those middlewares will be run in this order **-8 => 2 => 4 => 5** |
489 | 501 | ||
490 | ### Redirect | 502 | ### Redirect |
@@ -917,10 +929,10 @@ You have two options to build it. | @@ -917,10 +929,10 @@ You have two options to build it. | ||
917 | 929 | ||
918 | - with `builder` method you return the widget to build. | 930 | - with `builder` method you return the widget to build. |
919 | - with methods `desktop`, `tablet`,`phone`, `watch`. the specific | 931 | - with methods `desktop`, `tablet`,`phone`, `watch`. the specific |
920 | -method will be built when the screen type matches the method | ||
921 | -when the screen is [ScreenType.Tablet] the `tablet` method | ||
922 | -will be exuded and so on. | ||
923 | -**Note:** If you use this method please set the property `alwaysUseBuilder` to `false` | 932 | + method will be built when the screen type matches the method |
933 | + when the screen is [ScreenType.Tablet] the `tablet` method | ||
934 | + will be exuded and so on. | ||
935 | + **Note:** If you use this method please set the property `alwaysUseBuilder` to `false` | ||
924 | 936 | ||
925 | With `settings` property you can set the width limit for the screen types. | 937 | With `settings` property you can set the width limit for the screen types. |
926 | 938 | ||
@@ -1098,4 +1110,3 @@ Any contribution is welcome! | @@ -1098,4 +1110,3 @@ Any contribution is welcome! | ||
1098 | - [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris. | 1110 | - [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris. |
1099 | - [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - by App With Flutter. | 1111 | - [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - by App With Flutter. |
1100 | - [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - by App With Flutter. | 1112 | - [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - by App With Flutter. |
1101 | - |
@@ -139,6 +139,7 @@ class GetHttpClient { | @@ -139,6 +139,7 @@ class GetHttpClient { | ||
139 | url: uri, | 139 | url: uri, |
140 | headers: headers, | 140 | headers: headers, |
141 | bodyBytes: bodyStream, | 141 | bodyBytes: bodyStream, |
142 | + contentLength: bodyBytes.length, | ||
142 | followRedirects: followRedirects, | 143 | followRedirects: followRedirects, |
143 | maxRedirects: maxRedirects, | 144 | maxRedirects: maxRedirects, |
144 | decoder: decoder, | 145 | decoder: decoder, |
@@ -32,15 +32,15 @@ class HttpRequestImpl extends HttpRequestBase { | @@ -32,15 +32,15 @@ class HttpRequestImpl extends HttpRequestBase { | ||
32 | 32 | ||
33 | @override | 33 | @override |
34 | Future<Response<T>> send<T>(Request<T> request) async { | 34 | Future<Response<T>> send<T>(Request<T> request) async { |
35 | - var requestBody = await request.bodyBytes.toBytes(); | ||
36 | - var stream = BodyBytesStream.fromBytes(requestBody ?? const []); | 35 | + var stream = request.bodyBytes.asBroadcastStream(); |
36 | + //var stream = BodyBytesStream.fromBytes(requestBody ?? const []); | ||
37 | 37 | ||
38 | try { | 38 | try { |
39 | var ioRequest = (await _httpClient.openUrl(request.method, request.url)) | 39 | var ioRequest = (await _httpClient.openUrl(request.method, request.url)) |
40 | ..followRedirects = request.followRedirects | 40 | ..followRedirects = request.followRedirects |
41 | ..persistentConnection = request.persistentConnection | 41 | ..persistentConnection = request.persistentConnection |
42 | ..maxRedirects = request.maxRedirects | 42 | ..maxRedirects = request.maxRedirects |
43 | - ..contentLength = requestBody.length ?? -1; | 43 | + ..contentLength = request.contentLength ?? -1; |
44 | request.headers.forEach(ioRequest.headers.set); | 44 | request.headers.forEach(ioRequest.headers.set); |
45 | 45 | ||
46 | var response = await stream.pipe(ioRequest) as io.HttpClientResponse; | 46 | var response = await stream.pipe(ioRequest) as io.HttpClientResponse; |
@@ -20,6 +20,8 @@ class Request<T> { | @@ -20,6 +20,8 @@ class Request<T> { | ||
20 | /// ex: `GET`,`POST`,`PUT`,`DELETE` | 20 | /// ex: `GET`,`POST`,`PUT`,`DELETE` |
21 | final String method; | 21 | final String method; |
22 | 22 | ||
23 | + final int contentLength; | ||
24 | + | ||
23 | /// The BodyBytesStream of body from this [Request] | 25 | /// The BodyBytesStream of body from this [Request] |
24 | final BodyBytesStream bodyBytes; | 26 | final BodyBytesStream bodyBytes; |
25 | 27 | ||
@@ -38,6 +40,7 @@ class Request<T> { | @@ -38,6 +40,7 @@ class Request<T> { | ||
38 | @required this.bodyBytes, | 40 | @required this.bodyBytes, |
39 | @required this.url, | 41 | @required this.url, |
40 | @required this.headers, | 42 | @required this.headers, |
43 | + @required this.contentLength, | ||
41 | @required this.followRedirects, | 44 | @required this.followRedirects, |
42 | @required this.maxRedirects, | 45 | @required this.maxRedirects, |
43 | @required this.files, | 46 | @required this.files, |
@@ -52,6 +55,7 @@ class Request<T> { | @@ -52,6 +55,7 @@ class Request<T> { | ||
52 | BodyBytesStream bodyBytes, | 55 | BodyBytesStream bodyBytes, |
53 | bool followRedirects = true, | 56 | bool followRedirects = true, |
54 | int maxRedirects = 4, | 57 | int maxRedirects = 4, |
58 | + int contentLength, | ||
55 | FormData files, | 59 | FormData files, |
56 | bool persistentConnection = true, | 60 | bool persistentConnection = true, |
57 | Decoder<T> decoder, | 61 | Decoder<T> decoder, |
@@ -70,6 +74,7 @@ class Request<T> { | @@ -70,6 +74,7 @@ class Request<T> { | ||
70 | headers: Map.from(headers ??= <String, String>{}), | 74 | headers: Map.from(headers ??= <String, String>{}), |
71 | followRedirects: followRedirects, | 75 | followRedirects: followRedirects, |
72 | maxRedirects: maxRedirects, | 76 | maxRedirects: maxRedirects, |
77 | + contentLength: contentLength, | ||
73 | files: files, | 78 | files: files, |
74 | persistentConnection: persistentConnection, | 79 | persistentConnection: persistentConnection, |
75 | decoder: decoder, | 80 | decoder: decoder, |
@@ -5,6 +5,7 @@ export 'src/extension_navigation.dart'; | @@ -5,6 +5,7 @@ export 'src/extension_navigation.dart'; | ||
5 | export 'src/root/get_cupertino_app.dart'; | 5 | export 'src/root/get_cupertino_app.dart'; |
6 | export 'src/root/get_material_app.dart'; | 6 | export 'src/root/get_material_app.dart'; |
7 | export 'src/root/internacionalization.dart'; | 7 | export 'src/root/internacionalization.dart'; |
8 | +export 'src/root/root_controller.dart'; | ||
8 | export 'src/routes/custom_transition.dart'; | 9 | export 'src/routes/custom_transition.dart'; |
9 | export 'src/routes/default_route.dart'; | 10 | export 'src/routes/default_route.dart'; |
10 | export 'src/routes/get_route.dart'; | 11 | export 'src/routes/get_route.dart'; |
@@ -5,6 +5,7 @@ export 'src/rx_flutter/rx_getx_widget.dart'; | @@ -5,6 +5,7 @@ export 'src/rx_flutter/rx_getx_widget.dart'; | ||
5 | export 'src/rx_flutter/rx_notifier.dart'; | 5 | export 'src/rx_flutter/rx_notifier.dart'; |
6 | export 'src/rx_flutter/rx_obx_widget.dart'; | 6 | export 'src/rx_flutter/rx_obx_widget.dart'; |
7 | export 'src/rx_flutter/rx_ticket_provider_mixin.dart'; | 7 | export 'src/rx_flutter/rx_ticket_provider_mixin.dart'; |
8 | +export 'src/simple/get_controllers.dart'; | ||
8 | export 'src/simple/get_responsive.dart'; | 9 | export 'src/simple/get_responsive.dart'; |
9 | export 'src/simple/get_state.dart'; | 10 | export 'src/simple/get_state.dart'; |
10 | export 'src/simple/get_view.dart'; | 11 | export 'src/simple/get_view.dart'; |
@@ -24,7 +24,6 @@ abstract class DisposableInterface extends GetLifeCycle { | @@ -24,7 +24,6 @@ abstract class DisposableInterface extends GetLifeCycle { | ||
24 | /// navigation events, like snackbar, dialogs, or a new route, or | 24 | /// navigation events, like snackbar, dialogs, or a new route, or |
25 | /// async request. | 25 | /// async request. |
26 | @override | 26 | @override |
27 | - @mustCallSuper | ||
28 | void onReady() { | 27 | void onReady() { |
29 | super.onReady(); | 28 | super.onReady(); |
30 | } | 29 | } |
1 | +// ignore: prefer_mixin | ||
2 | +import 'package:flutter/widgets.dart'; | ||
3 | + | ||
4 | +import '../rx_flutter/rx_disposable.dart'; | ||
5 | +import '../rx_flutter/rx_notifier.dart'; | ||
6 | +import 'list_notifier.dart'; | ||
7 | + | ||
8 | +// ignore: prefer_mixin | ||
9 | +abstract class GetxController extends DisposableInterface with ListNotifier { | ||
10 | + /// Rebuilds [GetBuilder] each time you call [update()]; | ||
11 | + /// Can take a List of [ids], that will only update the matching | ||
12 | + /// `GetBuilder( id: )`, | ||
13 | + /// [ids] can be reused among `GetBuilders` like group tags. | ||
14 | + /// The update will only notify the Widgets, if [condition] is true. | ||
15 | + void update([List<String> ids, bool condition = true]) { | ||
16 | + if (!condition) { | ||
17 | + return; | ||
18 | + } | ||
19 | + if (ids == null) { | ||
20 | + refresh(); | ||
21 | + } else { | ||
22 | + for (final id in ids) { | ||
23 | + refreshGroup(id); | ||
24 | + } | ||
25 | + } | ||
26 | + } | ||
27 | +} | ||
28 | + | ||
29 | +abstract class RxController extends DisposableInterface {} | ||
30 | + | ||
31 | +abstract class SuperController<T> extends FullLifeCycleController | ||
32 | + with FullLifeCycle, StateMixin<T> {} | ||
33 | + | ||
34 | +abstract class FullLifeCycleController extends GetxController | ||
35 | + with | ||
36 | + // ignore: prefer_mixin | ||
37 | + WidgetsBindingObserver {} | ||
38 | + | ||
39 | +mixin FullLifeCycle on FullLifeCycleController { | ||
40 | + @mustCallSuper | ||
41 | + @override | ||
42 | + void onInit() { | ||
43 | + super.onInit(); | ||
44 | + WidgetsBinding.instance.addObserver(this); | ||
45 | + } | ||
46 | + | ||
47 | + @mustCallSuper | ||
48 | + @override | ||
49 | + void onClose() { | ||
50 | + WidgetsBinding.instance.removeObserver(this); | ||
51 | + super.onClose(); | ||
52 | + } | ||
53 | + | ||
54 | + @mustCallSuper | ||
55 | + @override | ||
56 | + void didChangeAppLifecycleState(AppLifecycleState state) { | ||
57 | + switch (state) { | ||
58 | + case AppLifecycleState.resumed: | ||
59 | + onResumed(); | ||
60 | + break; | ||
61 | + case AppLifecycleState.inactive: | ||
62 | + onInactive(); | ||
63 | + break; | ||
64 | + case AppLifecycleState.paused: | ||
65 | + onPaused(); | ||
66 | + break; | ||
67 | + case AppLifecycleState.detached: | ||
68 | + onDetached(); | ||
69 | + break; | ||
70 | + } | ||
71 | + } | ||
72 | + | ||
73 | + void onResumed(); | ||
74 | + void onPaused(); | ||
75 | + void onInactive(); | ||
76 | + void onDetached(); | ||
77 | +} |
1 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
2 | import '../../../get_instance/src/get_instance.dart'; | 2 | import '../../../get_instance/src/get_instance.dart'; |
3 | +import '../../../instance_manager.dart'; | ||
3 | import '../../get_state_manager.dart'; | 4 | import '../../get_state_manager.dart'; |
4 | import 'list_notifier.dart'; | 5 | import 'list_notifier.dart'; |
5 | 6 | ||
@@ -22,30 +23,26 @@ mixin GetStateUpdaterMixin<T extends StatefulWidget> on State<T> { | @@ -22,30 +23,26 @@ mixin GetStateUpdaterMixin<T extends StatefulWidget> on State<T> { | ||
22 | } | 23 | } |
23 | } | 24 | } |
24 | 25 | ||
25 | -// ignore: prefer_mixin | ||
26 | -class GetxController extends DisposableInterface with ListNotifier { | ||
27 | - /// Rebuilds [GetBuilder] each time you call [update()]; | ||
28 | - /// Can take a List of [ids], that will only update the matching | ||
29 | - /// `GetBuilder( id: )`, | ||
30 | - /// [ids] can be reused among `GetBuilders` like group tags. | ||
31 | - /// The update will only notify the Widgets, if [condition] is true. | ||
32 | - void update([List<String> ids, bool condition = true]) { | ||
33 | - if (!condition) { | ||
34 | - return; | ||
35 | - } | ||
36 | - if (ids == null) { | ||
37 | - refresh(); | ||
38 | - } else { | ||
39 | - for (final id in ids) { | ||
40 | - refreshGroup(id); | ||
41 | - } | ||
42 | - } | ||
43 | - } | ||
44 | -} | ||
45 | - | ||
46 | typedef GetControllerBuilder<T extends DisposableInterface> = Widget Function( | 26 | typedef GetControllerBuilder<T extends DisposableInterface> = Widget Function( |
47 | T controller); | 27 | T controller); |
48 | 28 | ||
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 | +} | ||
45 | + | ||
49 | class GetBuilder<T extends GetxController> extends StatefulWidget { | 46 | class GetBuilder<T extends GetxController> extends StatefulWidget { |
50 | final GetControllerBuilder<T> builder; | 47 | final GetControllerBuilder<T> builder; |
51 | final bool global; | 48 | final bool global; |
@@ -73,6 +70,25 @@ class GetBuilder<T extends GetxController> extends StatefulWidget { | @@ -73,6 +70,25 @@ class GetBuilder<T extends GetxController> extends StatefulWidget { | ||
73 | }) : assert(builder != null), | 70 | }) : assert(builder != null), |
74 | super(key: key); | 71 | super(key: key); |
75 | 72 | ||
73 | + static T of<T extends GetxController>( | ||
74 | + BuildContext context, { | ||
75 | + bool rebuild = false, | ||
76 | + }) { | ||
77 | + var widget = rebuild | ||
78 | + ? context | ||
79 | + .dependOnInheritedWidgetOfExactType<_InheritedGetxController<T>>() | ||
80 | + : context | ||
81 | + .getElementForInheritedWidgetOfExactType< | ||
82 | + _InheritedGetxController<T>>() | ||
83 | + ?.widget; | ||
84 | + | ||
85 | + if (widget == null) { | ||
86 | + throw 'Error: Could not find the correct dependency.'; | ||
87 | + } else { | ||
88 | + return (widget as _InheritedGetxController<T>).model; | ||
89 | + } | ||
90 | + } | ||
91 | + | ||
76 | @override | 92 | @override |
77 | _GetBuilderState<T> createState() => _GetBuilderState<T>(); | 93 | _GetBuilderState<T> createState() => _GetBuilderState<T>(); |
78 | } | 94 | } |
@@ -156,5 +172,23 @@ class _GetBuilderState<T extends GetxController> extends State<GetBuilder<T>> | @@ -156,5 +172,23 @@ class _GetBuilderState<T extends GetxController> extends State<GetBuilder<T>> | ||
156 | } | 172 | } |
157 | 173 | ||
158 | @override | 174 | @override |
159 | - Widget build(BuildContext context) => widget.builder(controller); | 175 | + Widget build(BuildContext context) { |
176 | + return _InheritedGetxController<T>( | ||
177 | + model: controller, | ||
178 | + child: widget.builder(controller), | ||
179 | + ); | ||
180 | + } | ||
181 | +} | ||
182 | + | ||
183 | +extension FindExt on BuildContext { | ||
184 | + T find<T extends GetxController>() { | ||
185 | + return GetBuilder.of<T>(this, rebuild: false); | ||
186 | + } | ||
187 | +} | ||
188 | + | ||
189 | +extension ObserverEtx on BuildContext { | ||
190 | + T obs<T extends GetxController>() { | ||
191 | + return GetBuilder.of<T>(this, rebuild: true); | ||
192 | + } | ||
160 | } | 193 | } |
194 | + |
@@ -72,7 +72,10 @@ class _GetCache<S extends GetLifeCycleBase> extends WidgetCache<GetWidget<S>> { | @@ -72,7 +72,10 @@ class _GetCache<S extends GetLifeCycleBase> extends WidgetCache<GetWidget<S>> { | ||
72 | @override | 72 | @override |
73 | void onInit() { | 73 | void onInit() { |
74 | _isCreator = Get.isPrepared<S>(tag: widget.tag); | 74 | _isCreator = Get.isPrepared<S>(tag: widget.tag); |
75 | - _controller = Get.find<S>(tag: widget.tag); | 75 | + if (Get.isPrepared<S>()) { |
76 | + _controller = Get.find<S>(tag: widget.tag); | ||
77 | + } | ||
78 | + | ||
76 | GetWidget._cache[widget] = _controller; | 79 | GetWidget._cache[widget] = _controller; |
77 | super.onInit(); | 80 | super.onInit(); |
78 | } | 81 | } |
@@ -21,7 +21,7 @@ class GetWidgetCacheElement extends ComponentElement { | @@ -21,7 +21,7 @@ class GetWidgetCacheElement extends ComponentElement { | ||
21 | 21 | ||
22 | @override | 22 | @override |
23 | void mount(Element parent, dynamic newSlot) { | 23 | void mount(Element parent, dynamic newSlot) { |
24 | - cache.onInit(); | 24 | + cache?.onInit(); |
25 | super.mount(parent, newSlot); | 25 | super.mount(parent, newSlot); |
26 | } | 26 | } |
27 | 27 |
@@ -90,6 +90,11 @@ class ListNotifier implements Listenable { | @@ -90,6 +90,11 @@ class ListNotifier implements Listenable { | ||
90 | return _updaters.isNotEmpty; | 90 | return _updaters.isNotEmpty; |
91 | } | 91 | } |
92 | 92 | ||
93 | + int get listeners { | ||
94 | + assert(_debugAssertNotDisposed()); | ||
95 | + return _updaters.length; | ||
96 | + } | ||
97 | + | ||
93 | @override | 98 | @override |
94 | void removeListener(VoidCallback listener) { | 99 | void removeListener(VoidCallback listener) { |
95 | assert(_debugAssertNotDisposed()); | 100 | assert(_debugAssertNotDisposed()); |
@@ -40,15 +40,19 @@ extension Trans on String { | @@ -40,15 +40,19 @@ extension Trans on String { | ||
40 | } | 40 | } |
41 | } | 41 | } |
42 | 42 | ||
43 | - String trArgs([List<String> args]) { | 43 | + String trArgs([List<String> args = const []]) { |
44 | var key = tr; | 44 | var key = tr; |
45 | - if (args != null) { | 45 | + if (args.isNotEmpty) { |
46 | for (final arg in args) { | 46 | for (final arg in args) { |
47 | key = key.replaceFirst(RegExp(r'%s'), arg.toString()); | 47 | key = key.replaceFirst(RegExp(r'%s'), arg.toString()); |
48 | } | 48 | } |
49 | } | 49 | } |
50 | return key; | 50 | return key; |
51 | } | 51 | } |
52 | + | ||
53 | + String trPlural([String pluralKey, int i, List<String> args = const []]) { | ||
54 | + return i > 1 ? pluralKey.trArgs(args) : trArgs(args); | ||
55 | + } | ||
52 | } | 56 | } |
53 | 57 | ||
54 | class _IntlHost { | 58 | class _IntlHost { |
@@ -535,11 +535,7 @@ class GetUtils { | @@ -535,11 +535,7 @@ class GetUtils { | ||
535 | /// Remove all whitespace inside string | 535 | /// Remove all whitespace inside string |
536 | /// Example: your name => yourname | 536 | /// Example: your name => yourname |
537 | static String removeAllWhitespace(String value) { | 537 | static String removeAllWhitespace(String value) { |
538 | - if (isNullOrBlank(value)) { | ||
539 | - return null; | ||
540 | - } | ||
541 | - | ||
542 | - return value.replaceAll(' ', ''); | 538 | + return value?.replaceAll(' ', ''); |
543 | } | 539 | } |
544 | 540 | ||
545 | /// Camelcase string | 541 | /// Camelcase string |
@@ -549,7 +545,8 @@ class GetUtils { | @@ -549,7 +545,8 @@ class GetUtils { | ||
549 | return null; | 545 | return null; |
550 | } | 546 | } |
551 | 547 | ||
552 | - final separatedWords = value.split(' '); | 548 | + final separatedWords = |
549 | + value.split(RegExp(r'[!@#<>?":`~;[\]\\|=+)(*&^%-\s_]+')); | ||
553 | var newString = ''; | 550 | var newString = ''; |
554 | 551 | ||
555 | for (final word in separatedWords) { | 552 | for (final word in separatedWords) { |
@@ -690,14 +690,17 @@ void main() { | @@ -690,14 +690,17 @@ void main() { | ||
690 | }); | 690 | }); |
691 | 691 | ||
692 | test('var.removeAllWhitespace', () { | 692 | test('var.removeAllWhitespace', () { |
693 | + String nullString; | ||
693 | expect('foo bar'.removeAllWhitespace, 'foobar'); | 694 | expect('foo bar'.removeAllWhitespace, 'foobar'); |
694 | expect('foo'.removeAllWhitespace, 'foo'); | 695 | expect('foo'.removeAllWhitespace, 'foo'); |
695 | - expect(''.removeAllWhitespace, null); | 696 | + expect(''.removeAllWhitespace, ''); |
697 | + expect(nullString.removeAllWhitespace, null); | ||
696 | }); | 698 | }); |
697 | 699 | ||
698 | test('var.camelCase', () { | 700 | test('var.camelCase', () { |
699 | expect('foo bar'.camelCase, 'fooBar'); | 701 | expect('foo bar'.camelCase, 'fooBar'); |
700 | expect('the fox jumped in the water'.camelCase, 'theFoxJumpedInTheWater'); | 702 | expect('the fox jumped in the water'.camelCase, 'theFoxJumpedInTheWater'); |
703 | + expect('foo_bar'.camelCase, 'fooBar'); | ||
701 | expect(''.camelCase, null); | 704 | expect(''.camelCase, null); |
702 | }); | 705 | }); |
703 | 706 |
-
Please register or login to post a comment