Jonatas

add supercontroller and improve upload time

... ... @@ -83,7 +83,7 @@
- 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.
- 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.
**It is possible to fully reuse your code made on the frontend on your backend with [Get Server](https://github.com/jonataslaw/get_server)**.
**It is possible to fully reuse your code made on the frontend on your backend with [Get Server](https://github.com/jonataslaw/get_server)**.
**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)**.
... ... @@ -341,6 +341,13 @@ Just append `.tr` to the specified key and it will be translated, using the curr
Text('title'.tr);
```
#### Using translation with singular and plural
```dart
var products = [];
Text('singularKey'.trPlural('pluralKey', products.length, Args));
```
### Locales
Pass parameters to `GetMaterialApp` to define the locale and translations.
... ... @@ -394,9 +401,11 @@ Get.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());
When `.darkmode` is activated, it will switch to the _light theme_, and when the _light theme_ becomes active, it will change to _dark theme_.
## GetConnect
GetConnect is an easy way to communicate from your back to your front with http or websockets
### Default configuration
You can simply extend GetConnect and use the GET/POST/PUT/DELETE/SOCKET methods to communicate with your Rest API or websockets.
```dart
... ... @@ -419,7 +428,9 @@ class UserProvider extends GetConnect {
}
}
```
### Custom configuration
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.
```dart
... ... @@ -485,6 +496,7 @@ final middlewares = [
GetMiddleware(priority: -8),
];
```
those middlewares will be run in this order **-8 => 2 => 4 => 5**
### Redirect
... ... @@ -917,10 +929,10 @@ You have two options to build it.
- with `builder` method you return the widget to build.
- with methods `desktop`, `tablet`,`phone`, `watch`. the specific
method will be built when the screen type matches the method
when the screen is [ScreenType.Tablet] the `tablet` method
will be exuded and so on.
**Note:** If you use this method please set the property `alwaysUseBuilder` to `false`
method will be built when the screen type matches the method
when the screen is [ScreenType.Tablet] the `tablet` method
will be exuded and so on.
**Note:** If you use this method please set the property `alwaysUseBuilder` to `false`
With `settings` property you can set the width limit for the screen types.
... ... @@ -1098,4 +1110,3 @@ Any contribution is welcome!
- [GetX Flutter Firebase Auth Example](https://medium.com/@jeffmcmorris/getx-flutter-firebase-auth-example-b383c1dd1de2) - Article by Jeff McMorris.
- [Flutter State Management with GetX – Complete App](https://www.appwithflutter.com/flutter-state-management-with-getx/) - by App With Flutter.
- [Flutter Routing with Animation using Get Package](https://www.appwithflutter.com/flutter-routing-using-get-package/) - by App With Flutter.
... ...
... ... @@ -139,6 +139,7 @@ class GetHttpClient {
url: uri,
headers: headers,
bodyBytes: bodyStream,
contentLength: bodyBytes.length,
followRedirects: followRedirects,
maxRedirects: maxRedirects,
decoder: decoder,
... ...
... ... @@ -32,15 +32,15 @@ class HttpRequestImpl extends HttpRequestBase {
@override
Future<Response<T>> send<T>(Request<T> request) async {
var requestBody = await request.bodyBytes.toBytes();
var stream = BodyBytesStream.fromBytes(requestBody ?? const []);
var stream = request.bodyBytes.asBroadcastStream();
//var stream = BodyBytesStream.fromBytes(requestBody ?? const []);
try {
var ioRequest = (await _httpClient.openUrl(request.method, request.url))
..followRedirects = request.followRedirects
..persistentConnection = request.persistentConnection
..maxRedirects = request.maxRedirects
..contentLength = requestBody.length ?? -1;
..contentLength = request.contentLength ?? -1;
request.headers.forEach(ioRequest.headers.set);
var response = await stream.pipe(ioRequest) as io.HttpClientResponse;
... ...
... ... @@ -20,6 +20,8 @@ class Request<T> {
/// ex: `GET`,`POST`,`PUT`,`DELETE`
final String method;
final int contentLength;
/// The BodyBytesStream of body from this [Request]
final BodyBytesStream bodyBytes;
... ... @@ -38,6 +40,7 @@ class Request<T> {
@required this.bodyBytes,
@required this.url,
@required this.headers,
@required this.contentLength,
@required this.followRedirects,
@required this.maxRedirects,
@required this.files,
... ... @@ -52,6 +55,7 @@ class Request<T> {
BodyBytesStream bodyBytes,
bool followRedirects = true,
int maxRedirects = 4,
int contentLength,
FormData files,
bool persistentConnection = true,
Decoder<T> decoder,
... ... @@ -70,6 +74,7 @@ class Request<T> {
headers: Map.from(headers ??= <String, String>{}),
followRedirects: followRedirects,
maxRedirects: maxRedirects,
contentLength: contentLength,
files: files,
persistentConnection: persistentConnection,
decoder: decoder,
... ...
... ... @@ -5,6 +5,7 @@ export 'src/extension_navigation.dart';
export 'src/root/get_cupertino_app.dart';
export 'src/root/get_material_app.dart';
export 'src/root/internacionalization.dart';
export 'src/root/root_controller.dart';
export 'src/routes/custom_transition.dart';
export 'src/routes/default_route.dart';
export 'src/routes/get_route.dart';
... ...
... ... @@ -5,6 +5,7 @@ export 'src/rx_flutter/rx_getx_widget.dart';
export 'src/rx_flutter/rx_notifier.dart';
export 'src/rx_flutter/rx_obx_widget.dart';
export 'src/rx_flutter/rx_ticket_provider_mixin.dart';
export 'src/simple/get_controllers.dart';
export 'src/simple/get_responsive.dart';
export 'src/simple/get_state.dart';
export 'src/simple/get_view.dart';
... ...
... ... @@ -24,7 +24,6 @@ abstract class DisposableInterface extends GetLifeCycle {
/// navigation events, like snackbar, dialogs, or a new route, or
/// async request.
@override
@mustCallSuper
void onReady() {
super.onReady();
}
... ...
// ignore: prefer_mixin
import 'package:flutter/widgets.dart';
import '../rx_flutter/rx_disposable.dart';
import '../rx_flutter/rx_notifier.dart';
import 'list_notifier.dart';
// ignore: prefer_mixin
abstract class GetxController extends DisposableInterface with ListNotifier {
/// Rebuilds [GetBuilder] each time you call [update()];
/// Can take a List of [ids], that will only update the matching
/// `GetBuilder( id: )`,
/// [ids] can be reused among `GetBuilders` like group tags.
/// The update will only notify the Widgets, if [condition] is true.
void update([List<String> ids, bool condition = true]) {
if (!condition) {
return;
}
if (ids == null) {
refresh();
} else {
for (final id in ids) {
refreshGroup(id);
}
}
}
}
abstract class RxController extends DisposableInterface {}
abstract class SuperController<T> extends FullLifeCycleController
with FullLifeCycle, StateMixin<T> {}
abstract class FullLifeCycleController extends GetxController
with
// ignore: prefer_mixin
WidgetsBindingObserver {}
mixin FullLifeCycle on FullLifeCycleController {
@mustCallSuper
@override
void onInit() {
super.onInit();
WidgetsBinding.instance.addObserver(this);
}
@mustCallSuper
@override
void onClose() {
WidgetsBinding.instance.removeObserver(this);
super.onClose();
}
@mustCallSuper
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
switch (state) {
case AppLifecycleState.resumed:
onResumed();
break;
case AppLifecycleState.inactive:
onInactive();
break;
case AppLifecycleState.paused:
onPaused();
break;
case AppLifecycleState.detached:
onDetached();
break;
}
}
void onResumed();
void onPaused();
void onInactive();
void onDetached();
}
... ...
import 'package:flutter/material.dart';
import '../../../get_instance/src/get_instance.dart';
import '../../../instance_manager.dart';
import '../../get_state_manager.dart';
import 'list_notifier.dart';
... ... @@ -22,30 +23,26 @@ mixin GetStateUpdaterMixin<T extends StatefulWidget> on State<T> {
}
}
// ignore: prefer_mixin
class GetxController extends DisposableInterface with ListNotifier {
/// Rebuilds [GetBuilder] each time you call [update()];
/// Can take a List of [ids], that will only update the matching
/// `GetBuilder( id: )`,
/// [ids] can be reused among `GetBuilders` like group tags.
/// The update will only notify the Widgets, if [condition] is true.
void update([List<String> ids, bool condition = true]) {
if (!condition) {
return;
}
if (ids == null) {
refresh();
} else {
for (final id in ids) {
refreshGroup(id);
}
}
}
}
typedef GetControllerBuilder<T extends DisposableInterface> = Widget Function(
T controller);
class _InheritedGetxController<T extends GetxController>
extends InheritedWidget {
final T model;
final int version;
_InheritedGetxController({
Key key,
@required Widget child,
@required this.model,
}) : version = model.notifierVersion,
super(key: key, child: child);
@override
bool updateShouldNotify(_InheritedGetxController<T> oldWidget) =>
(oldWidget.version != version);
}
class GetBuilder<T extends GetxController> extends StatefulWidget {
final GetControllerBuilder<T> builder;
final bool global;
... ... @@ -73,6 +70,25 @@ class GetBuilder<T extends GetxController> extends StatefulWidget {
}) : assert(builder != null),
super(key: key);
static T of<T extends GetxController>(
BuildContext context, {
bool rebuild = false,
}) {
var widget = rebuild
? context
.dependOnInheritedWidgetOfExactType<_InheritedGetxController<T>>()
: context
.getElementForInheritedWidgetOfExactType<
_InheritedGetxController<T>>()
?.widget;
if (widget == null) {
throw 'Error: Could not find the correct dependency.';
} else {
return (widget as _InheritedGetxController<T>).model;
}
}
@override
_GetBuilderState<T> createState() => _GetBuilderState<T>();
}
... ... @@ -156,5 +172,23 @@ class _GetBuilderState<T extends GetxController> extends State<GetBuilder<T>>
}
@override
Widget build(BuildContext context) => widget.builder(controller);
Widget build(BuildContext context) {
return _InheritedGetxController<T>(
model: controller,
child: widget.builder(controller),
);
}
}
extension FindExt on BuildContext {
T find<T extends GetxController>() {
return GetBuilder.of<T>(this, rebuild: false);
}
}
extension ObserverEtx on BuildContext {
T obs<T extends GetxController>() {
return GetBuilder.of<T>(this, rebuild: true);
}
}
... ...
... ... @@ -72,7 +72,10 @@ class _GetCache<S extends GetLifeCycleBase> extends WidgetCache<GetWidget<S>> {
@override
void onInit() {
_isCreator = Get.isPrepared<S>(tag: widget.tag);
if (Get.isPrepared<S>()) {
_controller = Get.find<S>(tag: widget.tag);
}
GetWidget._cache[widget] = _controller;
super.onInit();
}
... ...
... ... @@ -21,7 +21,7 @@ class GetWidgetCacheElement extends ComponentElement {
@override
void mount(Element parent, dynamic newSlot) {
cache.onInit();
cache?.onInit();
super.mount(parent, newSlot);
}
... ...
... ... @@ -90,6 +90,11 @@ class ListNotifier implements Listenable {
return _updaters.isNotEmpty;
}
int get listeners {
assert(_debugAssertNotDisposed());
return _updaters.length;
}
@override
void removeListener(VoidCallback listener) {
assert(_debugAssertNotDisposed());
... ...
... ... @@ -40,15 +40,19 @@ extension Trans on String {
}
}
String trArgs([List<String> args]) {
String trArgs([List<String> args = const []]) {
var key = tr;
if (args != null) {
if (args.isNotEmpty) {
for (final arg in args) {
key = key.replaceFirst(RegExp(r'%s'), arg.toString());
}
}
return key;
}
String trPlural([String pluralKey, int i, List<String> args = const []]) {
return i > 1 ? pluralKey.trArgs(args) : trArgs(args);
}
}
class _IntlHost {
... ...
... ... @@ -535,11 +535,7 @@ class GetUtils {
/// Remove all whitespace inside string
/// Example: your name => yourname
static String removeAllWhitespace(String value) {
if (isNullOrBlank(value)) {
return null;
}
return value.replaceAll(' ', '');
return value?.replaceAll(' ', '');
}
/// Camelcase string
... ... @@ -549,7 +545,8 @@ class GetUtils {
return null;
}
final separatedWords = value.split(' ');
final separatedWords =
value.split(RegExp(r'[!@#<>?":`~;[\]\\|=+)(*&^%-\s_]+'));
var newString = '';
for (final word in separatedWords) {
... ...
... ... @@ -690,14 +690,17 @@ void main() {
});
test('var.removeAllWhitespace', () {
String nullString;
expect('foo bar'.removeAllWhitespace, 'foobar');
expect('foo'.removeAllWhitespace, 'foo');
expect(''.removeAllWhitespace, null);
expect(''.removeAllWhitespace, '');
expect(nullString.removeAllWhitespace, null);
});
test('var.camelCase', () {
expect('foo bar'.camelCase, 'fooBar');
expect('the fox jumped in the water'.camelCase, 'theFoxJumpedInTheWater');
expect('foo_bar'.camelCase, 'fooBar');
expect(''.camelCase, null);
});
... ...