Jonny Borges
Committed by GitHub

Constraint BottomSheet to keyboard

## [2.6.3]
- Flutter currently has a problem on some devices where using showModalBottomSheet() can cause TextFields to be hidden behind the keyboard (https://github.com/flutter/flutter/issues/18564) this issue is closed, even users reporting that the problem still occurs.
The problem happens casually, as well as the problem of the snackbar on the iPhone SE 2, and checking the code, I realized that a padding with MediaQuery.of(context).viewInsets.bottom is missing inside the bottomSheet to make it work correctly, since it does not have any constraint with the keyboard.
For stability, I decided not to use the standard Flutter bottomSheet, which contains many bugs, mainly related to keyboard padding, and the lack of respect for topBar's safeArea, and to use a proprietary bottomSheet implementation that is more stable. The Flutter dialog has no problem, so it will be used as the basis for Get.dialog. The bottomSheet will be based on the Flutter bottomSheet Raw API (_ModalBottomSheetRoute), applying bug fixes.
- Added Get.isSnackbarOpen tests
## [2.6.2]
- Refactor Bindings API
## [2.6.1]
- Expose Bindings API
## [2.6.0]
- Added bindings.
You can now add bindings from your controllers to your routes, to prepare GetBuilder or GetX to create a dependency already declared in a Binding class. This feature is in an experimental phase, and will not be documented until the end of the tests.
... ...
... ... @@ -278,7 +278,7 @@ What performance improvements does Get bring?
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.
3- Forget StatefulWidget! With Get you will never need it. 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.
4- Organize your project for real! Controllers must not be in your UI, place your TextEditController, or any controller you use within your Controller class.
... ... @@ -288,7 +288,7 @@ What performance improvements does Get bring?
7- Use streams only if necessary. You can use your StreamControllers inside your controller normally, and use StreamBuilder also normally, but remember, a stream reasonably consumes memory, reactive programming is beautiful, but you shouldn't abuse it. 30 streams open simultaneously can be worse than changeNotifier (and changeNotifier is very bad).
8- Update widgets without spending ram for that. Get stores only the GetBuilder creator ID, and updates that GetBuilder when necessary. The memory consumption of the get ID storage in memory is close to 0 even for thousands of GetBuilders. When you create a new GetBuilder, you are actually sharing the state of GetBuilder that has a creator ID. A new state is not created for each GetBuilder, which saves A LOT OF ram for large applications. Basically your application will be entirely Stateless, and the few Widgets that will be Stateful (within GetBuilder) will have a single state, and therefore updating one will update them all. The state is just one.
8- Update widgets without spending ram for that. Get stores only the GetBuilder creator ID, and updates that GetBuilder when necessary. The memory consumption of the get ID storage in memory is very low even for thousands of GetBuilders. When you create a new GetBuilder, you are actually sharing the state of GetBuilder that has a creator ID. A new state is not created for each GetBuilder, which saves A LOT OF ram for large applications. Basically your application will be entirely Stateless, and the few Widgets that will be Stateful (within GetBuilder) will have a single state, and therefore updating one will update them all. The state is just one.
9- Get is omniscient and in most cases it knows exactly the time to take a controller out of memory. You should not worry about when to dispose of a controller, Get knows the best time to do this. Example:
... ... @@ -318,6 +318,9 @@ GetBuilder<Controller>(
**Done!**
- You have already learned how to manage states with Get.
- Note: You may want a larger organization, and not use the init property. For that, you can create a class and extends Bindings class, and within it mention the controllers that will be created within that route. Controllers will not be created at that time, on the contrary, this is just a statement, so that the first time you use a Controller, Get will know where to look. Get will remain lazyLoad, and will continue to dispose Controllers when they are no longer needed. See the pub.dev example to see how it works.
If you navigate many routes and need data that was in your previously used controller, you just need to use GetBuilder Again (with no init):
```dart
... ...

38.3 KB | W: | H:

38.6 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
... ... @@ -13,7 +13,7 @@ export 'src/rx/rx_getbuilder.dart';
export 'src/root/root_widget.dart';
export 'src/routes/default_route.dart';
export 'src/routes/get_route.dart';
export 'src/routes/get_route.dart';
export 'src/routes/bindings_interface.dart';
export 'src/routes/observers/route_observer.dart';
export 'src/routes/transitions_type.dart';
export 'src/platform/platform.dart';
... ...
... ... @@ -8,9 +8,6 @@ class GetModalBottomSheetRoute<T> extends PopupRoute<T> {
this.backgroundColor,
this.elevation,
this.shape,
this.removeBottom = false,
this.removeLeft = false,
this.removeRight = false,
this.removeTop = true,
this.clipBehavior,
this.modalBarrierColor,
... ... @@ -36,12 +33,6 @@ class GetModalBottomSheetRoute<T> extends PopupRoute<T> {
// remove safearea from top
final bool removeTop;
// remove safearea from bottom
final bool removeBottom;
// remove safearea from left
final bool removeLeft;
// remove safearea from right
final bool removeRight;
@override
Duration get transitionDuration => Duration(milliseconds: 700);
... ... @@ -75,9 +66,9 @@ class GetModalBottomSheetRoute<T> extends PopupRoute<T> {
Widget bottomSheet = MediaQuery.removePadding(
context: context,
removeTop: removeTop,
removeBottom: removeBottom,
removeLeft: removeLeft,
removeRight: removeRight,
child: Padding(
padding:
EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: _GetModalBottomSheet<T>(
route: this,
backgroundColor: backgroundColor ??
... ... @@ -90,6 +81,7 @@ class GetModalBottomSheetRoute<T> extends PopupRoute<T> {
isScrollControlled: isScrollControlled,
enableDrag: enableDrag,
),
),
);
if (theme != null) bottomSheet = Theme(data: theme, child: bottomSheet);
return bottomSheet;
... ...
... ... @@ -366,7 +366,8 @@ class Get {
assert(isDismissible != null);
assert(enableDrag != null);
return navigator.push<T>(GetModalBottomSheetRoute<T>(
return Navigator.of(overlayContext, rootNavigator: useRootNavigator)
.push(GetModalBottomSheetRoute<T>(
builder: (_) => bottomsheet,
theme: Theme.of(Get.key.currentContext, shadowThemeOnly: true),
isScrollControlled: isScrollControlled,
... ...
... ... @@ -135,6 +135,7 @@ class GetMaterialApp extends StatelessWidget {
curve: newNamedRoutes[settingsName].curve,
alignment: newNamedRoutes[settingsName].alignment,
opaque: newNamedRoutes[settingsName].opaque,
binding: newNamedRoutes[settingsName].binding,
transitionDuration: (transitionDuration == null
? newNamedRoutes[settingsName].transitionDuration
: transitionDuration),
... ... @@ -159,6 +160,7 @@ class GetMaterialApp extends StatelessWidget {
alignment: unknownRoute.alignment,
parameter: unknownRoute.parameter,
opaque: unknownRoute.opaque,
binding: unknownRoute.binding,
transitionDuration: unknownRoute.transitionDuration,
popGesture: unknownRoute.popGesture,
transition: unknownRoute.transition,
... ...
... ... @@ -41,7 +41,12 @@ class GetRouteBase<T> extends PageRoute<T> {
assert(maintainState != null),
assert(fullscreenDialog != null),
// assert(opaque),
super(settings: settings, fullscreenDialog: fullscreenDialog);
super(settings: settings, fullscreenDialog: fullscreenDialog) {
/// prebuild dependencies
if (binding != null) {
binding.dependencies();
}
}
/// Builds the primary contents of the route.
final Widget page;
... ... @@ -468,11 +473,6 @@ class GetRouteBase<T> extends PageRoute<T> {
@override
Widget buildTransitions(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) {
/// prebuild dependencies
if (binding != null) {
binding.dependencies();
}
return buildPageTransitions<T>(
this,
context,
... ...
... ... @@ -12,7 +12,7 @@ class GetRoute {
final Alignment alignment;
final bool maintainState;
final bool opaque;
final Bindings bindings;
final Bindings binding;
final Widget customTransition;
final Duration transitionDuration;
final bool fullscreenDialog;
... ... @@ -29,7 +29,7 @@ class GetRoute {
this.opaque = true,
this.transitionDuration = const Duration(milliseconds: 400),
this.popGesture,
this.bindings,
this.binding,
this.transition,
this.customTransition,
this.fullscreenDialog = false,
... ...
name: get
description: Open screens/snackbars/dialogs/bottomSheets without context, manage states and inject dependencies easily with Get.
version: 2.6.0
version: 2.6.3
homepage: https://github.com/jonataslaw/get
environment:
... ...
... ... @@ -330,6 +330,51 @@ void main() {
expect(find.byType(FirstScreen), findsOneWidget);
});
testWidgets("Get.snackbar test", (tester) async {
await tester.pumpWidget(
Wrapper(
child: RaisedButton(
child: Text('Open Snackbar'),
onPressed: () {
Get.snackbar('title', "message",
duration: Duration(seconds: 1), instantInit: true);
},
),
),
);
expect(Get.isSnackbarOpen, false);
await tester.tap(find.text('Open Snackbar'));
expect(Get.isSnackbarOpen, true);
await tester.pump(const Duration(seconds: 1));
});
testWidgets("Get.rawSnackbar test", (tester) async {
await tester.pumpWidget(
Wrapper(
child: RaisedButton(
child: Text('Open Snackbar'),
onPressed: () {
Get.rawSnackbar(
title: 'title',
message: "message",
duration: Duration(seconds: 1),
instantInit: true);
},
),
),
);
expect(Get.isSnackbarOpen, false);
await tester.tap(find.text('Open Snackbar'));
expect(Get.isSnackbarOpen, true);
await tester.pump(const Duration(seconds: 1));
});
}
class FirstScreen extends StatelessWidget {
... ...