Jonny Borges
Committed by GitHub

Bump to lastest version

## [2.5.2]
- Fix: key not found when Get.key is used with no MaterialApp
## [2.5.1]
- Improve - GetBuilder uses 18% less ram on more of 20 controllers.
## [2.5.0]
- Added List.obs
- Now you can transform any class on obs
... ...
... ... @@ -23,6 +23,23 @@ Flutter's conventional navigation has a lot of unnecessary boilerplate, requires
In addition, when a route is pushed, the entire MaterialApp can be rebuilt causing freezes, this does not happen with Get.
This library that will change the way you work with the Framework and save your life from cliche code, increasing your productivity, and eliminating the rebuild bugs of your application.
- **[How to use?](#how-to-use)**
- **[Navigating without named routes](#Navigating-without-named-routes)**
- **[SnackBars](#SnackBars)**
- **[Dialogs](#Dialogs)**
- **[BottomSheets](#BottomSheets)**
- **[Simple State Manager](#Simple-State-Manager)**
- **[Reactive State Manager](#Reactive-State-Manager)**
- **[Simple Instance Manager](#Simple-Instance-Manager)**
- **[Navigate with named routes](#Navigate-with-named-routes)**
- **[Send data to named Routes](#Send-data-to-named-Routes)**
- **[Dynamic urls links](#Dynamic-urls-links)**
- **[Middleware](#Middleware)**
- **[Optional Global Settings](#Optional-Global-Settings)**
- **[Other Advanced APIs and Manual configurations](#Other-Advanced-APIs-and-Manual-configurations)**
- **[Nested Navigators](#Nested-Navigators)**
## How to use?
<!-- - Flutter Master/Dev/Beta: version 2.0.x-dev
... ... @@ -39,7 +56,7 @@ GetMaterialApp( // Before: MaterialApp(
home: MyHome(),
)
```
### Navigating without named routes
## Navigating without named routes
To navigate to a new screen:
```dart
... ... @@ -153,6 +170,7 @@ With Get, all you have to do is call your Get.snackbar from anywhere in your cod
// SnackPosition snackPosition,
// Widget titleText,
// Widget messageText,
// bool instantInit,
// Widget icon,
// bool shouldIconPulse,
// double maxWidth,
... ... @@ -242,7 +260,7 @@ What performance improvements does Get bring?
1- Update only the required widget.
2- Does not use changeNotifier, it is the state manager that uses less memory (close to 0mb).
2- Does not use changeNotifier, it is the state manager that uses less memory (close to 0mb for until).
3- Forget StatefulWidget! With Get you will never need it again (if you need to use it, you are using Get incorrectly). With the other state managers, you will probably have to use a StatefulWidget to get the instance of your Provider, BLoC, MobX Controller, etc. But have you ever stopped to think that your appBar, your scaffold, and most of the widgets that are in your class are stateless? So why save the state of an entire class, if you can only save the state of the Widget that is stateful? Get solves that, too. Create a Stateless class, make everything stateless. If you need to update a single component, wrap it with GetBuilder, and its state will be maintained.
... ... @@ -329,7 +347,7 @@ FloatingActionButton(
```
When you press FloatingActionButton, all widgets that are listening to the 'counter' variable will be updated automatically.
##### No StatefulWidget:
#### No StatefulWidget:
Using StatefulWidgets means storing the state of entire screens unnecessarily. With Get the use of StatefulWidget is optional. Avoid them and save your users' RAM.
If you need to call initState() or dispose() method, you can call them directly from GetBuilder();
... ... @@ -434,8 +452,6 @@ You can also impose conditions for the update:
```
update(this,['text'], counter < 10);
Why use the update method and why don't we use ChangeNotifier?
## Reactive State Manager
... ... @@ -537,6 +553,7 @@ Camila
23
24
25
```
## Simple Instance Manager
... ... @@ -805,7 +822,7 @@ Get.config(
### Other Advanced APIs and Manual configurations
GetMaterialApp configures everything for you, but if you are using any package like Modular, you may want to configure Get Manually using advanced APIs.
GetMaterialApp configures everything for you, but if you want to configure Get Manually using advanced APIs.
```dart
MaterialApp(
... ... @@ -863,6 +880,8 @@ Get.contextOverlay // Gives the context of the snackbar/dialog/bottomsheet in th
Get made Flutter's nested navigation even easier.
You don't need the context, and you will find your navigation stack by Id.
- NOTE: Creating parallel navigation stacks can be dangerous. The ideal is not to use NestedNavigators, or to use sparingly. If your project requires it, go ahead, but keep in mind that keeping multiple navigation stacks in memory may not be a good idea for RAM consumption.
See how simple it is:
```dart
Navigator(
... ...
... ... @@ -42,18 +42,6 @@ class Get {
GlobalKey<NavigatorState> _key;
static GlobalKey<NavigatorState> addKey(GlobalKey<NavigatorState> newKey) {
_get._key = newKey;
return _get._key;
}
static GlobalKey<NavigatorState> get key {
if (_get._key == null) {
_get._key = GlobalKey<NavigatorState>();
}
return _get._key;
}
/// It replaces Navigator.push, but needs no context, and it doesn't have the Navigator.push
/// routes rebuild bug present in Flutter. If for some strange reason you want the default behavior
/// of rebuilding every app after a route, use opaque = true as the parameter.
... ... @@ -268,6 +256,8 @@ class Get {
VoidCallback onConfirm,
VoidCallback onCancel,
VoidCallback onCustom,
Color cancelTextColor,
Color confirmTextColor,
String textConfirm,
String textCancel,
String textCustom,
... ... @@ -295,7 +285,10 @@ class Get {
Get.back();
},
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 8),
child: Text(textCancel ?? "Cancel"),
child: Text(
textCancel ?? "Cancel",
style: TextStyle(color: cancelTextColor ?? theme.accentColor),
),
shape: RoundedRectangleBorder(
side: BorderSide(
color: buttonColor ?? Get.theme.accentColor,
... ... @@ -314,7 +307,10 @@ class Get {
color: buttonColor ?? Get.theme.accentColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100)),
child: Text(textConfirm ?? "Ok"),
child: Text(
textConfirm ?? "Ok",
style: TextStyle(color: confirmTextColor ?? theme.primaryColor),
),
onPressed: () {
onConfirm?.call();
}));
... ... @@ -607,6 +603,19 @@ class Get {
_get._getController.restartApp();
}
static GlobalKey<NavigatorState> addKey(GlobalKey<NavigatorState> newKey) {
Get()._key = newKey;
return Get()._key;
}
static GlobalKey<NavigatorState> get key {
// _get start empty, is mandatory key be static to prevent errors like "key was called null"
if (Get()._key == null) {
Get()._key = GlobalKey<NavigatorState>();
}
return Get()._key;
}
Map<int, GlobalKey<NavigatorState>> _keys = {};
static GlobalKey<NavigatorState> nestedKey(int key) {
... ... @@ -678,7 +687,7 @@ class Get {
}
/// Find a instance from required class
static S find<S>({String name}) {
static S find<S>({String name, _FcBuilderFunc<S> instance}) {
if (Get.isRegistred<S>()) {
String key = _getKey(S, name);
_FcBuilder builder = Get()._singl[key];
... ... @@ -701,6 +710,30 @@ class Get {
}
}
static S findInstance<S>(_FcBuilderFunc<S> instance, {String name}) {
if (Get()._singl.containsKey(_getKey(instance.call().runtimeType, name))) {
String key = _getKey(instance.call().runtimeType, name);
_FcBuilder builder = Get()._singl[key];
if (builder == null) {
if (name == null) {
throw "class ${S.toString()} is not register";
} else {
throw "class ${S.toString()} with name '$name' is not register";
}
}
return Get()._singl[key].getSependency();
} else {
if (!Get()._factory.containsKey(instance.call().runtimeType))
throw " $S not found. You need call Get.put<$S>($S()) before";
if (isLogEnable) print('[GET] $S instance was created at that time');
S _value =
Get.put<S>(Get()._factory[instance.call().runtimeType].call() as S);
Get()._factory.remove(instance.call().runtimeType);
return _value;
}
}
/// Remove dependency of [S] on dependency abstraction. For concrete class use Get.delete
static void remove<S>({String name}) {
String key = _getKey(S, name);
... ... @@ -753,15 +786,15 @@ class Get {
Map<String, String> _parameters = {};
Get.setParameter(Map<String, String> param) {
_get._parameters = param;
_parameters = param;
}
Get.setRouting(Routing rt) {
_get._routing = rt;
_routing = rt;
}
Get.setSettings(RouteSettings settings) {
_get._settings = settings;
_settings = settings;
}
/// give current arguments
... ...
... ... @@ -5,7 +5,6 @@ import 'package:get/src/routes/utils/parse_arguments.dart';
import 'root_controller.dart';
class GetMaterialApp extends StatelessWidget {
const GetMaterialApp({
Key key,
this.navigatorKey,
... ...
... ... @@ -31,7 +31,7 @@ class _GetXState<T extends RxController> extends State<GetX<T>> {
T controller;
_GetXState() {
_observer = Rx();
_observer = ListX();
}
@override
... ... @@ -60,15 +60,23 @@ class _GetXState<T extends RxController> extends State<GetX<T>> {
@override
void dispose() {
controller?.close();
if (widget.dispose != null) widget.dispose(this);
if (widget.init != null) {
if (widget.autoRemove && Get.isRegistred<T>()) {
controller.onClose();
Get.delete<T>();
}
}
controller.onClose();
_observer.close();
_listenSubscription?.cancel();
_observer?.close();
super.dispose();
}
@override
Widget build(BuildContext context) {
_observer.close();
// _observer.close();
final observer = Get.obs;
Get.obs = this._observer;
final result = widget.builder(controller);
... ...
... ... @@ -145,7 +145,13 @@ class ListX<E> extends DelegatingList<E> implements List<E>, RxInterface<E> {
Map<Stream<Change<E>>, StreamSubscription> _subscriptions = Map();
final _changeCtl = StreamController<Change<E>>();
// StreamSubscription _changectl = StreamSubscription();
StreamController<Change<E>> _changeCtl =
StreamController<Change<E>>.broadcast();
@override
StreamController<Change<E>> subject = StreamController<Change<E>>.broadcast();
/// Adds [item] only if [condition] resolves to true.
void addIf(condition, E item) {
... ... @@ -161,6 +167,9 @@ class ListX<E> extends DelegatingList<E> implements List<E>, RxInterface<E> {
operator []=(int index, E value) {
super[index] = value;
if (Get.obs != null) {
Get.obs.addListener(subject.stream);
}
subject.add(Change<E>.set(item: value, pos: index));
}
... ... @@ -196,6 +205,7 @@ class ListX<E> extends DelegatingList<E> implements List<E>, RxInterface<E> {
}
close() {
clear();
_subscriptions.forEach((observable, subscription) {
subscription.cancel();
});
... ... @@ -219,15 +229,13 @@ class ListX<E> extends DelegatingList<E> implements List<E>, RxInterface<E> {
/// A stream of record of changes to this list
Stream<Change<E>> get onChange {
final now = DateTime.now();
_changeCtl.addStream(_onChange.skipWhile((m) => m.time.isBefore(now)));
_onChange.skipWhile((m) => m.time.isBefore(now));
return _changeCtl.stream.asBroadcastStream();
}
Stream<Change<E>> _onChange;
@override
StreamController<Change<E>> subject = StreamController<Change<E>>();
addListener(Stream<Change<E>> rxGetx) {
if (_subscriptions.containsKey(rxGetx)) {
return;
... ... @@ -238,7 +246,18 @@ class ListX<E> extends DelegatingList<E> implements List<E>, RxInterface<E> {
}
@override
var value;
get value {
if (Get.obs != null) {
Get.obs.addListener(subject.stream);
}
return this;
}
// int get length => (value as List).length;
set value(E val) {
assign(val);
}
@override
Stream<E> get stream => onChange.map((c) => c.item);
... ... @@ -252,7 +271,7 @@ class ListX<E> extends DelegatingList<E> implements List<E>, RxInterface<E> {
void bindStream(Stream<E> stream) => stream.listen((v) => value = v);
@override
void bindOrSet(/* T | Stream<T> | Rx<T> */ other) {
void bindOrSet(/* T | Stream<T> or Rx<T> */ other) {
if (other is RxInterface<E>) {
bind(other);
} else if (other is Stream<E>) {
... ... @@ -267,7 +286,7 @@ class ListX<E> extends DelegatingList<E> implements List<E>, RxInterface<E> {
stream.listen(callback);
@override
void setCast(dynamic /* T */ val) => value = val;
void setCast(dynamic val) => value = val;
}
typedef bool Condition();
... ... @@ -275,12 +294,12 @@ typedef bool Condition();
typedef E ChildrenListComposer<S, E>(S value);
/// An observable list that is bound to another list [binding]
class BoundList<S, E> extends ListX<E> {
class BindingList<S, E> extends ListX<E> {
final ListX<S> binding;
final ChildrenListComposer<S, E> composer;
BoundList(this.binding, this.composer) {
BindingList(this.binding, this.composer) {
for (S v in binding) _add(composer(v));
binding.onChange.listen((Change<S> n) {
if (n.op == ListChangeOp.add) {
... ...
... ... @@ -6,7 +6,7 @@ abstract class RxInterface<T> {
RxInterface([T initial]);
/// Get current value
T get value;
get value;
/// Set value
set value(T val);
... ... @@ -15,7 +15,7 @@ abstract class RxInterface<T> {
void setCast(dynamic /* T */ val);
/// Stream of record of [Change]s of value
Stream<Change<T>> get onChange;
// Stream<Change<T>> get onChange;
/// add listener to stream
addListener(Stream<Change<T>> rxGetx);
... ... @@ -52,10 +52,10 @@ abstract class RxInterface<T> {
class RxController implements DisposableInterface {
void onInit() async {}
void close() async {}
void onClose() async {}
}
abstract class DisposableInterface {
void close() async {}
void onClose() async {}
void onInit() async {}
}
... ...
import 'dart:async';
import 'package:flutter/widgets.dart';
import 'package:get/src/get_main.dart';
import 'rx_impl.dart';
import 'rx_interface.dart';
// import 'dart:async';
// import 'package:flutter/widgets.dart';
// import 'package:get/src/get_main.dart';
// import 'rx_impl.dart';
// import 'rx_interface.dart';
class ListViewX<T extends RxController> extends StatefulWidget {
final Widget Function(T, int) builder;
final bool global;
final ListX Function(T) list;
final bool autoRemove;
final void Function(State state) initState, dispose, didChangeDependencies;
final T init;
final int itemCount;
ListViewX({
this.builder,
this.global = true,
this.autoRemove = true,
this.initState,
@required this.list,
this.itemCount,
this.dispose,
this.didChangeDependencies,
this.init,
});
_ListViewXState<T> createState() => _ListViewXState<T>();
}
// class ListViewX<T extends RxController> extends StatefulWidget {
// final Widget Function(T, int) builder;
// final bool global;
// final ListX Function(T) list;
// final bool autoRemove;
// final void Function(State state) initState, dispose, didChangeDependencies;
// final T init;
// final int itemCount;
// ListViewX({
// this.builder,
// this.global = true,
// this.autoRemove = true,
// this.initState,
// @required this.list,
// this.itemCount,
// this.dispose,
// this.didChangeDependencies,
// this.init,
// });
// _ListViewXState<T> createState() => _ListViewXState<T>();
// }
class _ListViewXState<T extends RxController> extends State<ListViewX<T>> {
RxInterface _observer;
StreamSubscription _listenSubscription;
T controller;
// class _ListViewXState<T extends RxController> extends State<ListViewX<T>> {
// RxInterface _observer;
// StreamSubscription _listenSubscription;
// T controller;
_ListViewXState() {
_observer = ListX();
}
// _ListViewXState() {
// _observer = ListX();
// }
@override
void initState() {
if (widget.global) {
if (Get.isRegistred<T>()) {
controller = Get.find<T>();
} else {
controller = widget.init;
Get.put<T>(controller);
}
} else {
controller = widget.init;
}
if (widget.initState != null) widget.initState(this);
try {
controller?.onInit();
} catch (e) {
if (Get.isLogEnable) print("Failure on call onInit");
}
// @override
// void initState() {
// if (widget.global) {
// if (Get.isRegistred<T>()) {
// controller = Get.find<T>();
// } else {
// controller = widget.init;
// Get.put<T>(controller);
// }
// } else {
// controller = widget.init;
// }
// if (widget.initState != null) widget.initState(this);
// try {
// controller?.onInit();
// } catch (e) {
// if (Get.isLogEnable) print("Failure on call onInit");
// }
_listenSubscription = widget.list.call(controller).listen((data) {
setState(() {});
});
super.initState();
}
// _listenSubscription = widget.list.call(controller).listen((data) {
// setState(() {});
// });
// super.initState();
// }
@override
void dispose() {
controller?.close();
_listenSubscription?.cancel();
_observer?.close();
super.dispose();
}
// @override
// void dispose() {
// controller?.onClose();
// _listenSubscription?.cancel();
// _observer?.close();
// super.dispose();
// }
@override
Widget build(BuildContext context) {
_observer.close();
final observer = Get.obs;
Get.obs = this._observer;
final result = ListView.builder(
itemCount: widget.itemCount ?? widget.list.call(controller).length,
itemBuilder: (context, index) {
return widget.builder(controller, index);
});
Get.obs = observer;
return result;
}
}
// @override
// Widget build(BuildContext context) {
// _observer.close();
// final observer = Get.obs;
// Get.obs = this._observer;
// final result = ListView.builder(
// itemCount: widget.itemCount ?? widget.list.call(controller).length,
// itemBuilder: (context, index) {
// return widget.builder(controller, index);
// });
// Get.obs = observer;
// return result;
// }
// }
... ...
... ... @@ -8,20 +8,22 @@ class RealState {
}
class GetController extends State {
Map<GetController, List<RealState>> _allStates = {};
Map<int, List<RealState>> _allStates = {};
/// Update GetBuilder with update(this)
void update(GetController controller, [List<String> ids]) {
if (controller != null) {
void update(GetController controller,
[List<String> ids, bool condition = true]) {
if (controller == null || !condition) return;
if (ids == null) {
var all = _allStates[controller];
var all = _allStates[controller.hashCode];
all.forEach((rs) {
if (rs.state != null && rs.state.mounted) rs.state.setState(() {});
});
} else {
ids.forEach(
(s) {
var all = _allStates[controller];
var all = _allStates[controller.hashCode];
all.forEach((rs) {
if (rs.state != null && rs.state.mounted && rs.id == s)
rs.state.setState(() {});
... ... @@ -30,9 +32,9 @@ class GetController extends State {
);
}
}
}
void close() {}
void onClose() {}
void onInit() {}
@override
Widget build(_) => throw ("build method can't be called");
... ... @@ -72,31 +74,31 @@ class _GetBuilderState<T extends GetController> extends State<GetBuilder<T>> {
if (widget.global) {
if (Get.isRegistred<T>()) {
controller = Get.find<T>();
if (controller._allStates[controller] == null) {
controller._allStates[controller] = [];
if (controller._allStates[controller.hashCode] == null) {
controller._allStates[controller.hashCode] = [];
}
controller._allStates[controller]
controller._allStates[controller.hashCode]
.add(RealState(state: this, id: widget.id));
} else {
controller = widget.init;
if (controller._allStates[controller] == null) {
controller._allStates[controller] = [];
if (controller._allStates[controller.hashCode] == null) {
controller._allStates[controller.hashCode] = [];
}
controller._allStates[controller]
controller._allStates[controller.hashCode]
.add(RealState(state: this, id: widget.id));
Get.put<T>(controller);
}
} else {
controller = widget.init;
if (controller._allStates[controller] == null) {
controller._allStates[controller] = [];
if (controller._allStates[controller.hashCode] == null) {
controller._allStates[controller.hashCode] = [];
}
controller._allStates[controller]
controller._allStates[controller.hashCode]
.add(RealState(state: this, id: widget.id));
}
if (widget.initState != null) widget.initState(this);
try {
controller?.initState();
controller?.onInit();
} catch (e) {
if (Get.isLogEnable) print("Controller is not attach");
}
... ... @@ -108,25 +110,25 @@ class _GetBuilderState<T extends GetController> extends State<GetBuilder<T>> {
if (widget.init != null) {
var b = controller;
if (b._allStates[controller].hashCode == this.hashCode) {
b._allStates.remove(controller);
if (b._allStates[controller.hashCode].hashCode == this.hashCode) {
b._allStates.remove(controller.hashCode);
}
} else {
var b = controller;
if (b._allStates[controller].hashCode == this.hashCode) {
b._allStates.remove(controller);
if (b._allStates[controller.hashCode].hashCode == this.hashCode) {
b._allStates.remove(controller.hashCode);
}
}
if (widget.dispose != null) widget.dispose(this);
if (widget.init != null) {
if (widget.autoRemove && Get.isRegistred<T>()) {
controller.close();
controller.onClose();
Get.delete<T>();
}
} else {
// controller._allStates[controller].remove(this);
controller._allStates[controller]
controller._allStates[controller.hashCode]
.remove(RealState(state: this, id: widget.id));
}
}
... ... @@ -149,3 +151,5 @@ class _GetBuilderState<T extends GetController> extends State<GetBuilder<T>> {
return widget.builder(controller);
}
}
... ...
name: get
description: Open screens/snackbars/dialogs/bottomSheets without context, manage states and inject dependencies easily with Get.
version: 2.5.0
version: 2.5.2
homepage: https://github.com/jonataslaw/get
environment:
... ...