Jonatas

refactor getview from scratch, reformulate rx variables, add error handler to wo…

…rkers, improve RxList, RxMap and RxSet factorys constructors, fix GetStream addError, refactor instance manager, add patch method to http
class Logger {
// Sample of abstract logging function
static void write(String text, {bool isError = false}) {
print('** $text [$isError]');
Future.microtask(() => print('** $text. isError: [$isError]'));
}
}
... ...
... ... @@ -253,25 +253,6 @@ class GetHttpClient {
));
}
Future<Request<T>> _post<T>(
String url, {
String contentType,
@required dynamic body,
Map<String, dynamic> query,
Decoder<T> decoder,
@required Progress uploadProgress,
}) {
return _requestWithBody<T>(
url,
contentType,
body,
'post',
query,
decoder ?? (defaultDecoder as Decoder<T>),
uploadProgress,
);
}
Future<Request<T>> _request<T>(
String url,
String method, {
... ... @@ -292,25 +273,6 @@ class GetHttpClient {
);
}
Future<Request<T>> _put<T>(
String url, {
String contentType,
@required dynamic body,
@required Map<String, dynamic> query,
Decoder<T> decoder,
@required Progress uploadProgress,
}) {
return _requestWithBody<T>(
url,
contentType,
body,
'put',
query,
decoder ?? (defaultDecoder as Decoder<T>),
uploadProgress,
);
}
Request<T> _delete<T>(
String url,
String contentType,
... ... @@ -329,6 +291,40 @@ class GetHttpClient {
);
}
Future<Response<T>> patch<T>(
String url, {
dynamic body,
String contentType,
Map<String, String> headers,
Map<String, dynamic> query,
Decoder<T> decoder,
Progress uploadProgress,
// List<MultipartFile> files,
}) async {
try {
var response = await _performRequest<T>(
() => _request<T>(
url,
'patch',
contentType: contentType,
body: body,
query: query,
decoder: decoder,
uploadProgress: uploadProgress,
),
headers: headers,
);
return response;
} on Exception catch (e) {
if (!errorSafety) {
throw GetHttpException(e.toString());
}
return Future.value(Response<T>(
statusText: 'Can not connect to server. Reason: $e',
));
}
}
Future<Response<T>> post<T>(
String url, {
dynamic body,
... ... @@ -341,8 +337,9 @@ class GetHttpClient {
}) async {
try {
var response = await _performRequest<T>(
() => _post<T>(
() => _request<T>(
url,
'post',
contentType: contentType,
body: body,
query: query,
... ... @@ -407,8 +404,9 @@ class GetHttpClient {
}) async {
try {
var response = await _performRequest<T>(
() => _put<T>(
() => _request<T>(
url,
'put',
contentType: contentType,
query: query,
body: body,
... ...
import 'dart:async';
import 'dart:collection';
import '../../get_core/get_core.dart';
import 'package:get/utils.dart';
import 'lifecycle.dart';
... ... @@ -19,7 +20,7 @@ class GetInstance {
/// Holds a reference to every registered callback when using
/// [Get.lazyPut()]
static final Map<String, _Lazy> _factory = {};
// static final Map<String, _Lazy> _factory = {};
/// Holds a reference to [Get.reference] when the Instance was
/// created to manage the memory.
... ... @@ -56,10 +57,14 @@ class GetInstance {
void lazyPut<S>(
InstanceBuilderCallback<S> builder, {
String tag,
bool fenix = false,
bool fenix,
}) {
final key = _getKey(S, tag);
_factory.putIfAbsent(key, () => _Lazy(builder, fenix));
_insert(
isSingleton: true,
name: tag,
permanent: fenix ?? Get.smartManagement == SmartManagement.keepFactory,
builder: builder,
);
}
void injector<S>(
... ... @@ -133,7 +138,11 @@ class GetInstance {
bool permanent = true,
}) {
_insert(
isSingleton: false, name: tag, builder: builder, permanent: permanent);
isSingleton: false,
name: tag,
builder: builder,
permanent: permanent,
);
}
/// Injects the Instance [S] builder into the [_singleton] HashMap.
... ... @@ -240,17 +249,6 @@ class GetInstance {
if (_singl.containsKey(key)) {
return _singl[key].getDependency() as S;
} else {
if (_factory.containsKey(key)) {
final _value = put<S>((_factory[key].builder() as S), tag: tag);
if (Get.smartManagement != SmartManagement.keepFactory) {
if (!_factory[key].fenix) {
_factory.remove(key);
}
}
return _value;
}
return GetInstance().put(dep(), tag: tag);
}
}
... ... @@ -277,21 +275,8 @@ class GetInstance {
final i = _initDependencies<S>(name: tag);
return i ?? _singl[key].getDependency() as S;
} else {
if (!_factory.containsKey(key)) {
// ignore: lines_longer_than_80_chars
throw '"$S" not found. You need to call "Get.put($S())" or "Get.lazyPut(()=>$S())"';
}
Get.log('Lazy instance "$S" created');
final _value = put<S>(_factory[key].builder() as S, tag: tag);
_initDependencies<S>(name: tag);
if (Get.smartManagement != SmartManagement.keepFactory &&
!_factory[key].fenix) {
_factory.remove(key);
}
return _value;
// ignore: lines_longer_than_80_chars
throw '"$S" not found. You need to call "Get.put($S())" or "Get.lazyPut(()=>$S())"';
}
}
... ... @@ -308,7 +293,7 @@ class GetInstance {
/// [clearRouteBindings] clears Instances associated with routes.
///
bool reset({bool clearFactory = true, bool clearRouteBindings = true}) {
if (clearFactory) _factory.clear();
// if (clearFactory) _factory.clear();
if (clearRouteBindings) _routesKey.clear();
_singl.clear();
return true;
... ... @@ -330,13 +315,13 @@ class GetInstance {
/// - [key] For internal usage, is the processed key used to register
/// the Instance. **don't use** it unless you know what you are doing.
/// - [force] Will delete an Instance even if marked as [permanent].
bool delete<S>({String tag, String key, bool force = false}) {
Future<bool> delete<S>({String tag, String key, bool force = false}) {
// return _queue.secure<bool>(() {
return _delete<S>(tag: tag, key: key, force: force);
// });
}
bool _delete<S>({String tag, String key, bool force = false}) {
Future<bool> _delete<S>({String tag, String key, bool force = false}) async {
final newKey = key ?? _getKey(S, tag);
if (!_singl.containsKey(newKey)) {
... ... @@ -358,18 +343,20 @@ class GetInstance {
if (i is GetxServiceMixin && !force) {
return false;
}
if (i is GetLifeCycle) {
i.onDelete();
Get.log('"$newKey" onClose() called');
}
await Get.asap(() {
if (i is GetLifeCycle) {
i.onDelete();
Get.log('"$newKey" onClose() called');
}
_singl.removeWhere((oldKey, value) => (oldKey == newKey));
if (_singl.containsKey(newKey)) {
Get.log('Error removing object "$newKey"', isError: true);
} else {
Get.log('"$newKey" deleted from memory');
}
// _routesKey?.remove(key);
_singl.remove(newKey);
if (_singl.containsKey(newKey)) {
Get.log('Error removing object "$newKey"', isError: true);
} else {
Get.log('"$newKey" deleted from memory');
}
});
return true;
}
... ... @@ -380,7 +367,20 @@ class GetInstance {
/// Checks if a lazy factory callback ([Get.lazyPut()] that returns an
/// Instance<[S]> is registered in memory.
/// - [tag] is optional, if you used a [tag] to register the lazy Instance.
bool isPrepared<S>({String tag}) => _factory.containsKey(_getKey(S, tag));
bool isPrepared<S>({String tag}) {
final newKey = _getKey(S, tag);
if (!_singl.containsKey(newKey)) {
Get.log('Instance "$newKey" not found.', isError: true);
return false;
}
final builder = _singl[newKey];
if (!builder.isInit) {
return true;
}
return false;
}
}
typedef InstanceBuilderCallback<S> = S Function();
... ... @@ -420,13 +420,3 @@ class _InstanceBuilderFactory<S> {
return isSingleton ? dependency ??= builderFunc() : builderFunc();
}
}
/// Internal class to register a future instance with [lazyPut],
/// keeps a reference to the callback to be called.
class _Lazy {
bool fenix;
bool permanent = false;
InstanceBuilderCallback builder;
_Lazy(this.builder, this.fenix);
}
... ...
... ... @@ -384,14 +384,14 @@ class GetPageRoute<T> extends PageRoute<T> {
@override
void dispose() {
super.dispose();
// if (Get.smartManagement != SmartManagement.onlyBuilder) {
// WidgetsBinding.instance.addPostFrameCallback((_) => GetInstance()
// .removeDependencyByRoute("${settings?.name ?? routeName}"));
// }
super.dispose();
if (Get.smartManagement != SmartManagement.onlyBuilder) {
WidgetsBinding.instance.addPostFrameCallback(
(_) => GetInstance().removeDependencyByRoute("$reference"));
GetInstance().removeDependencyByRoute("$reference");
}
final middlewareRunner = MiddlewareRunner(middlewares);
... ...
... ... @@ -56,7 +56,12 @@ class GetStream<T> {
var itemsToRemove = <LightSubscription<T>>[];
for (final item in _onData) {
if (!item.isPaused) {
item._onError?.call(error, stackTrace);
if (stackTrace != null) {
item._onError?.call(error, stackTrace);
} else {
item._onError?.call(error);
}
if (item.cancelOnError) {
//item.cancel?.call();
itemsToRemove.add(item);
... ... @@ -147,7 +152,7 @@ class LightSubscription<T> extends StreamSubscription<T> {
OnData<T> _data;
dynamic _onError;
Function _onError;
Callback _onDone;
... ...
... ... @@ -166,6 +166,10 @@ abstract class _RxImpl<T> extends RxNotifier<T> with RxObjectMixin<T> {
_value = initial;
}
void addError(Object error, [StackTrace stackTrace]) {
subject.addError(error, stackTrace);
}
Stream<R> map<R>(R mapper(T data)) => stream.map(mapper);
/// Uses a callback to update [value] internally, similar to [refresh],
... ... @@ -198,6 +202,10 @@ abstract class _RxImpl<T> extends RxNotifier<T> with RxObjectMixin<T> {
class RxBool extends _RxImpl<bool> {
RxBool([bool initial]) : super(initial);
bool get isTrue => value;
bool get isfalse => !isTrue;
bool operator &(bool other) => other && value;
bool operator |(bool other) => other || value;
... ... @@ -221,10 +229,134 @@ class RxBool extends _RxImpl<bool> {
}
/// Rx class for `String` Type.
class RxString extends _RxImpl<String> {
class RxString extends _RxImpl<String> implements Comparable<String>, Pattern {
RxString([String initial]) : super(initial);
String operator +(String val) => _value + val;
/// Compares this string to [other].
@override
int compareTo(String other) {
return value.compareTo(other);
}
/// Returns true if this string ends with [other]. For example:
///
/// 'Dart'.endsWith('t'); // true
bool endsWith(String other) {
return value.endsWith(other);
}
/// Returns true if this string starts with a match of [pattern].
bool startsWith(Pattern pattern, [int index = 0]) {
return value.startsWith(pattern, index);
}
/// Returns the position of the first match of [pattern] in this string
int indexOf(Pattern pattern, [int start = 0]) {
return value.indexOf(pattern, start);
}
/// Returns the starting position of the last match [pattern] in this string,
/// searching backward starting at [start], inclusive:
int lastIndexOf(Pattern pattern, [int start]) {
return value.lastIndexOf(pattern, start);
}
/// Returns true if this string is empty.
bool get isEmpty => value.isEmpty;
/// Returns true if this string is not empty.
bool get isNotEmpty => !isEmpty;
/// Returns the substring of this string that extends from [startIndex],
/// inclusive, to [endIndex], exclusive
String substring(int startIndex, [int endIndex]) {
return value.substring(startIndex, endIndex);
}
/// Returns the string without any leading and trailing whitespace.
String trim() {
return value.trim();
}
/// Returns the string without any leading whitespace.
///
/// As [trim], but only removes leading whitespace.
String trimLeft() {
return value.trimLeft();
}
/// Returns the string without any trailing whitespace.
///
/// As [trim], but only removes trailing whitespace.
String trimRight() {
return value.trimRight();
}
/// Pads this string on the left if it is shorter than [width].
///
/// Return a new string that prepends [padding] onto this string
/// one time for each position the length is less than [width].
String padLeft(int width, [String padding = ' ']) {
return value.padLeft(width, padding);
}
/// Pads this string on the right if it is shorter than [width].
/// Return a new string that appends [padding] after this string
/// one time for each position the length is less than [width].
String padRight(int width, [String padding = ' ']) {
return value.padRight(width, padding);
}
/// Returns true if this string contains a match of [other]:
bool contains(Pattern other, [int startIndex = 0]) {
return value.contains(other, startIndex);
}
/// Replaces all substrings that match [from] with [replace].
String replaceAll(Pattern from, String replace) {
return value.replaceAll(from, replace);
}
/// Splits the string at matches of [pattern] and returns a list
/// of substrings.
List<String> split(Pattern pattern) {
return value.split(pattern);
}
/// Returns an unmodifiable list of the UTF-16 code units of this string.
List<int> get codeUnits => value.codeUnits;
/// Returns an [Iterable] of Unicode code-points of this string.
///
/// If the string contains surrogate pairs, they are combined and returned
/// as one integer by this iterator. Unmatched surrogate halves are treated
/// like valid 16-bit code-units.
Runes get runes => value.runes;
/// Converts all characters in this string to lower case.
/// If the string is already in all lower case, this method returns `this`.
String toLowerCase() {
return value.toLowerCase();
}
/// Converts all characters in this string to upper case.
/// If the string is already in all upper case, this method returns `this`.
String toUpperCase() {
return value.toUpperCase();
}
@override
Iterable<Match> allMatches(String string, [int start = 0]) {
return value.allMatches(string, start);
}
@override
Match matchAsPrefix(String string, [int start = 0]) {
return value.matchAsPrefix(string, start);
}
}
/// Foundation class used for custom `Types` outside the common native Dart
... ...
... ... @@ -10,6 +10,35 @@ class RxList<E> extends ListMixin<E>
}
}
factory RxList.filled(int length, E fill, {bool growable = false}) {
return RxList(List.filled(length, fill, growable: growable));
}
factory RxList.empty({bool growable = false}) {
return RxList(List.empty(growable: growable));
}
/// Creates a list containing all [elements].
factory RxList.from(Iterable elements, {bool growable = true}) {
return RxList(List.from(elements, growable: growable));
}
/// Creates a list from [elements].
factory RxList.of(Iterable<E> elements, {bool growable = true}) {
return RxList(List.of(elements, growable: growable));
}
/// Generates a list of values.
factory RxList.generate(int length, E generator(int index),
{bool growable = true}) {
return RxList(List.generate(length, generator, growable: growable));
}
/// Creates an unmodifiable list containing all [elements].
factory RxList.unmodifiable(Iterable elements) {
return RxList(List.unmodifiable(elements));
}
@override
Iterator<E> get iterator => value.iterator;
... ... @@ -136,10 +165,6 @@ class RxList<E> extends ListMixin<E>
extension ListExtension<E> on List<E> {
RxList<E> get obs {
if (this != null) {
return RxList<E>(this);
} else {
return RxList<E>(null);
}
return RxList<E>(this);
}
}
... ...
... ... @@ -9,6 +9,25 @@ class RxMap<K, V> extends MapMixin<K, V>
}
}
factory RxMap.from(Map<K, V> other) {
return RxMap(Map.from(other));
}
/// Creates a [LinkedHashMap] with the same keys and values as [other].
factory RxMap.of(Map<K, V> other) {
return RxMap(Map.of(other));
}
///Creates an unmodifiable hash based map containing the entries of [other].
factory RxMap.unmodifiable(Map<dynamic, dynamic> other) {
return RxMap(Map.unmodifiable(other));
}
/// Creates an identity map with the default implementation, [LinkedHashMap].
factory RxMap.identity() {
return RxMap(Map.identity());
}
@override
V operator [](Object key) {
return value[key];
... ...
... ... @@ -43,11 +43,22 @@ typedef WorkerCallback<T> = Function(T callback);
/// void increment() => count + 1;
/// }
/// ```
Worker ever<T>(RxInterface<T> listener, WorkerCallback<T> callback,
{dynamic condition = true}) {
StreamSubscription sub = listener.listen((event) {
if (_conditional(condition)) callback(event);
});
Worker ever<T>(
RxInterface<T> listener,
WorkerCallback<T> callback, {
dynamic condition = true,
Function onError,
void Function() onDone,
bool cancelOnError,
}) {
StreamSubscription sub = listener.listen(
(event) {
if (_conditional(condition)) callback(event);
},
onError: onError,
onDone: onDone,
cancelOnError: cancelOnError,
);
return Worker(sub.cancel, '[ever]');
}
... ... @@ -55,13 +66,24 @@ Worker ever<T>(RxInterface<T> listener, WorkerCallback<T> callback,
/// for the [callback] is common to all [listeners],
/// and the [callback] is executed to each one of them. The [Worker] is
/// common to all, so [worker.dispose()] will cancel all streams.
Worker everAll(List<RxInterface> listeners, WorkerCallback callback,
{dynamic condition = true}) {
Worker everAll(
List<RxInterface> listeners,
WorkerCallback callback, {
dynamic condition = true,
Function onError,
void Function() onDone,
bool cancelOnError,
}) {
final evers = <StreamSubscription>[];
for (var i in listeners) {
final sub = i.listen((event) {
if (_conditional(condition)) callback(event);
});
final sub = i.listen(
(event) {
if (_conditional(condition)) callback(event);
},
onError: onError,
onDone: onDone,
cancelOnError: cancelOnError,
);
evers.add(sub);
}
... ... @@ -96,17 +118,28 @@ Worker everAll(List<RxInterface> listeners, WorkerCallback callback,
/// void increment() => count + 1;
/// }
///```
Worker once<T>(RxInterface<T> listener, WorkerCallback<T> callback,
{dynamic condition}) {
Worker once<T>(
RxInterface<T> listener,
WorkerCallback<T> callback, {
dynamic condition = true,
Function onError,
void Function() onDone,
bool cancelOnError,
}) {
Worker ref;
StreamSubscription sub;
sub = listener.listen((event) {
if (!_conditional(condition)) return;
ref._disposed = true;
ref._log('called');
sub?.cancel();
callback(event);
});
sub = listener.listen(
(event) {
if (!_conditional(condition)) return;
ref._disposed = true;
ref._log('called');
sub?.cancel();
callback(event);
},
onError: onError,
onDone: onDone,
cancelOnError: cancelOnError,
);
ref = Worker(sub.cancel, '[once]');
return ref;
}
... ... @@ -128,17 +161,29 @@ Worker once<T>(RxInterface<T> listener, WorkerCallback<T> callback,
/// condition: () => count < 20,
/// );
/// ```
Worker interval<T>(RxInterface<T> listener, WorkerCallback<T> callback,
{Duration time = const Duration(seconds: 1), dynamic condition = true}) {
Worker interval<T>(
RxInterface<T> listener,
WorkerCallback<T> callback, {
Duration time = const Duration(seconds: 1),
dynamic condition = true,
Function onError,
void Function() onDone,
bool cancelOnError,
}) {
var debounceActive = false;
time ??= const Duration(seconds: 1);
StreamSubscription sub = listener.listen((event) async {
if (debounceActive || !_conditional(condition)) return;
debounceActive = true;
await Future.delayed(time);
debounceActive = false;
callback(event);
});
StreamSubscription sub = listener.listen(
(event) async {
if (debounceActive || !_conditional(condition)) return;
debounceActive = true;
await Future.delayed(time);
debounceActive = false;
callback(event);
},
onError: onError,
onDone: onDone,
cancelOnError: cancelOnError,
);
return Worker(sub.cancel, '[interval]');
}
... ... @@ -161,15 +206,26 @@ Worker interval<T>(RxInterface<T> listener, WorkerCallback<T> callback,
/// );
/// }
/// ```
Worker debounce<T>(RxInterface<T> listener, WorkerCallback<T> callback,
{Duration time}) {
Worker debounce<T>(
RxInterface<T> listener,
WorkerCallback<T> callback, {
Duration time,
Function onError,
void Function() onDone,
bool cancelOnError,
}) {
final _debouncer =
Debouncer(delay: time ?? const Duration(milliseconds: 800));
StreamSubscription sub = listener.listen((event) {
_debouncer(() {
callback(event);
});
});
StreamSubscription sub = listener.listen(
(event) {
_debouncer(() {
callback(event);
});
},
onError: onError,
onDone: onDone,
cancelOnError: cancelOnError,
);
return Worker(sub.cancel, '[debounce]');
}
... ... @@ -183,6 +239,8 @@ class Worker {
final String type;
bool _disposed = false;
bool get disposed => _disposed;
//final bool _verbose = true;
void _log(String msg) {
// if (!_verbose) return;
... ...
... ... @@ -53,18 +53,17 @@ class GetXState<T extends DisposableInterface> extends State<GetX<T>> {
@override
void initState() {
var isPrepared = GetInstance().isPrepared<T>(tag: widget.tag);
// var isPrepared = GetInstance().isPrepared<T>(tag: widget.tag);
var isRegistered = GetInstance().isRegistered<T>(tag: widget.tag);
if (widget.global) {
if (isPrepared) {
if (Get.smartManagement != SmartManagement.keepFactory) {
if (isRegistered) {
if (GetInstance().isPrepared<T>(tag: widget.tag)) {
isCreator = true;
} else {
isCreator = false;
}
controller = GetInstance().find<T>(tag: widget.tag);
} else if (isRegistered) {
controller = GetInstance().find<T>(tag: widget.tag);
isCreator = false;
} else {
controller = widget.init;
isCreator = true;
... ... @@ -75,7 +74,7 @@ class GetXState<T extends DisposableInterface> extends State<GetX<T>> {
isCreator = true;
controller?.onStart();
}
if (widget.initState != null) widget.initState(this);
widget.initState?.call(this);
if (widget.global && Get.smartManagement == SmartManagement.onlyBuilder) {
controller?.onStart();
}
... ...
... ... @@ -29,10 +29,16 @@ class _ObxState extends State<ObxWidget> {
@override
void initState() {
subs = _observer.listen((data) => setState(() {}));
subs = _observer.listen(_updateTree);
super.initState();
}
void _updateTree(_) {
if (mounted) {
setState(() {});
}
}
@override
void dispose() {
subs.cancel();
... ...
import 'package:flutter/material.dart';
import '../../../get_core/get_core.dart';
import '../../../get_instance/src/get_instance.dart';
import '../../get_state_manager.dart';
import 'list_notifier.dart';
... ... @@ -89,19 +88,18 @@ class _GetBuilderState<T extends GetxController> extends State<GetBuilder<T>>
void initState() {
super.initState();
if (widget.initState != null) widget.initState(this);
if (widget.global) {
final isPrepared = GetInstance().isPrepared<T>(tag: widget.tag);
final isRegistered = GetInstance().isRegistered<T>(tag: widget.tag);
widget.initState?.call(this);
var isRegistered = GetInstance().isRegistered<T>(tag: widget.tag);
if (isPrepared) {
if (Get.smartManagement != SmartManagement.keepFactory) {
if (widget.global) {
if (isRegistered) {
if (GetInstance().isPrepared<T>(tag: widget.tag)) {
isCreator = true;
} else {
isCreator = false;
}
controller = GetInstance().find<T>(tag: widget.tag);
} else if (isRegistered) {
controller = GetInstance().find<T>(tag: widget.tag);
isCreator = false;
} else {
controller = widget.init;
isCreator = true;
... ... @@ -160,36 +158,3 @@ class _GetBuilderState<T extends GetxController> extends State<GetBuilder<T>>
@override
Widget build(BuildContext context) => widget.builder(controller);
}
/// It's Experimental class, the Api can be change
abstract class GetState<T> extends GetxController {
GetState(T initialValue) {
_state = initialValue;
}
// StreamController<T> _subject;
// @override
// void onClose() {
// _subject?.close();
// }
// Stream<T> get stream {
// if (_subject == null) {
// _subject = StreamController<T>.broadcast();
// }
// return _subject.stream;
// }
T _state;
T get state => _state;
@protected
void change(T newState) {
if (newState != _state) {
_state = newState;
update();
}
}
}
... ...
import 'package:flutter/widgets.dart';
import '../../../get_instance/src/get_instance.dart';
import '../../../instance_manager.dart';
import '../../../utils.dart';
import 'get_widget_cache.dart';
/// GetView is a great way of quickly access your Controller
... ... @@ -40,25 +41,6 @@ abstract class GetView<T> extends StatelessWidget {
Widget build(BuildContext context);
}
// abstract class GetView<A, B> extends StatelessWidget {
// const GetView({Key key}) : super(key: key);
// A get controller => GetInstance().find();
// B get controller2 => GetInstance().find();
// @override
// Widget build(BuildContext context);
// }
// abstract class GetView2<A, B, C> extends StatelessWidget {
// const GetView2({Key key}) : super(key: key);
// A get controller => GetInstance().find();
// B get controller2 => GetInstance().find();
// C get controller3 => GetInstance().find();
// @override
// Widget build(BuildContext context);
// }
/// GetWidget is a great way of quickly access your individual Controller
/// without having to call Get.find<AwesomeController>() yourself.
/// Get save you controller on cache, so, you can to use Get.create() safely
... ... @@ -73,7 +55,9 @@ abstract class GetWidget<S extends GetLifeCycleBase> extends GetWidgetCache {
S get controller => GetWidget._cache[this] as S;
static final _cache = <GetWidget, GetLifeCycleBase>{};
// static final _cache = <GetWidget, GetLifeCycleBase>{};
static final _cache = Expando<GetLifeCycleBase>();
@protected
Widget build(BuildContext context);
... ... @@ -84,8 +68,10 @@ abstract class GetWidget<S extends GetLifeCycleBase> extends GetWidgetCache {
class _GetCache<S extends GetLifeCycleBase> extends WidgetCache<GetWidget<S>> {
S _controller;
bool _isCreator = false;
@override
void onInit() {
_isCreator = Get.isPrepared<S>(tag: widget.tag);
_controller = Get.find<S>(tag: widget.tag);
GetWidget._cache[widget] = _controller;
super.onInit();
... ... @@ -93,7 +79,14 @@ class _GetCache<S extends GetLifeCycleBase> extends WidgetCache<GetWidget<S>> {
@override
void onClose() {
GetWidget._cache.remove(widget);
if (_isCreator) {
Get.asap(() {
widget.controller.onDelete();
Get.log('"${widget.controller.runtimeType}" onClose() called');
Get.log('"${widget.controller.runtimeType}" deleted from memory');
GetWidget._cache[widget] = null;
});
}
super.onClose();
}
... ...
import '../get_utils/get_utils.dart';
extension GetDynamicUtils on dynamic {
extension GetDynamicUtils<T> on T {
@Deprecated('isNull is deprecated and cannot be used, use "==" operator')
bool get isNull => GetUtils.isNull(this);
... ...
... ... @@ -103,12 +103,13 @@ void main() {
tearDownAll(Get.reset);
test('Get.put test with init check', () async {
final instance = Get.put<DisposableController>(DisposableController());
final instance = Get.put(DisposableController());
expect(instance, Get.find<DisposableController>());
expect(instance.initialized, true);
});
test('Get.delete test with disposable controller', () async {
// Get.put(DisposableController());
expect(await Get.delete<DisposableController>(), true);
expect(() => Get.find<DisposableController>(),
throwsA(m.TypeMatcher<String>()));
... ...