Jonatas Borges

update to 4.1.2

## [4.1.2]
- Fix warning ˜can add data to a closed stream˜ when GetBuilder and Obx are nested
- Fix get_connect decoder can not be null (@Goddchen)
- Migrate example code (@3lB4rt0)
- Fix initial value of nullables (@RafaRuiz)
- Improve error message to navigation (@maxzod)
- Fix typo on docs (@Rahulshahare)
- Fixed darktheme being changed only through Get.changeTheme and not through the DarkTheme theme property in MaterialApp (@GoldenSoju)
- Fix controller is removed when navigate to same page (@eduardoflorence)
- Fix missing reload() and reloadAll() to Get extensions (@lkloon123)
## [4.1.1]
- default type to non nullables types
- Remove mandatory initialValue to nullables types
## [4.1.0]
- Added Rxn to non nullables reactives types
... ...
... ... @@ -119,7 +119,7 @@ void main() => runApp(GetMaterialApp(home: Home()));
```
- Note: this does not modify the MaterialApp of the Flutter, GetMaterialApp is not a modified MaterialApp, it is just a pre-configured Widget, which has the default MaterialApp as a child. You can configure this manually, but it is definitely not necessary. GetMaterialApp will create routes, inject them, inject translations, inject everything you need for route navigation. If you use Get only for state management or dependency management, it is not necessary to use GetMaterialApp. GetMaterialApp is necessary for routes, snackbars, internationalization, bottomSheets, dialogs, and high-level apis related to routes and absence of context.
- Note²: This step in only necessary if you gonna use route management (`Get.to()`, `Get.back()` and so on). If you not gonna use it then it is not necessary to do step 1
- Note²: This step is only necessary if you gonna use route management (`Get.to()`, `Get.back()` and so on). If you not gonna use it then it is not necessary to do step 1
- Step 2:
Create your business logic class and place all variables, methods and controllers inside it.
... ...
... ... @@ -282,6 +282,7 @@ As the view has only widgets, you can use a view for android, and another for iO
However, some examples like internationalization, Snackbars without context, validators, responsiveness and other Getx resources, were not explored (and it would not even be possible to explore all resources in such a simple example), so below is an example not very complete, but trying demonstrate how to use internationalization, reactive custom classes, reactive lists, snackbars contextless, workers etc.
```dart
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
... ... @@ -397,29 +398,27 @@ class Second extends GetView<ControllerX> {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GetX<ControllerX>(
// Using bindings you don't need of init: method
// Using Getx you can take controller instance of "builder: (_)"
builder: (_) {
Obx(
() {
print("count1 rebuild");
return Text('${_.count1}');
return Text('${controller.count1}');
},
),
GetX<ControllerX>(
builder: (_) {
Obx(
() {
print("count2 rebuild");
return Text('${controller.count2}');
},
),
GetX<ControllerX>(builder: (_) {
Obx(() {
print("sum rebuild");
return Text('${_.sum}');
return Text('${controller.sum}');
}),
GetX<ControllerX>(
builder: (_) => Text('Name: ${controller.user.value.name}'),
Obx(
() => Text('Name: ${controller.user.value?.name}'),
),
GetX<ControllerX>(
builder: (_) => Text('Age: ${_.user.value.age}'),
Obx(
() => Text('Age: ${controller.user.value?.age}'),
),
ElevatedButton(
child: Text("Go to last page"),
... ... @@ -440,25 +439,25 @@ class Second extends GetView<ControllerX> {
ElevatedButton(
child: Text("Increment"),
onPressed: () {
Get.find<ControllerX>().increment();
controller.increment();
},
),
ElevatedButton(
child: Text("Increment"),
onPressed: () {
Get.find<ControllerX>().increment2();
controller.increment2();
},
),
ElevatedButton(
child: Text("Update name"),
onPressed: () {
Get.find<ControllerX>().updateUser();
controller.updateUser();
},
),
ElevatedButton(
child: Text("Dispose worker"),
onPressed: () {
Get.find<ControllerX>().disposeWorker();
controller.disposeWorker();
},
),
],
... ... @@ -509,7 +508,7 @@ class ControllerX extends GetxController {
updateUser() {
user.update((value) {
value.name = 'Jose';
value!.name = 'Jose';
value.age = 30;
});
}
... ... @@ -523,7 +522,7 @@ class ControllerX extends GetxController {
/// Here is an outline of how you can use them:
/// made this if you need cancel you worker
Worker _ever;
late Worker _ever;
@override
onInit() {
... ... @@ -562,8 +561,8 @@ class SizeTransitions extends CustomTransition {
@override
Widget buildTransition(
BuildContext context,
Curve curve,
Alignment alignment,
Curve? curve,
Alignment? alignment,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
... ... @@ -572,7 +571,7 @@ class SizeTransitions extends CustomTransition {
child: SizeTransition(
sizeFactor: CurvedAnimation(
parent: animation,
curve: curve,
curve: curve!,
),
child: child,
),
... ...
... ... @@ -18,7 +18,6 @@ class CountryView extends GetView<HomeController> {
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 15.0, sigmaY: 15.0),
child: Container(
decoration: BoxDecoration(color: Colors.white.withOpacity(0.0)),
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
... ...
... ... @@ -21,7 +21,6 @@ class DetailsView extends StatelessWidget {
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 15.0, sigmaY: 15.0),
child: Container(
decoration: BoxDecoration(color: Colors.white.withOpacity(0.0)),
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
... ...
... ... @@ -249,7 +249,7 @@ class GetHttpClient {
method: 'get',
url: uri,
headers: headers,
decoder: decoder ?? (defaultDecoder as Decoder<T>),
decoder: decoder ?? (defaultDecoder as Decoder<T>?),
contentLength: 0,
));
}
... ...
... ... @@ -107,6 +107,11 @@ extension Inst on GetInterface {
Future<bool> delete<S>({String? tag, bool force = false}) async =>
GetInstance().delete<S>(tag: tag, force: force);
void reloadAll({bool force = false}) => GetInstance().reloadAll(force: force);
void reload<S>({String? tag, String? key, bool force = false}) =>
GetInstance().reload<S>(tag: tag, key: key, force: force);
/// Checks if a Class Instance<[S]> (or [tag]) is registered in memory.
/// - [tag] optional, if you use a [tag] to register the Instance.
bool isRegistered<S>({String? tag}) =>
... ...
... ... @@ -345,7 +345,6 @@ extension ExtensionDialog on GetInterface {
actions.add(TextButton(
style: TextButton.styleFrom(
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
//color: buttonColor ?? theme.accentColor,
backgroundColor: buttonColor ?? theme.accentColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100)),
... ... @@ -364,6 +363,7 @@ extension ExtensionDialog on GetInterface {
Widget baseAlertDialog = AlertDialog(
titlePadding: EdgeInsets.all(8),
contentPadding: EdgeInsets.all(8),
backgroundColor: backgroundColor ?? theme.dialogBackgroundColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(radius))),
... ... @@ -434,8 +434,10 @@ extension ExtensionBottomSheet on GetInterface {
// theme: Theme.of(key.currentContext, shadowThemeOnly: true),
theme: Theme.of(key.currentContext!),
isScrollControlled: isScrollControlled,
barrierLabel: MaterialLocalizations.of(key.currentContext!)
.modalBarrierDismissLabel,
backgroundColor: backgroundColor ?? Colors.transparent,
elevation: elevation,
shape: shape,
... ... @@ -519,6 +521,9 @@ extension GetNavigation on GetInterface {
Using a widget function instead of a widget fully guarantees that the widget and its controllers will be removed from memory when they are no longer used.
''');
return () => page;
} else if (page is String) {
throw '''Unexpected String,
use toNamed() instead''';
} else {
throw '''Unexpected format,
you can only use widgets and widget functions here''';
... ...
... ... @@ -245,7 +245,7 @@ class GetMaterialApp extends StatelessWidget {
onGenerateTitle: onGenerateTitle,
color: color,
theme: _.theme ?? theme ?? ThemeData.fallback(),
darkTheme: darkTheme,
darkTheme: _.darkTheme ?? darkTheme ?? ThemeData.fallback(),
themeMode: _.themeMode ?? themeMode,
locale: Get.locale ?? locale,
localizationsDelegates: localizationsDelegates,
... ... @@ -293,7 +293,7 @@ class GetMaterialApp extends StatelessWidget {
onGenerateTitle: onGenerateTitle,
color: color,
theme: _.theme ?? theme ?? ThemeData.fallback(),
darkTheme: darkTheme,
darkTheme: _.darkTheme ?? darkTheme ?? ThemeData.fallback(),
themeMode: _.themeMode ?? themeMode,
locale: Get.locale ?? locale,
localizationsDelegates: localizationsDelegates,
... ...
... ... @@ -10,6 +10,7 @@ class GetMaterialController extends GetxController {
bool testMode = false;
Key? unikey;
ThemeData? theme;
ThemeData? darkTheme;
ThemeMode? themeMode;
bool defaultPopGesture = GetPlatform.isIOS;
... ... @@ -36,7 +37,15 @@ class GetMaterialController extends GetxController {
Map<dynamic, GlobalKey<NavigatorState>> keys = {};
void setTheme(ThemeData value) {
theme = value;
if (darkTheme == null) {
theme = value;
} else {
if (value.brightness == Brightness.light) {
theme = value;
} else {
darkTheme = value;
}
}
update();
}
... ...
... ... @@ -31,7 +31,7 @@ class GetPageRoute<T> extends PageRoute<T> {
this.maintainState = true,
bool fullscreenDialog = false,
this.middlewares,
}) : reference = "$routeName: ${page.hashCode}",
}) : reference = "$routeName: ${settings?.hashCode ?? page.hashCode}",
super(settings: settings, fullscreenDialog: fullscreenDialog);
@override
... ...
... ... @@ -161,7 +161,7 @@ class GetObserver extends NavigatorObserver {
value.isDialog = newRoute.isDialog;
});
print('currentRoute.isDialog ${currentRoute.isDialog}');
// print('currentRoute.isDialog ${currentRoute.isDialog}');
routing?.call(_routeSend);
}
... ...
... ... @@ -187,6 +187,7 @@ class PageRedirect {
)
: GetPageRoute<T>(
page: route!.page,
routeName: route!.name,
parameter: route!.parameter,
settings: RouteSettings(
name: settings.name, arguments: settings.arguments),
... ...
... ... @@ -136,7 +136,9 @@ mixin NotifyManager<T> {
/// Subscribe to changes on the inner stream.
void addListener(GetStream<T> rxGetx) {
if (!_subscriptions.containsKey(rxGetx)) {
final subs = rxGetx.listen(subject.add);
final subs = rxGetx.listen((data) {
if (!subject.isClosed) subject.add(data);
});
final listSubscriptions =
_subscriptions[rxGetx] ??= <StreamSubscription>[];
listSubscriptions.add(subs);
... ... @@ -149,8 +151,12 @@ mixin NotifyManager<T> {
void Function()? onDone,
bool? cancelOnError,
}) =>
subject.listen(onData,
onError: onError, onDone: onDone, cancelOnError: cancelOnError);
subject.listen(
onData,
onError: onError,
onDone: onDone,
cancelOnError: cancelOnError ?? false,
);
/// Closes the subscriptions for this Rx, releasing the resources.
void close() {
... ...
... ... @@ -18,8 +18,10 @@ class GetX<T extends DisposableInterface> extends StatefulWidget {
// final StreamController Function(T) streamController;
final bool autoRemove;
final bool assignId;
final void Function(State state)? initState, dispose, didChangeDependencies;
final void Function(GetX oldWidget, State state)? didUpdateWidget;
final void Function(GetXState<T> state)? initState,
dispose,
didChangeDependencies;
final void Function(GetX oldWidget, GetXState<T> state)? didUpdateWidget;
final T? init;
final String? tag;
... ... @@ -48,8 +50,8 @@ class GetXState<T extends DisposableInterface> extends State<GetX<T>> {
}
RxInterface? _observer;
T? controller;
bool? isCreator = false;
late StreamSubscription subs;
bool? _isCreator = false;
late StreamSubscription _subs;
@override
void initState() {
... ... @@ -59,26 +61,26 @@ class GetXState<T extends DisposableInterface> extends State<GetX<T>> {
if (widget.global) {
if (isRegistered) {
if (GetInstance().isPrepared<T>(tag: widget.tag)) {
isCreator = true;
_isCreator = true;
} else {
isCreator = false;
_isCreator = false;
}
controller = GetInstance().find<T>(tag: widget.tag);
} else {
controller = widget.init;
isCreator = true;
_isCreator = true;
GetInstance().put<T>(controller!, tag: widget.tag);
}
} else {
controller = widget.init;
isCreator = true;
_isCreator = true;
controller?.onStart();
}
widget.initState?.call(this);
if (widget.global && Get.smartManagement == SmartManagement.onlyBuilder) {
controller?.onStart();
}
subs = _observer!.listen((data) => setState(() {}));
_subs = _observer!.listen((data) => setState(() {}), cancelOnError: false);
super.initState();
}
... ... @@ -99,15 +101,15 @@ class GetXState<T extends DisposableInterface> extends State<GetX<T>> {
@override
void dispose() {
if (widget.dispose != null) widget.dispose!(this);
if (isCreator! || widget.assignId) {
if (_isCreator! || widget.assignId) {
if (widget.autoRemove && GetInstance().isRegistered<T>(tag: widget.tag)) {
GetInstance().delete<T>(tag: widget.tag);
}
}
subs.cancel();
_subs.cancel();
_observer!.close();
controller = null;
isCreator = null;
_isCreator = null;
super.dispose();
}
... ...
... ... @@ -29,7 +29,7 @@ class _ObxState extends State<ObxWidget> {
@override
void initState() {
subs = _observer!.listen(_updateTree);
subs = _observer!.listen(_updateTree, cancelOnError: false);
super.initState();
}
... ...
... ... @@ -59,8 +59,11 @@ class GetBuilder<T extends GetxController> extends StatefulWidget {
final bool autoRemove;
final bool assignId;
final Object Function(T value)? filter;
final void Function(State state)? initState, dispose, didChangeDependencies;
final void Function(GetBuilder oldWidget, State state)? didUpdateWidget;
final void Function(GetBuilderState<T> state)? initState,
dispose,
didChangeDependencies;
final void Function(GetBuilder oldWidget, GetBuilderState<T> state)?
didUpdateWidget;
final T? init;
const GetBuilder({
... ... @@ -99,22 +102,15 @@ class GetBuilder<T extends GetxController> extends StatefulWidget {
// }
@override
_GetBuilderState<T> createState() => _GetBuilderState<T>();
GetBuilderState<T> createState() => GetBuilderState<T>();
}
class _GetBuilderState<T extends GetxController> extends State<GetBuilder<T>>
class GetBuilderState<T extends GetxController> extends State<GetBuilder<T>>
with GetStateUpdaterMixin {
T? controller;
bool? isCreator = false;
VoidCallback? remove;
bool? _isCreator = false;
VoidCallback? _remove;
Object? _filter;
List<VoidCallback>? _watchs;
// static _GetBuilderState _currentState;
void watch(VoidCallback listener) {
(_watchs ??= <VoidCallback>[]).add(listener);
}
@override
void initState() {
... ... @@ -127,19 +123,19 @@ class _GetBuilderState<T extends GetxController> extends State<GetBuilder<T>>
if (widget.global) {
if (isRegistered) {
if (GetInstance().isPrepared<T>(tag: widget.tag)) {
isCreator = true;
_isCreator = true;
} else {
isCreator = false;
_isCreator = false;
}
controller = GetInstance().find<T>(tag: widget.tag);
} else {
controller = widget.init;
isCreator = true;
_isCreator = true;
GetInstance().put<T>(controller!, tag: widget.tag);
}
} else {
controller = widget.init;
isCreator = true;
_isCreator = true;
controller?.onStart();
}
... ... @@ -154,8 +150,8 @@ class _GetBuilderState<T extends GetxController> extends State<GetBuilder<T>>
/// It gets a reference to the remove() callback, to delete the
/// setState "link" from the Controller.
void _subscribeToController() {
remove?.call();
remove = (widget.id == null)
_remove?.call();
_remove = (widget.id == null)
? controller?.addListener(
_filter != null ? _filterUpdate : getUpdate,
)
... ... @@ -177,19 +173,18 @@ class _GetBuilderState<T extends GetxController> extends State<GetBuilder<T>>
void dispose() {
super.dispose();
widget.dispose?.call(this);
if (isCreator! || widget.assignId) {
if (_isCreator! || widget.assignId) {
if (widget.autoRemove && GetInstance().isRegistered<T>(tag: widget.tag)) {
GetInstance().delete<T>(tag: widget.tag);
}
}
remove?.call();
_remove?.call();
controller = null;
isCreator = null;
remove = null;
_isCreator = null;
_remove = null;
_filter = null;
_watchs = null;
}
@override
... ...
import 'dart:async';
import 'dart:collection';
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
... ... @@ -11,11 +10,11 @@ typedef Disposer = void Function();
typedef GetStateUpdate = void Function();
class ListNotifier implements Listenable {
int _version = 0;
int _microtask = 0;
// int _version = 0;
// int _microtask = 0;
int get notifierVersion => _version;
int get notifierMicrotask => _microtask;
// int get notifierVersion => _version;
// int get notifierMicrotask => _microtask;
List<GetStateUpdate?>? _updaters = <GetStateUpdate?>[];
... ... @@ -28,14 +27,14 @@ class ListNotifier implements Listenable {
/// This debounce the call to update.
/// It prevent errors and duplicates builds
if (_microtask == _version) {
_microtask++;
scheduleMicrotask(() {
_version++;
_microtask = _version;
_notifyUpdate();
});
}
// if (_microtask == _version) {
// _microtask++;
// scheduleMicrotask(() {
// _version++;
// _microtask = _version;
_notifyUpdate();
// });
// }
}
void _notifyUpdate() {
... ...
... ... @@ -149,7 +149,7 @@ referenceValue is ${calculePercentage(referenceValue, requestedValue)}% more tha
print('GetValue delay $getx ms to made $times requests');
print('-----------');
print('''
GetValue is ${calculePercentage(dart, getx).round()}% more fast than Default ValueNotifier with $times requests''');
GetValue is ${calculePercentage(dart, getx).round()}% faster than Default ValueNotifier with $times requests''');
});
test('run benchmarks from Streams', () async {
... ... @@ -162,7 +162,7 @@ GetValue is ${calculePercentage(dart, getx).round()}% more fast than Default Val
var dart = await stream();
print('-----------');
print('''
GetStream is ${calculePercentage(dart, mini).round()}% more fast than Default Stream with $times requests''');
GetStream is ${calculePercentage(dart, mini).round()}% faster than Default Stream with $times requests''');
print('-----------');
times = 30000;
... ... @@ -180,7 +180,7 @@ GetStream is ${calculePercentage(dart, mini).round()}% more fast than Default St
print('getx_mini_stream delay $mini ms to made $times requests');
print('-----------');
print('''
GetStream is ${calculePercentage(dart, mini).round()}% more fast than Default Stream with $times requests''');
GetStream is ${calculePercentage(dart, mini).round()}% faster than Default Stream with $times requests''');
});
}
... ...