Jonatas

update to 3.16.2

## [3.16.2]
- Clean RxList, RxMap and RxSet implementation
- Now when declaring an `RxList()`, it will be started empty. If you want to start a null RxList, you must use `RxList(null)`.
Improved GetStream to receive the same parameters as the StreamController, such as `onListen`, `onPause`, `onResume` and `onCancel`.
- Improve docs
## [3.16.1]
- Fix compilation error on master
... ... @@ -6,7 +12,7 @@
- Added error message callback for StateMixin (@eduardoflorence)
- Fix incorrect Get.reference when pop route (@4mb1t)
- Added Uppercase/Capital letter on GetUtils (@AleFachini)
- Redraw the Streams api to use GetStream instead of StreamControllers. Why this change? GetStream is as light as a ValueNotifier, has very low latency and low consumption of RAM and CPU. There are cases where the performance gain exceeds 9000%, making Get unique when it comes to low latency and resource savings. We did this because new devices are being equipped with 120hz refresh rate, and to provide an even smoother reconstruction of the widgets, it was necessary to create a low latency solution from scratch. GetStream was then created, released in the previous version, and improved in that version. In the previous version, only a small part of GetX used this low-latency API so that it was possible to verify solidly if the api was mature enough to equip state management, which is the most used feature of this library. After two weeks of unremitting tests, we realized that in addition to being fast, the new api is reliable, and will even equip the Stable version of GetServer, which due to the low latency will have performance of low level languages ​​close to C, C ++, Rust and GO.
- Redraw the Streams api to use GetStream instead of StreamControllers. Why this change? GetStream is as light as a ValueNotifier, has very low latency and low consumption of RAM and CPU. The performance difference between Standard Stream and GetStream can exceeds 9000% ([run benchmark by yourself](https://github.com/jonataslaw/getx/blob/master/test/benchmarks/benckmark_test.dart)), making Get unique when it comes to low latency and resource savings. We did this because GetServer needed a low latency solution to optimize the rate of requests, and because today's smartphones are being equipped with increasingly higher refresh rates. There are cell phones today that start at a rate of 120Hz, and the low latency ensures that no frames are lost, ensuring better fluidity. GetStream was then created, released in the previous version, and improved in that version. In the previous version, only a small part of GetX used this low-latency API so that it was possible to verify solidly if the api was mature enough to equip state management, which is the most used feature of this library. After two weeks of unremitting tests, we realized that in addition to being fast, the new api is reliable, and will even equip the Stable version of GetServer, which due to the low latency will have performance of low level languages ​​close to C, C ++, Rust and GO.
## [3.15.0] - Big update
- **Improve Performance**: We made modifications to make GetBuilder even faster. We have improved the structure behind it so that listeners are notified faster. Perhaps in version 4.0 everything will be based on this new structure, but maintaining the power and compatibility with streams. If you want to know how much Getx is faster than pure streams or ChangeNotifier (even after the last update using LinkedList), you can create run the repository tests at: (https://github.com/jonataslaw/getx/blob/master/test/benchmarks/benckmark_test.dart)
... ...
... ... @@ -54,18 +54,22 @@ _Languages: English (this file), [Chinese](README.zh-cn.md), [Brazilian Portugue
- GetX is an extra-light and powerful solution for Flutter. It combines high performance state management, intelligent dependency injection, and route management in a quick and practical way.
- GetX has 3 basic principles, this means that this is the priority for all resources in the library
- GetX has 3 basic principles, this means that this is the priority for all resources in the library: **PRODUCTIVITY, PERFORMANCE AND ORGANIZATION.**
- **PERFORMANCE:** GetX is focused on performance and minimum consumption of resources. Benchmarks are almost always not important in the real world, but if you want, there is a consumption indicator here([benchmarks](https://github.com/jonataslaw/benchmarks)), where GetX does better than other state management approaches, for example. The difference is not large, but it shows our concern not to waste its resources.
- **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
- **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 / blocks 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.
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.
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.
GetX is the easiest, most 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.
- **PERFORMANCE:** GetX is focused on performance and minimum consumption of resources. GetX does not use Streams or ChangeNotifier like other state managers. Why? In addition to building applications for android, iOS, web, linux, macos and linux, with GetX you can build server applications with the same syntax as Flutter/GetX. In order to improve response time and reduce RAM consumption, we created GetValue and GetStream, which are low latency solutions that deliver a lot of performance, at a low operating cost. We use this base to build all of our resources, including state management. Here ([benchmarks](https://github.com/jonataslaw/getx/blob/master/test/benchmarks/benckmark_test.dart)) there is a test that aims to measure the latency time between ChangeNotifier/GetValue and Streams/GetStreams, specifically measuring the time each of these takes to make 30 to 30,000 status updates. By using simple VoidCallbacks instead of buffering for Streams, RAM consumption is also low. In addition, an application using GetX for state management is also generally smaller than using other approaches. You can test this for yourself using this repository ([state manager approachs](https://github.com/jonataslaw/flutter_state_managers)) that has a simple application with the main state managers of Flutter, which had the collaboration of the creators of each lib, however the difference is small (0.1mb), and you shouldn't choose to use GetX just for that, but mainly because of the two other principles:
- **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.
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.
- **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.
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.
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.
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.
- 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. You can compile the benchmark repository, and you will see that using only Get state management, the application compiled with Get has become smaller than all other applications that have only the state management of other packages, because nothing that is not used will be compiled into your code, and each GetX solution was designed to be extra lightweight. The merit here also comes from Flutter's tree shaking which is incredible, and manages to eliminate unused resources like no other framework does.
In case you need it, GetX also has separate packages for each resource, but this is probably not necessary, as GetX alone separates the packages in the single library.
- Getx has a huge ecosystem, capable of running with the same code on Android, iOS, Web, Mac, Linux, Windows, and on your server.
- 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)**.
**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)**.
... ... @@ -160,13 +164,7 @@ Improve your deadlines, deliver everything on time without losing performance. G
## State management
There are currently several state managers for Flutter. However, most of them involve using ChangeNotifier to update widgets and this is a bad and very bad approach to performance of medium or large applications. You can check in the official Flutter documentation that [ChangeNotifier should be used with 1 or a maximum of 2 listeners](https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html), making it practically unusable for any application medium or large.
Get isn't better or worse than any other state manager, but that you should analyze these points as well as the points below to choose between using Get in pure form (Vanilla), or using it in conjunction with another state manager.
Definitely, Get is not the enemy of any other state manager, because Get is a microframework, not just a state manager, and can be used either alone or in conjunction with them.
Get has two different state managers: the simple state manager (we'll call it GetBuilder) and the reactive state manager (who has the package name, GetX)
Get has two different state managers: the simple state manager (we'll call it GetBuilder) and the reactive state manager (GetX/Obx)
### Reactive State Manager
... ... @@ -176,6 +174,7 @@ Reactive programming can alienate many people because it is said to be complicat
- You won't need to create a StreamBuilder for each variable
- You will not need to create a class for each state.
- You will not need to create a get for an initial value.
- You will not need to use code generators
Reactive programming with Get is as easy as using setState.
... ... @@ -349,13 +348,11 @@ Get.updateLocale(locale);
#### System locale
To read the system locale, you could use `window.locale`.
To read the system locale, you could use `Get.deviceLocale`.
```dart
import 'dart:ui' as ui;
return GetMaterialApp(
locale: ui.window.locale,
locale: Get.deviceLocale,
);
```
... ...
- [State Management](#state-management)
- [Reactive State Manager](#reactive-state-manager)
- [Advantages](#advantages)
- [Maximum performance:](#maximum-performance)
- [Declaring a reactive variable](#declaring-a-reactive-variable)
- [Having a reactive state, is easy.](#having-a-reactive-state-is-easy)
- [Using the values in the view](#using-the-values-in-the-view)
- [Conditions to rebuild](#conditions-to-rebuild)
- [Where .obs can be used](#where-obs-can-be-used)
... ... @@ -22,15 +24,16 @@
# State Management
There are currently several state managers for Flutter. However, most of them involve using ChangeNotifier to update widgets and this is a bad and very bad approach to performance of medium or large applications. You can check in the official Flutter documentation that [ChangeNotifier should be used with 1 or a maximum of 2 listeners](https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html), making it practically unusable for any application medium or large.
GetX does not use Streams or ChangeNotifier like other state managers. Why? In addition to building applications for android, iOS, web, linux, macos and linux, with GetX you can build server applications with the same syntax as Flutter/GetX. In order to improve response time and reduce RAM consumption, we created GetValue and GetStream, which are low latency solutions that deliver a lot of performance, at a low operating cost. We use this base to build all of our resources, including state management.
Other state managers are good, but have their nuances:
- BLoC is very safe and efficient, but it is very complex for beginners, which has kept people from developing with Flutter.
- MobX is easier than BLoC and reactive, almost perfect, I would say, but you need to use a code generator, that for large applications, reduces productivity, since you will need to drink a lot of coffees until your code is ready again after a `flutter clean` (And this is not MobX's fault, but the codegen which is really slow!).
- Provider uses InheritedWidget to deliver the same listener, as a way of solving the problem reported above with ChangeNotifier, which implies that any access to its ChangeNotifier class must be within the widget tree because of the context to access o Inherited.
Get isn't better or worse than any other state manager, but that you should analyze these points as well as the points below to choose between using Get in pure form (Vanilla), or using it in conjunction with another state manager. Definitely, Get is not the enemy of any other state manager, because Get is a microframework, not just a state manager, and can be used either alone or in conjunction with them.
- _Complexity_: Some state managers are complex and have a lot of boilerplate. With GetX you don't have to define a class for each event, the code is highly clean and clear, and you do a lot more by writing less. Many people have given up on Flutter because of this topic, and they now finally have a stupidly simple solution for managing states.
- _No code generators_: You spend half your development time writing your application logic. Some state managers rely on code generators to have minimally readable code. Changing a variable and having to run build_runner can be unproductive, and often the waiting time after a flutter clean will be long, and you will have to drink a lot of coffee.
With GetX everything is reactive, and nothing depends on code generators, increasing your productivity in all aspects of your development.
- _It does not depend on context_: You probably already needed to send the context of your view to a controller, making the View's coupling with your business logic high. You have probably had to use a dependency for a place that has no context, and had to pass the context through various classes and functions. This just doesn't exist with GetX. You have access to your controllers from within your controllers without any context. You don't need to send the context by parameter for literally nothing.
- _Granular control_: most state managers are based on ChangeNotifier. ChangeNotifier will notify all widgets that depend on it when notifyListeners is called. If you have 40 widgets on one screen, which have a variable of your ChangeNotifier class, when you update one, all of them will be rebuilt.
With GetX, even nested widgets are respected. If you have Obx watching your ListView, and another watching a checkbox inside the ListView, when changing the CheckBox value, only it will be updated, when changing the List value, only the ListView will be updated.
- _It only reconstructs if its variable REALLY changes_: GetX has flow control, that means if you display a Text with 'Paola', if you change the observable variable to 'Paola' again, the widget will not be reconstructed. That's because GetX knows that 'Paola' is already being displayed in Text, and will not do unnecessary reconstructions.
Most (if not all) current state managers will rebuild on the screen.
## Reactive State Manager
... ...
... ... @@ -1046,6 +1046,8 @@ Since version 2.8 it is possible to access the properties
///The window to which this binding is bound.
ui.Window get window => ui.window;
Locale get deviceLocale => window.locale;
///The number of device pixels for each logical pixel.
double get pixelRatio => window.devicePixelRatio;
... ...
... ... @@ -8,58 +8,12 @@ part of rx_stream;
/// to stream. [listen] is a very light StreamSubscription interface.
/// Is possible take the last value with [value] property.
class GetStream<T> {
LightListenable<T> listenable = LightListenable<T>();
void Function() onListen;
void Function() onPause;
void Function() onResume;
FutureOr<void> Function() onCancel;
T _value;
T get value => _value;
void add(T event) {
_value = event;
_checkIfDisposed();
listenable.notifyData(event);
}
void _checkIfDisposed([bool isClosed = false]) {
if (listenable == null) {
throw '''[LightStream] Error:
You cannot ${isClosed ? "close" : "add events to"} a closed stream.''';
}
}
void addError(Object error, [StackTrace stackTrace]) {
_checkIfDisposed();
listenable.notifyError(error, stackTrace);
}
void close() {
_checkIfDisposed(true);
listenable.notifyDone();
listenable.dispose();
listenable = null;
_value = null;
}
int get length => listenable.length;
bool get hasListeners => listenable.hasListeners;
bool get isClosed => listenable == null;
LightSubscription<T> listen(void Function(T event) onData,
{Function onError, void Function() onDone, bool cancelOnError}) {
final subs = LightSubscription<T>(listenable)
..onData(onData)
..onError(onError)
..onDone(onDone);
listenable.addSubscription(subs);
return subs;
}
Stream<T> get stream => GetStreamTransformation(listenable);
}
class LightListenable<T> {
GetStream({this.onListen, this.onPause, this.onResume, this.onCancel});
List<LightSubscription<T>> _onData = <LightSubscription<T>>[];
bool _isBusy = false;
... ... @@ -69,7 +23,7 @@ class LightListenable<T> {
return _onData.remove(subs);
} else {
await Future.delayed(Duration.zero);
return _onData.remove(subs);
return _onData?.remove(subs);
}
}
... ... @@ -86,70 +40,114 @@ class LightListenable<T> {
bool get hasListeners => _onData.isNotEmpty;
void notifyData(T data) {
assert(!isDisposed, 'You cannot add data to a closed stream.');
void _notifyData(T data) {
_isBusy = true;
for (final item in _onData) {
if (item.isPaused) {
break;
if (!item.isPaused) {
item._data?.call(data);
}
item._data?.call(data);
}
_isBusy = false;
}
void notifyError(Object error, [StackTrace stackTrace]) {
assert(!isDisposed, 'You cannot add errors to a closed stream.');
void _notifyError(Object error, [StackTrace stackTrace]) {
assert(!isClosed, 'You cannot add errors to a closed stream.');
_isBusy = true;
var itemsToRemove = <LightSubscription<T>>[];
for (final item in _onData) {
if (item.isPaused) {
break;
}
item._onError?.call(error, stackTrace);
if (item.cancelOnError) {
item.cancel?.call();
item._onDone?.call();
if (!item.isPaused) {
item._onError?.call(error, stackTrace);
if (item.cancelOnError) {
//item.cancel?.call();
itemsToRemove.add(item);
item.pause();
item._onDone?.call();
}
}
}
for (final item in itemsToRemove) {
_onData.remove(item);
}
_isBusy = false;
}
void notifyDone() {
assert(!isDisposed, 'You cannot close a closed stream.');
void _notifyDone() {
assert(!isClosed, 'You cannot close a closed stream.');
_isBusy = true;
for (final item in _onData) {
if (item.isPaused) {
break;
if (!item.isPaused) {
item._onDone?.call();
}
item._onDone?.call();
}
_isBusy = false;
}
void dispose() {
T _value;
T get value => _value;
void add(T event) {
assert(!isClosed, 'You cannot add event to closed Stream');
_value = event;
_notifyData(event);
}
bool get isClosed => _onData == null;
void addError(Object error, [StackTrace stackTrace]) {
assert(!isClosed, 'You cannot add error to closed Stream');
_notifyError(error, stackTrace);
}
void close() {
assert(!isClosed, 'You cannot close a closed Stream');
_notifyDone();
_onData = null;
_isBusy = null;
_value = null;
}
bool get isDisposed => _onData == null;
LightSubscription<T> listen(void Function(T event) onData,
{Function onError, void Function() onDone, bool cancelOnError}) {
final subs = LightSubscription<T>(
removeSubscription,
onPause: onPause,
onResume: onResume,
onCancel: onCancel,
)
..onData(onData)
..onError(onError)
..onDone(onDone)
..cancelOnError = cancelOnError;
addSubscription(subs);
onListen?.call();
return subs;
}
Stream<T> get stream =>
GetStreamTransformation(addSubscription, removeSubscription);
}
class LightSubscription<T> extends StreamSubscription<T> {
final LightListenable<T> listener;
LightSubscription(this.listener);
final RemoveSubscription<T> _removeSubscription;
LightSubscription(this._removeSubscription,
{this.onPause, this.onResume, this.onCancel});
final void Function() onPause;
final void Function() onResume;
final FutureOr<void> Function() onCancel;
bool cancelOnError = false;
@override
Future<void> cancel() {
listener.removeSubscription(this);
_removeSubscription(this);
onCancel?.call();
return Future.value();
}
OnData<T> _data;
Function _onError;
dynamic _onError;
Callback _onDone;
... ... @@ -165,10 +163,16 @@ class LightSubscription<T> extends StreamSubscription<T> {
void onDone(Callback handleDone) => _onDone = handleDone;
@override
void pause([Future<void> resumeSignal]) => _isPaused = true;
void pause([Future<void> resumeSignal]) {
_isPaused = true;
onPause?.call();
}
@override
void resume() => _isPaused = false;
void resume() {
_isPaused = false;
onResume?.call();
}
@override
bool get isPaused => _isPaused;
... ... @@ -178,18 +182,23 @@ class LightSubscription<T> extends StreamSubscription<T> {
}
class GetStreamTransformation<T> extends Stream<T> {
final LightListenable<T> listenable;
GetStreamTransformation(this.listenable);
final AddSubscription<T> _addSubscription;
final RemoveSubscription<T> _removeSubscription;
GetStreamTransformation(this._addSubscription, this._removeSubscription);
@override
LightSubscription<T> listen(void Function(T event) onData,
{Function onError, void Function() onDone, bool cancelOnError}) {
final subs = LightSubscription<T>(listenable)
final subs = LightSubscription<T>(_removeSubscription)
..onData(onData)
..onError(onError)
..onDone(onDone);
listenable.addSubscription(subs);
_addSubscription(subs);
return subs;
}
}
typedef RemoveSubscription<T> = FutureOr<bool> Function(
LightSubscription<T> subs);
typedef AddSubscription<T> = FutureOr<void> Function(LightSubscription<T> subs);
... ...
... ... @@ -110,7 +110,7 @@ mixin RxObjectMixin<T> on NotifyManager<T> {
return _value;
}
Stream<T> get stream => GetStreamTransformation<T>(subject.listenable);
Stream<T> get stream => subject.stream;
/// Binds an existing [Stream<T>] to this Rx<T> to keep the values in sync.
/// You can bind multiple sources to update the value.
... ...
... ... @@ -4,8 +4,10 @@ part of rx_types;
class RxList<E> extends ListMixin<E>
with NotifyManager<List<E>>, RxObjectMixin<List<E>>
implements RxInterface<List<E>> {
RxList([List<E> initial]) {
_value = initial;
RxList([List<E> initial = const []]) {
if (initial != null) {
_value = List.from(initial);
}
}
@override
... ... @@ -130,442 +132,10 @@ class RxList<E> extends ListMixin<E>
}
}
// /// Create a list similar to `List<T>`
// class RxList<E> implements List<E>, RxInterface<List<E>> {
// RxList([List<E> initial]) {
// if (initial != null) _value = initial;
// }
// List<E> _value = <E>[];
// @override
// Iterator<E> get iterator => value.iterator;
// @override
// bool get isEmpty => value.isEmpty;
// bool get canUpdate {
// return _subscriptions.length > 0;
// }
// @override
// bool get isNotEmpty => value.isNotEmpty;
// @override
// StreamController<List<E>> subject = StreamController.broadcast();
// final _subscriptions = HashMap<Stream<List<E>>, StreamSubscription>();
// void operator []=(int index, E val) {
// _value[index] = val;
// refresh();
// }
// void refresh() {
// subject.add(_value);
// }
// /// Special override to push() element(s) in a reactive way
// /// inside the List,
// RxList<E> operator +(Iterable<E> val) {
// addAll(val);
// refresh();
// return this;
// }
// E operator [](int index) {
// return value[index];
// }
// void add(E item) {
// _value.add(item);
// refresh();
// }
// @override
// void addAll(Iterable<E> item) {
// _value.addAll(item);
// refresh();
// }
// /// Add [item] to [List<E>] only if [item] is not null.
// void addNonNull(E item) {
// if (item != null) add(item);
// }
// /// Add [Iterable<E>] to [List<E>] only if [Iterable<E>] is not null.
// void addAllNonNull(Iterable<E> item) {
// if (item != null) addAll(item);
// }
// /// Add [item] to [List<E>] only if [condition] is true.
// void addIf(dynamic condition, E item) {
// if (condition is Condition) condition = condition();
// if (condition is bool && condition) add(item);
// }
// /// Adds [Iterable<E>] to [List<E>] only if [condition] is true.
// void addAllIf(dynamic condition, Iterable<E> items) {
// if (condition is Condition) condition = condition();
// if (condition is bool && condition) addAll(items);
// }
// @override
// void insert(int index, E item) {
// _value.insert(index, item);
// refresh();
// }
// @override
// void insertAll(int index, Iterable<E> iterable) {
// _value.insertAll(index, iterable);
// refresh();
// }
// @override
// int get length => value.length;
// /// Removes an item from the list.
// ///
// /// This is O(N) in the number of items in the list.
// ///
// /// Returns whether the item was present in the list.
// @override
// bool remove(Object item) {
// final hasRemoved = _value.remove(item);
// if (hasRemoved) {
// refresh();
// }
// return hasRemoved;
// }
// @override
// E removeAt(int index) {
// final item = _value.removeAt(index);
// refresh();
// return item;
// }
// @override
// E removeLast() {
// final item = _value.removeLast();
// refresh();
// return item;
// }
// @override
// void removeRange(int start, int end) {
// _value.removeRange(start, end);
// refresh();
// }
// @override
// void removeWhere(bool Function(E) test) {
// _value.removeWhere(test);
// refresh();
// }
// @override
// void clear() {
// _value.clear();
// refresh();
// }
// @override
// void sort([int compare(E a, E b)]) {
// _value.sort(compare);
// refresh();
// }
// @override
// void close() {
// _subscriptions.forEach((observable, subscription) {
// subscription.cancel();
// });
// _subscriptions.clear();
// subject.close();
// }
// /// Replaces all existing items of this list with [item]
// void assign(E item) {
// clear();
// add(item);
// }
// void update(void fn(Iterable<E> value)) {
// fn(value);
// refresh();
// }
// /// Replaces all existing items of this list with [items]
// void assignAll(Iterable<E> items) {
// clear();
// addAll(items);
// }
// @protected
// List<E> get value {
// if (getObs != null) {
// getObs.addListener(subject.stream);
// }
// return _value;
// }
// String get string => value.toString();
// void addListener(Stream<List<E>> rxGetX) {
// if (_subscriptions.containsKey(rxGetX)) {
// return;
// }
// _subscriptions[rxGetX] = rxGetX.listen(subject.add);
// }
// set value(List<E> val) {
// if (_value == val) return;
// _value = val;
// refresh();
// }
// Stream<List<E>> get stream => subject.stream;
// StreamSubscription<List<E>> listen(
// void Function(List<E>) onData, {
// Function onError,
// void Function() onDone,
// bool cancelOnError,
// }) =>
// stream.listen(onData, onError: onError, onDone: onDone);
// /// Binds an existing [Stream<List>] to this [RxList].
// /// You can bind multiple sources to update the value.
// /// Closing the subscription will happen automatically when the observer
// /// Widget ([GetX] or [Obx]) gets unmounted from the Widget tree.
// void bindStream(Stream<List<E>> stream) {
// _subscriptions[stream] = stream.listen((va) => value = va);
// }
// @override
// E get first => value.first;
// @override
// E get last => value.last;
// @override
// bool any(bool Function(E) test) {
// return value.any(test);
// }
// @override
// Map<int, E> asMap() {
// return value.asMap();
// }
// @override
// List<R> cast<R>() {
// return value.cast<R>();
// }
// @override
// bool contains(Object element) {
// return value.contains(element);
// }
// @override
// E elementAt(int index) {
// return value.elementAt(index);
// }
// @override
// bool every(bool Function(E) test) {
// return value.every(test);
// }
// @override
// Iterable<T> expand<T>(Iterable<T> Function(E) f) {
// return value.expand(f);
// }
// @override
// void fillRange(int start, int end, [E fillValue]) {
// _value.fillRange(start, end, fillValue);
// refresh();
// }
// @override
// E firstWhere(bool Function(E) test, {E Function() orElse}) {
// return value.firstWhere(test, orElse: orElse);
// }
// @override
// T fold<T>(T initialValue, T Function(T, E) combine) {
// return value.fold(initialValue, combine);
// }
// @override
// Iterable<E> followedBy(Iterable<E> other) {
// return value.followedBy(other);
// }
// @override
// void forEach(void Function(E) f) {
// value.forEach(f);
// }
// @override
// Iterable<E> getRange(int start, int end) {
// return value.getRange(start, end);
// }
// @override
// int indexOf(E element, [int start = 0]) {
// return value.indexOf(element, start);
// }
// @override
// int indexWhere(bool Function(E) test, [int start = 0]) {
// return value.indexWhere(test, start);
// }
// @override
// String join([String separator = ""]) {
// return value.join(separator);
// }
// @override
// int lastIndexOf(E element, [int start]) {
// return value.lastIndexOf(element, start);
// }
// @override
// int lastIndexWhere(bool Function(E) test, [int start]) {
// return value.lastIndexWhere(test, start);
// }
// @override
// E lastWhere(bool Function(E) test, {E Function() orElse}) {
// return value.lastWhere(test, orElse: orElse);
// }
// @override
// set length(int newLength) {
// _value.length = newLength;
// refresh();
// }
// @override
// Iterable<T> map<T>(T Function(E) f) {
// return value.map(f);
// }
// @override
// E reduce(E Function(E, E) combine) {
// return value.reduce(combine);
// }
// @override
// void replaceRange(int start, int end, Iterable<E> replacement) {
// _value.replaceRange(start, end, replacement);
// refresh();
// }
// @override
// void retainWhere(bool Function(E) test) {
// _value.retainWhere(test);
// refresh();
// }
// @override
// Iterable<E> get reversed => value.reversed;
// @override
// void setAll(int index, Iterable<E> iterable) {
// _value.setAll(index, iterable);
// refresh();
// }
// @override
// void setRange(int start, int end,
// Iterable<E> iterable, [int skipCount = 0],) {
// _value.setRange(start, end, iterable, skipCount);
// refresh();
// }
// @override
// void shuffle([Random random]) {
// _value.shuffle(random);
// refresh();
// }
// @override
// E get single => value.single;
// @override
// E singleWhere(bool Function(E) test, {E Function() orElse}) {
// return value.singleWhere(test, orElse: orElse);
// }
// @override
// Iterable<E> skip(int count) {
// return value.skip(count);
// }
// @override
// Iterable<E> skipWhile(bool Function(E) test) {
// return value.skipWhile(test);
// }
// @override
// List<E> sublist(int start, [int end]) {
// return value.sublist(start, end);
// }
// @override
// Iterable<E> take(int count) {
// return value.take(count);
// }
// @override
// Iterable<E> takeWhile(bool Function(E) test) {
// return value.takeWhile(test);
// }
// @override
// List<E> toList({bool growable = true}) {
// return value.toList(growable: growable);
// }
// @override
// Set<E> toSet() {
// return value.toSet();
// }
// @override
// Iterable<E> where(bool Function(E) test) {
// return value.where(test);
// }
// @override
// Iterable<T> whereType<T>() {
// return value.whereType<T>();
// }
// @override
// set first(E value) {
// _value.first = value;
// refresh();
// }
// @override
// set last(E value) {
// _value.last = value;
// refresh();
// }
// }
extension ListExtension<E> on List<E> {
RxList<E> get obs {
if (this != null) {
return RxList<E>(<E>[])..addAllNonNull(this);
return RxList<E>(this);
} else {
return RxList<E>(null);
}
... ...
... ... @@ -3,8 +3,10 @@ part of rx_types;
class RxMap<K, V> extends MapMixin<K, V>
with NotifyManager<Map<K, V>>, RxObjectMixin<Map<K, V>>
implements RxInterface<Map<K, V>> {
RxMap([Map<K, V> initial]) {
_value = initial;
RxMap([Map<K, V> initial = const {}]) {
if (initial != null) {
_value = Map.from(initial);
}
}
@override
... ...
... ... @@ -3,8 +3,10 @@ part of rx_types;
class RxSet<E> extends SetMixin<E>
with NotifyManager<Set<E>>, RxObjectMixin<Set<E>>
implements RxInterface<Set<E>> {
RxSet([Set<E> initial]) {
if (initial != null) _value = initial;
RxSet([Set<E> initial = const {}]) {
if (initial != null) {
_value = Set.from(initial);
}
}
/// Adds [item] only if [condition] resolves to true.
... ... @@ -139,333 +141,6 @@ class RxSet<E> extends SetMixin<E>
}
}
// class RxSet<E> implements Set<E>, RxInterface<Set<E>> {
// RxSet([Set<E> initial]) {
// if (initial != null) _value = initial;
// }
// Set<E> _value = <E>{};
// @override
// Iterator<E> get iterator => value.iterator;
// @override
// bool get isEmpty => value.isEmpty;
// bool get canUpdate {
// return _subscriptions.length > 0;
// }
// @override
// bool get isNotEmpty => value.isNotEmpty;
// StreamController<Set<E>> subject = StreamController<Set<E>>.broadcast();
// final _subscriptions = HashMap<Stream<Set<E>>, StreamSubscription>();
// /// Adds [item] only if [condition] resolves to true.
// void addIf(dynamic condition, E item) {
// if (condition is Condition) condition = condition();
// if (condition is bool && condition) add(item);
// }
// /// Adds all [items] only if [condition] resolves to true.
// void addAllIf(dynamic condition, Iterable<E> items) {
// if (condition is Condition) condition = condition();
// if (condition is bool && condition) addAll(items);
// }
// void refresh() {
// subject.add(_value);
// }
// /// Special override to push() element(s) in a reactive way
// /// inside the List,
// RxSet<E> operator +(Set<E> val) {
// addAll(val);
// refresh();
// return this;
// }
// @override
// bool add(E value) {
// final val = _value.add(value);
// refresh();
// return val;
// }
// @override
// void addAll(Iterable<E> item) {
// _value.addAll(item);
// refresh();
// }
// /// Adds only if [item] is not null.
// void addNonNull(E item) {
// if (item != null) add(item);
// }
// /// Adds only if [item] is not null.
// void addAllNonNull(Iterable<E> item) {
// if (item != null) addAll(item);
// }
// int get length => value.length;
// /// Removes an item from the list.
// ///
// /// This is O(N) in the number of items in the list.
// ///
// /// Returns whether the item was present in the list.
// bool remove(Object item) {
// var hasRemoved = _value.remove(item);
// if (hasRemoved) {
// refresh();
// }
// return hasRemoved;
// }
// void removeWhere(bool Function(E) test) {
// _value.removeWhere(test);
// refresh();
// }
// void clear() {
// _value.clear();
// refresh();
// }
// void close() {
// _subscriptions.forEach((observable, subscription) {
// subscription.cancel();
// });
// _subscriptions.clear();
// subject.close();
// }
// /// Replaces all existing items of this list with [item]
// void assign(E item) {
// clear();
// add(item);
// }
// void update(void fn(Iterable<E> value)) {
// fn(value);
// refresh();
// }
// /// Replaces all existing items of this list with [items]
// void assignAll(Iterable<E> items) {
// clear();
// addAll(items);
// }
// @protected
// Set<E> get value {
// if (getObs != null) {
// getObs.addListener(subject.stream);
// }
// return _value;
// }
// String get string => value.toString();
// void addListener(Stream<Set<E>> rxGetX) {
// if (_subscriptions.containsKey(rxGetX)) {
// return;
// }
// _subscriptions[rxGetX] = rxGetX.listen((data) {
// subject.add(data);
// });
// }
// set value(Set<E> val) {
// if (_value == val) return;
// _value = val;
// refresh();
// }
// Stream<Set<E>> get stream => subject.stream;
// StreamSubscription<Set<E>> listen(void Function(Set<E>) onData,
// {Function onError, void Function() onDone, bool cancelOnError}) =>
// stream.listen(onData, onError: onError, onDone: onDone);
// /// Binds an existing [Stream<Set>] to this [RxSet].
// /// You can bind multiple sources to update the value.
// /// Closing the subscription will happen automatically when the observer
// /// Widget ([GetX] or [Obx]) gets unmounted from the Widget tree.
// void bindStream(Stream<Set<E>> stream) {
// _subscriptions[stream] = stream.listen((va) => value = va);
// }
// @override
// E get first => value.first;
// @override
// E get last => value.last;
// @override
// bool any(bool Function(E) test) {
// return value.any(test);
// }
// @override
// Set<R> cast<R>() {
// return value.cast<R>();
// }
// @override
// bool contains(Object element) {
// return value.contains(element);
// }
// @override
// E elementAt(int index) {
// return value.elementAt(index);
// }
// @override
// bool every(bool Function(E) test) {
// return value.every(test);
// }
// @override
// Iterable<T> expand<T>(Iterable<T> Function(E) f) {
// return value.expand(f);
// }
// @override
// E firstWhere(bool Function(E) test, {E Function() orElse}) {
// return value.firstWhere(test, orElse: orElse);
// }
// @override
// T fold<T>(T initialValue, T Function(T, E) combine) {
// return value.fold(initialValue, combine);
// }
// @override
// Iterable<E> followedBy(Iterable<E> other) {
// return value.followedBy(other);
// }
// @override
// void forEach(void Function(E) f) {
// value.forEach(f);
// }
// @override
// String join([String separator = ""]) {
// return value.join(separator);
// }
// @override
// E lastWhere(bool Function(E) test, {E Function() orElse}) {
// return value.lastWhere(test, orElse: orElse);
// }
// @override
// Iterable<T> map<T>(T Function(E) f) {
// return value.map(f);
// }
// @override
// E reduce(E Function(E, E) combine) {
// return value.reduce(combine);
// }
// @override
// E get single => value.single;
// @override
// E singleWhere(bool Function(E) test, {E Function() orElse}) {
// return value.singleWhere(test, orElse: orElse);
// }
// @override
// Iterable<E> skip(int count) {
// return value.skip(count);
// }
// @override
// Iterable<E> skipWhile(bool Function(E) test) {
// return value.skipWhile(test);
// }
// @override
// Iterable<E> take(int count) {
// return value.take(count);
// }
// @override
// Iterable<E> takeWhile(bool Function(E) test) {
// return value.takeWhile(test);
// }
// @override
// List<E> toList({bool growable = true}) {
// return value.toList(growable: growable);
// }
// @override
// Set<E> toSet() {
// return value.toSet();
// }
// @override
// Iterable<E> where(bool Function(E) test) {
// return value.where(test);
// }
// @override
// Iterable<T> whereType<T>() {
// return value.whereType<T>();
// }
// @override
// bool containsAll(Iterable<Object> other) {
// return value.containsAll(other);
// }
// @override
// Set<E> difference(Set<Object> other) {
// return value.difference(other);
// }
// @override
// Set<E> intersection(Set<Object> other) {
// return value.intersection(other);
// }
// @override
// E lookup(Object object) {
// return value.lookup(object);
// }
// @override
// void removeAll(Iterable<Object> elements) {
// _value.removeAll(elements);
// refresh();
// }
// @override
// void retainAll(Iterable<Object> elements) {
// _value.retainAll(elements);
// refresh();
// }
// @override
// void retainWhere(bool Function(E) E) {
// _value.retainWhere(E);
// refresh();
// }
// @override
// Set<E> union(Set<E> other) {
// return value.union(other);
// }
// }
extension SetExtension<E> on Set<E> {
RxSet<E> get obs {
if (this != null) {
... ...
name: get
description: Open screens/snackbars/dialogs/bottomSheets without context, manage states and inject dependencies easily with GetX.
version: 3.16.1
version: 3.16.2
homepage: https://github.com/jonataslaw/getx
environment:
... ...
... ... @@ -163,17 +163,23 @@ GetValue is ${calculePercentage(dart, getx).round()}% more fast than Default Val
print('''
GetStream is ${calculePercentage(dart, mini).round()}% more fast than Default Stream with $times listeners''');
print('-----------');
times = 30000;
dart = await stream();
getx = await getStream();
mini = await miniStream();
times = 60000;
dart = await stream();
getx = await getStream();
mini = await miniStream();
print('-----------');
print('dart_stream delay $dart ms to made $times requests');
print('getx_stream delay $getx ms to made $times requests');
print('getx_mini_stream delay $mini ms to made $times requests');
print('-----------');
print('''
GetStream is ${calculePercentage(dart, getx).round()}% more fast than Default Stream with $times listeners''');
GetStream is ${calculePercentage(dart, mini).round()}% more fast than Default Stream with $times listeners''');
});
}
... ...