jonataslaw

Release Get 2.0

... ... @@ -207,4 +207,24 @@
## [1.20.0-dev]
- Added Get Instance Manager
Get.put / Get.find / Get.delete
\ No newline at end of file
Get.put / Get.find / Get.delete
## [1.20.1-dev]
- Improve: Get.finds
## [2.0.0-dev]
- Added easy state manager
- Cleaner code
- Improve Get
- Change dialog API
- Added GetMaterialApp
- Added new experimental APIs
- Improve Observer
- Added default duration on Transitions
- Added new routeNamed sistem
- Added Global stateManager config
- Improve Get instance manager
- Added routingCallback
- Added closeOverlays to Get.back
- Added dynamic urls
- Many APIs added
\ No newline at end of file
... ...
# Get
A consistent navigation library that lets you navigate between screens, open dialogs/bottomSheets, and display snackbars from anywhere in your code without context.
## Getting Started
*Languages: [English](README.md), [Brazilian Portuguese](README.pt-br.md).*
Flutter's conventional navigation has a lot of unnecessary boilerplate, requires context to navigate between screens, open dialogs, and use snackbars on framework is really painful.
In addition, when a route is pushed, the entire MaterialApp can be rebuilt causing freezes, this does not happen with Get.
This library that will change the way you work with the Framework and save your life from cliche code, increasing your productivity, and eliminating the rebuild bugs of your application.
Get is an extra-light and powerful microframework for Flutter that will give you superpowers and increase your productivity. Navigate without context, open dialogs, snackbars or bottomsheets from anywhere in your code in an easy and practical way.
Get is secure, stable, up-to-date, and offers a huge range of APIs that are not present in the standard framework.
```dart
// Default Flutter navigator
... ... @@ -23,23 +17,28 @@ Navigator.of(context).push(
// Get sintax
Get.to(Home());
```
*Languages: [English](README.md), [Brazilian Portuguese](README.pt-br.md).*
## Getting Started
Flutter's conventional navigation has a lot of unnecessary boilerplate, requires context to navigate between screens, open dialogs, and use snackbars on framework is really boring.
In addition, when a route is pushed, the entire MaterialApp can be rebuilt causing freezes, this does not happen with Get.
This library that will change the way you work with the Framework and save your life from cliche code, increasing your productivity, and eliminating the rebuild bugs of your application.
## How to use?
- Flutter Master/Dev/Beta: version 2.0.0-dev
- Flutter Stable branch: version 1.17.3
Add this to your package's pubspec.yaml file:
```
dependencies:
get: ^1.17.3 // ^1.20.0-dev on beta/dev/master
```
And import it:
get: ^1.17.3 // ^2.0.0-dev on beta/dev/master
```
Exchange your MaterialApp for GetMaterialApp and enjoy!
```dart
import 'package:get/get.dart';
```
Add GetKey to your MaterialApp and enjoy:
```dart
MaterialApp(
navigatorKey: Get.key,
GetMaterialApp( // Before: MaterialApp(
home: MyHome(),
)
```
... ... @@ -218,8 +217,7 @@ Get.bottomSheet is like showModalBottomSheet, but don't need of context.
```dart
Get.bottomSheet(
builder: (_){
return Container(
Container(
child: Wrap(
children: <Widget>[
ListTile(
... ... @@ -238,19 +236,108 @@ Get.bottomSheet(
}
);
```
### Global configurations
You can create Global settings for Get. Just add Get.config to your code before pushing any route
## Simple State Manager
There are currently several state managers for Flutter. However, most of them involve using an inheritedWidget to access your data through context and use ChangeNotifier to update widgets (like the Provider), or are too complex for beginners (like BLoC), others are easy and reactive (like MobX) however they need to use a code generator.
So I created in just 95 lines of code this easy and light state manager, which does not use ChangeNotifier (ChangeNotifier is bad for performance, and which will supply the need especially for those who are new to Flutter. Get is omniscient, this means that it has access to any Flutter API, whether inside or outside the widget tree. The Get state manager updates only the necessary Widget, uses the widgets' own memory status to update, making it more efficient than ChangeNotifier, and does not use InheritedWidget, giving you full control of the state of your application. This does not mean that it is the best state manager, but it is an ideal solution for certain types of users.
Get's state manager is perfect for the MVC standard, and you can use it like this:
```dart
Get.config(
enableLog = true,
defaultPopGesture = true,
defaultTransition = Transitions.cupertino}
// Create controller class and extends GetController
class Controller extends GetController {
int counter = 0;
void increment() {
counter++;
update(this); // use update(this) to update counter variable um UI when increment be called
}
}
// On your Stateless/Stateful class, use GetBuilder to update Text when increment be called
GetBuilder(
controller: controller,
builder: (_) => Text(
'${_.counter}',
)),
```
**Done!**
- You have already learned how to manage states with Get.
## Simple Instance Manager
Are you already using Get and want to make your project as lean as possible? Now Get has a simple manager that allows you to retrieve the same class as your Bloc or Controller with just 1 lines of code.
### Global State manager
If you navigate many routes and need data that was in your previously used controller, you just need to send Get to find the controller in memory for you!
```dart
class OtherClasse extends StatelessWidget {
@override
Widget build(BuildContext context) {
Controller controller = Get.find();
return Scaffold(
body: Center(
child: GetBuilder(
controller: controller,
builder: (_) => Text(
'${_.counter}',
style: Theme.of(context).textTheme.headline4,
),
),
),
);
}
```
If you don't want to instantiate your controller whenever you need to use it, you can create a get directly on your controller and access it statically.
```dart
class Controller extends GetController {
static Controller get to => Get.find(); // add this line
int counter = 0;
void increment() {
counter++;
update(this);
}
}
```
And then you can access your controller directly, that way:
```dart
FloatingActionButton(
onPressed: Controller.to.increment, // This is incredibly simple!
child: Icon(Icons.add),
),
```
When you press FloatingActionButton, all widgets that are listening to the 'counter' variable will be updated automatically.
##### Different forms of use:
You can use controlador instance directly on GetBuilder:
```dart
GetBuilder(
controller: Controller(), //here
builder: (_) => Text(
'${_.counter}',
)),
```
You can type your GetBuilder to access the IDE's autocomplete
```dart
GetBuilder<Controller>( //here
controller: Controller(),
builder: (value) => Text(
'${value.counter}', //here
)),
```
You can to use controller instance:
```dart
Controller controller = Controller();
[...]
GetBuilder(
controller: controller, //here
builder: (_) => Text(
'${controller.counter}', // here
)),
```
## Simple Instance Manager
Are you already using Get and want to make your project as lean as possible? Now Get has a simple instance manager that allows you to retrieve the same class as your Bloc or Controller with just 1 lines of code.
```dart
Controller controller = Get.put(Controller()); // Rather Controller controller = Controller();
... ... @@ -281,7 +368,7 @@ Get.delete(Controller());
## Navigate with named routes:
- If you prefer to browse selected routes, or Get also supports this.
- If you prefer to navigate by namedRoutes, Get also supports this.
To navigate to nextScreen
```dart
... ... @@ -296,6 +383,21 @@ To navigate and remove all previous screens from the tree.
Get.offAllNamed("/NextScreen");
```
To define routes, use GetMaterialApp:
```dart
void main() {
runApp(GetMaterialApp(
initialRoute: '/',
namedRoutes: {
'/': GetRoute(page: MyHomePage()),
'/second': GetRoute(page: Second()),
'/third': GetRoute(page: Third(),transition: Transition.cupertino);
},
));
}
```
### Send data to named Routes:
Just send what you want for arguments. Get accepts anything here, whether it is a String, a Map, a List, or even a class instance.
... ... @@ -309,61 +411,63 @@ print(Get.arguments);
//print out: Get is the best
```
## Configure the Named Routes and And offering full flutter_web support to friendly urls:
#### Dynamic urls links
Get is the first and only package to offer advanced dynamic urls just like on the Web. Web developers have probably already wanted this feature on Flutter, and most likely have seen a package promise this feature and deliver a totally different syntax than a URL would have on web, but Get also solves that.
### If you have not yet added "navigatorKey: Get.key," to your MaterialApp, do it now. Take the opportunity to add an "initialRoute" and your "onGenerateRoute".
```dart
Get.offAllNamed("/NextScreen?device=phone&id=354&name=Enzo");
```
on your controller/bloc/stateful/stateless class:
```dart
print(Get.parameters['id']);
// out: 354
print(Get.parameters['name']);
// out: Enzo
```
You can also receive NamedParameters with Get easily:
```dart
void main() {
runApp(MaterialApp(
onGenerateRoute: Router.generateRoute,
initialRoute: "/",
navigatorKey: Get.key,
title: 'Navigation',
runApp(GetMaterialApp(
initialRoute: '/',
namedRoutes: {
'/': GetRoute(page: MyHomePage()),
'/second/:user': GetRoute(page: Second()), // receive ID
'/third': GetRoute(page: Third(),transition: Transition.cupertino);
},
));
}
```
Send data on route name
```dart
Get.toNamed("/second/34954");
```
Copy this Router class below and put it in your app, rename routes and classes for your own, add more classes to it if necessary.
```dart
class Router {
static Route<dynamic> generateRoute(RouteSettings settings) {
switch (settings.name) {
case '/':
return GetRoute(
page: First(),
settings: settings,
);
case '/second':
return GetRoute(
settings: settings, page: Second(), transition: Transition.fade);
case '/third':
return GetRoute(
settings: settings,
page: Third(),
popGesture: true,
transition: Transition.cupertino);
default:
return GetRoute(
settings: settings,
transition: Transition.fade,
page: Scaffold(
body:
Center(child: Text('No route defined for ${settings.name}')),
));
}
}
}
On second screen take the data by parameter
```dart
print(Get.parameters['user']);
// out: 34954
```
And now, all you need to do is use Get.toNamed() to navigate your named routes, without any context (you can call your routes directly from your BLoC or Controller class), and when your app is compiled to the web, your routes will appear in the url <3
#### Middleware
If you want listen Get events to trigger actions, you can add a GetObserver to your materialApp. This is extremely useful for triggering events whenever a specific Screen is displayed on the screen. Currently on Flutter you would have to put the event on initState and wait for a possible response in a navigator.pop (context); to get that. But with Get, this is extremely simple!
If you want listen Get events to trigger actions, you can to use routingCallback to it
```dart
GetMaterialApp(
routingCallback: (route){
if(routing.current == '/second'){
openAds();
}
}
```
If you are not using GetMaterialApp, you can use the manual API to attach Middleware observer.
##### add GetObserver();
```dart
void main() {
runApp(MaterialApp(
... ... @@ -466,18 +570,34 @@ class Third extends StatelessWidget {
}
```
### Optional Global Settings
You can create Global settings for Get. Just add Get.config to your code before pushing any route or do it directly in your GetMaterialApp
```dart
GetMaterialApp(
enableLog: true,
defaultTransition: Transitions.fade,
defaultOpaqueRoute: Get.isOpaqueRouteDefault,
defaultPopGesture: Get.isPopGestureEnable,
defaultDurationTransition: Get.defaultDurationTransition,
defaultGlobalState: Get.defaultGlobalState,
);
Get.config(
enableLog = true,
defaultPopGesture = true,
defaultTransition = Transitions.cupertino}
```
### Advanced APIs
Each day Get gets further away from the standard Framework, and provides a wider range of features that are unthinkable to be executed using the standard Flutter.
With Get 1.17.0 a range of new APIs was launched, which allow access from arguments of a named route to whether there is a snackbar or dialog open at that moment, or which screen is being displayed.
This is a big step towards completely detaching the Flutter navigation from InheritedWidgets. Using context to access an InheritedWidget to access a simple navigation feature is one of the only boring things to do in this incredible framework, and now Get has solved this problem, it has become omniscient, and you will have access to basically any tool Flutter which is only available within the widget tree using it.
All APIs available here are in beta stage, so if you find any errors here, open an issue or offer a PR.
### Other Advanced APIs and Manual configurations
GetMaterialApp configures everything for you, but if you are using any package like Modular, you may want to configure Get Manually using advanced APIs.
```dart
MaterialApp(
navigatorKey: Get.key,
navigatorObservers: [GetObserver()], // ADD THIS !!!!
navigatorObservers: [GetObserver()],
);
```
... ... @@ -507,8 +627,24 @@ Get.isDialogOpen // check if dialog is open
Get.isBottomSheetOpen // check if bottomsheet is open
Get.removeRoute() // remove one route.
Get.until() // back repeatedly until the predicate returns true.
Get.offUntil() // go to next route and remove all the previous routes until the predicate returns true.
Get.offNamedUntil() // go to next named route and remove all the previous routes until the predicate returns true.
GetPlatform.isAndroid/isIOS/isWeb... //(This method is completely compatible with FlutterWeb, unlike the framework. "Platform.isAndroid")
Get.height / Get.width // Equivalent to the method: MediaQuery.of(context).size.height
Get.context // Gives the context of the screen in the foreground anywhere in your code.
Get.contextOverlay // Gives the context of the snackbar/dialog/bottomsheet in the foreground anywhere in your code.
```
### Nested Navigators
Get made Flutter's nested navigation even easier.
... ... @@ -554,25 +690,4 @@ See how simple it is:
```
### Others methods (docs will be added soon):
```dart
Get.removeRoute() // remove one route.
Get.until() // back repeatedly until the predicate returns true.
Get.offUntil() // go to next route and remove all the previous routes until the predicate returns true.
Get.offNamedUntil() // go to next named route and remove all the previous routes until the predicate returns true.
GetPlatform.isAndroid/isIOS/isWeb... //(This method is completely compatible with FlutterWeb, unlike the framework. "Platform.isAndroid")
Get.height / Get.width // Equivalent to the method: MediaQuery.of(context).size.height
Get.context // Gives the context of the screen in the foreground anywhere in your code.
Get.contextOverlay // Gives the context of the snackbar/dialog/bottomsheet in the foreground anywhere in your code.
```
This library will always be updated and implementing new features. Feel free to offer PRs and contribute to them.
... ...
... ... @@ -69,7 +69,7 @@
},
{
"name": "get",
"rootUri": "file:///opt/flutter/.pub-cache/hosted/pub.dartlang.org/get-1.11.6",
"rootUri": "file:///opt/flutter/.pub-cache/hosted/pub.dartlang.org/get-1.15.2",
"packageUri": "lib/",
"languageVersion": "2.1"
},
... ... @@ -176,7 +176,7 @@
"languageVersion": "2.1"
}
],
"generated": "2020-04-02T04:26:33.309754Z",
"generated": "2020-04-27T06:02:27.159254Z",
"generator": "pub",
"generatorVersion": "2.8.0-dev.18.0.flutter-e8c4aed700"
"generatorVersion": "2.8.0-dev.20.10"
}
... ...
# Generated by pub on 2020-04-02 01:26:33.285366.
# Generated by pub on 2020-04-27 03:02:27.132181.
archive:file:///opt/flutter/.pub-cache/hosted/pub.dartlang.org/archive-2.0.13/lib/
args:file:///opt/flutter/.pub-cache/hosted/pub.dartlang.org/args-1.6.0/lib/
async:file:///opt/flutter/.pub-cache/hosted/pub.dartlang.org/async-2.4.1/lib/
... ... @@ -10,7 +10,7 @@ crypto:file:///opt/flutter/.pub-cache/hosted/pub.dartlang.org/crypto-2.1.4/lib/
cupertino_icons:file:///opt/flutter/.pub-cache/hosted/pub.dartlang.org/cupertino_icons-0.1.3/lib/
flutter:file:///opt/flutter/packages/flutter/lib/
flutter_test:file:///opt/flutter/packages/flutter_test/lib/
get:file:///opt/flutter/.pub-cache/hosted/pub.dartlang.org/get-1.11.6/lib/
get:file:///opt/flutter/.pub-cache/hosted/pub.dartlang.org/get-1.15.2/lib/
image:file:///opt/flutter/.pub-cache/hosted/pub.dartlang.org/image-2.1.12/lib/
matcher:file:///opt/flutter/.pub-cache/hosted/pub.dartlang.org/matcher-0.12.6/lib/
meta:file:///opt/flutter/.pub-cache/hosted/pub.dartlang.org/meta-1.1.8/lib/
... ...
... ... @@ -80,7 +80,7 @@ packages:
name: get
url: "https://pub.dartlang.org"
source: hosted
version: "1.11.6"
version: "1.15.2"
image:
dependency: transitive
description:
... ...
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/.pub" />
<excludeFolder url="file://$MODULE_DIR$/build" />
<excludeFolder url="file://$MODULE_DIR$/example/.dart_tool" />
<excludeFolder url="file://$MODULE_DIR$/example/.pub" />
<excludeFolder url="file://$MODULE_DIR$/example/build" />
</content>
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Dart SDK" level="project" />
<orderEntry type="library" name="Dart Packages" level="project" />
</component>
</module>
\ No newline at end of file
... ...
... ... @@ -5,6 +5,8 @@ export 'src/get_main.dart';
export 'src/snackbar/snack.dart';
export 'src/bottomsheet/bottomsheet.dart';
export 'src/snackbar/snack_route.dart';
export 'src/state/get_state.dart';
export 'src/root/root_widget.dart';
export 'src/routes/observers/route_observer.dart';
export 'src/routes/transitions_type.dart';
export 'src/platform/platform.dart';
... ...
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class DefaultDialogGet extends StatelessWidget {
final color;
final double opacity;
final String title;
final Widget content;
final Widget cancel;
final Widget confirm;
const DefaultDialogGet(
{Key key,
this.color,
this.opacity = 0.5,
this.title,
this.content,
this.cancel,
this.confirm})
: super(key: key);
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text(title, textAlign: TextAlign.center),
content: content,
actions: <Widget>[cancel, confirm],
);
}
}
Future<T> getShowGeneralDialog<T>({
@required RoutePageBuilder pageBuilder,
bool barrierDismissible,
String barrierLabel,
Color barrierColor,
Duration transitionDuration,
RouteTransitionsBuilder transitionBuilder,
bool useRootNavigator = true,
}) {
assert(pageBuilder != null);
assert(useRootNavigator != null);
assert(!barrierDismissible || barrierLabel != null);
return Get.key.currentState.push<T>(_DialogRoute<T>(
pageBuilder: pageBuilder,
settings: RouteSettings(name: "dialog"),
barrierDismissible: barrierDismissible,
barrierLabel: barrierLabel,
barrierColor: barrierColor,
transitionDuration: transitionDuration,
transitionBuilder: transitionBuilder,
));
}
class _DialogRoute<T> extends PopupRoute<T> {
_DialogRoute({
@required RoutePageBuilder pageBuilder,
bool barrierDismissible = true,
String barrierLabel,
Color barrierColor = const Color(0x80000000),
Duration transitionDuration = const Duration(milliseconds: 200),
RouteTransitionsBuilder transitionBuilder,
RouteSettings settings,
}) : assert(barrierDismissible != null),
_pageBuilder = pageBuilder,
_barrierDismissible = barrierDismissible,
_barrierLabel = barrierLabel,
_barrierColor = barrierColor,
_transitionDuration = transitionDuration,
_transitionBuilder = transitionBuilder,
super(settings: settings);
final RoutePageBuilder _pageBuilder;
@override
bool get barrierDismissible => _barrierDismissible;
final bool _barrierDismissible;
@override
String get barrierLabel => _barrierLabel;
final String _barrierLabel;
@override
Color get barrierColor => _barrierColor;
final Color _barrierColor;
@override
Duration get transitionDuration => _transitionDuration;
final Duration _transitionDuration;
final RouteTransitionsBuilder _transitionBuilder;
@override
Widget buildPage(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
return Semantics(
child: _pageBuilder(context, animation, secondaryAnimation),
scopesRoute: true,
explicitChildNodes: true,
);
}
@override
Widget buildTransitions(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) {
if (_transitionBuilder == null) {
return FadeTransition(
opacity: CurvedAnimation(
parent: animation,
curve: Curves.linear,
),
child: child);
} // Some default transition
return _transitionBuilder(context, animation, secondaryAnimation, child);
}
}
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:get/src/dialog/dialog.dart';
import 'package:get/get.dart';
import '../get.dart';
import 'bottomsheet/bottomsheet.dart';
import 'platform/platform.dart';
import 'routes/default_route.dart';
import 'routes/observers/route_observer.dart';
import 'routes/transitions_type.dart';
import 'snackbar/snack.dart';
class Get {
static Get _get;
... ... @@ -46,6 +47,9 @@ class Get {
static bool _defaultOpaqueRoute = true;
static Transition _defaultTransition =
(GetPlatform.isIOS ? Transition.cupertino : Transition.fade);
static Duration _defaultDurationTransition = Duration(milliseconds: 400);
static bool _defaultGlobalState = true;
static RouteSettings _settings;
/// It replaces Navigator.push, but needs no context, and it doesn't have the Navigator.push
/// routes rebuild bug present in Flutter. If for some strange reason you want the default behavior
... ... @@ -56,21 +60,12 @@ class Get {
Duration duration,
int id,
bool popGesture}) {
if (id == null) {
return key.currentState.push(GetRoute(
opaque: opaque ?? true,
page: page,
popGesture: popGesture ?? _defaultPopGesture,
transition: transition ?? _defaultTransition,
transitionDuration: duration ?? const Duration(milliseconds: 400)));
} else {
return global(id).currentState.push(GetRoute(
opaque: opaque ?? true,
page: page,
popGesture: popGesture ?? _defaultPopGesture,
transition: transition ?? _defaultTransition,
transitionDuration: duration ?? const Duration(milliseconds: 400)));
}
return global(id).currentState.push(GetRoute(
opaque: opaque ?? true,
page: page,
popGesture: popGesture ?? _defaultPopGesture,
transition: transition ?? _defaultTransition,
transitionDuration: duration ?? _defaultDurationTransition));
}
/// It replaces Navigator.pushNamed, but needs no context, and it doesn't have the Navigator.pushNamed
... ... @@ -79,66 +74,40 @@ class Get {
static Future<T> toNamed<T>(String page, {arguments, int id}) {
// if (key.currentState.mounted) // add this if appear problems on future with route navigate
// when widget don't mounted
if (id == null) {
return key.currentState.pushNamed(page, arguments: arguments);
} else {
return global(id).currentState.pushNamed(page, arguments: arguments);
}
return global(id).currentState.pushNamed(page, arguments: arguments);
}
/// It replaces Navigator.pushReplacementNamed, but needs no context.
static Future<T> offNamed<T>(String page, {arguments, int id}) {
// if (key.currentState.mounted) // add this if appear problems on future with route navigate
// when widget don't mounted
if (id == null) {
return key.currentState.pushReplacementNamed(page, arguments: arguments);
} else {
return global(id)
.currentState
.pushReplacementNamed(page, arguments: arguments);
}
return global(id)
.currentState
.pushReplacementNamed(page, arguments: arguments);
}
/// It replaces Navigator.popUntil, but needs no context.
static void until(String page, predicate, {int id}) {
static void until(predicate, {int id}) {
// if (key.currentState.mounted) // add this if appear problems on future with route navigate
// when widget don't mounted
if (id == null) {
return key.currentState.popUntil(predicate);
} else {
return global(id).currentState.popUntil(predicate);
}
return global(id).currentState.popUntil(predicate);
}
/// It replaces Navigator.pushAndRemoveUntil, but needs no context.
static Future<T> offUntil<T>(page, predicate, {int id}) {
// if (key.currentState.mounted) // add this if appear problems on future with route navigate
// when widget don't mounted
if (id == null) {
return key.currentState.pushAndRemoveUntil(page, predicate);
} else {
return global(id).currentState.pushAndRemoveUntil(page, predicate);
}
return global(id).currentState.pushAndRemoveUntil(page, predicate);
}
/// It replaces Navigator.pushNamedAndRemoveUntil, but needs no context.
static Future<T> offNamedUntil<T>(page, predicate, {int id}) {
// if (key.currentState.mounted) // add this if appear problems on future with route navigate
// when widget don't mounted
if (id == null) {
return key.currentState.pushNamedAndRemoveUntil(page, predicate);
} else {
return global(id).currentState.pushNamedAndRemoveUntil(page, predicate);
}
return global(id).currentState.pushNamedAndRemoveUntil(page, predicate);
}
/// It replaces Navigator.removeRoute, but needs no context.
static void removeRoute(route, {int id}) {
if (id == null) {
return key.currentState.removeRoute(route);
} else {
return global(id).currentState.removeRoute(route);
}
return global(id).currentState.removeRoute(route);
}
/// It replaces Navigator.pushNamedAndRemoveUntil, but needs no context.
... ... @@ -146,24 +115,25 @@ class Get {
{RoutePredicate predicate, arguments, int id}) {
var route = (Route<dynamic> rota) => false;
if (id == null) {
return key.currentState.pushNamedAndRemoveUntil(
newRouteName, predicate ?? route,
arguments: arguments);
} else {
return global(id).currentState.pushNamedAndRemoveUntil(
newRouteName, predicate ?? route,
arguments: arguments);
}
return global(id).currentState.pushNamedAndRemoveUntil(
newRouteName, predicate ?? route,
arguments: arguments);
}
static bool get isOverlaysOpen =>
(isSnackbarOpen || isDialogOpen || isBottomSheetOpen);
static bool get isOverlaysClosed =>
(!Get.isSnackbarOpen && !Get.isDialogOpen && !Get.isBottomSheetOpen);
/// It replaces Navigator.pop, but needs no context.
static void back({dynamic result, int id}) {
if (id == null) {
key.currentState.pop(result);
} else {
global(id).currentState.pop(result);
static void back({dynamic result, bool closeOverlays = false, int id}) {
if (closeOverlays && isOverlaysOpen) {
navigator.popUntil((route) {
return (isOverlaysClosed);
});
}
global(id).currentState.pop(result);
}
/// Experimental API to back from overlay
... ... @@ -172,12 +142,12 @@ class Get {
}
/// It will close as many screens as you define. Times must be> 0;
static void close(int times) {
static void close(int times, [int id]) {
if ((times == null) || (times < 1)) {
times = 1;
}
int count = 0;
void back = key.currentState.popUntil((route) {
void back = global(id).currentState.popUntil((route) {
return count++ == times;
});
return back;
... ... @@ -191,22 +161,13 @@ class Get {
Transition transition,
bool popGesture,
int id,
Duration duration = const Duration(milliseconds: 400)}) {
if (id == null) {
return key.currentState.pushReplacement(GetRoute(
opaque: opaque ?? true,
page: page,
popGesture: popGesture ?? _defaultPopGesture,
transition: transition ?? _defaultTransition,
transitionDuration: duration));
} else {
return global(id).currentState.pushReplacement(GetRoute(
opaque: opaque ?? true,
page: page,
popGesture: popGesture ?? _defaultPopGesture,
transition: transition ?? _defaultTransition,
transitionDuration: duration));
}
Duration duration}) {
return global(id).currentState.pushReplacement(GetRoute(
opaque: opaque ?? true,
page: page,
popGesture: popGesture ?? _defaultPopGesture,
transition: transition ?? _defaultTransition,
transitionDuration: duration ?? _defaultDurationTransition));
}
/// It replaces Navigator.pushAndRemoveUntil, but needs no context
... ... @@ -218,78 +179,44 @@ class Get {
Transition transition}) {
var route = (Route<dynamic> rota) => false;
if (id == null) {
return key.currentState.pushAndRemoveUntil(
GetRoute(
opaque: opaque ?? true,
popGesture: popGesture ?? _defaultPopGesture,
page: page,
transition: transition ?? _defaultTransition,
),
predicate ?? route);
} else {
return global(id).currentState.pushAndRemoveUntil(
GetRoute(
opaque: opaque ?? true,
popGesture: popGesture ?? _defaultPopGesture,
page: page,
transition: transition ?? _defaultTransition,
),
predicate ?? route);
}
return global(id).currentState.pushAndRemoveUntil(
GetRoute(
opaque: opaque ?? true,
popGesture: popGesture ?? _defaultPopGesture,
page: page,
transition: transition ?? _defaultTransition,
),
predicate ?? route);
}
/// Show a dialog. You can choose color and opacity of background
/// Show a dialog
static Future<T> dialog<T>(
Widget child, {
bool barrierDismissible = true,
// WidgetBuilder builder,
bool useRootNavigator = true,
RouteSettings routeSettings,
}) {
assert(child != null);
assert(useRootNavigator != null);
final ThemeData theme =
Theme.of(Get.key.currentContext, shadowThemeOnly: true);
return getShowGeneralDialog(
pageBuilder: (BuildContext buildContext, Animation<double> animation,
Animation<double> secondaryAnimation) {
final Widget pageChild = child; // ?? Builder(builder: builder);
return SafeArea(
child: Builder(builder: (BuildContext context) {
return theme != null
? Theme(data: theme, child: pageChild)
: pageChild;
}),
);
},
return showDialog(
barrierDismissible: barrierDismissible,
barrierLabel: MaterialLocalizations.of(Get.key.currentContext)
.modalBarrierDismissLabel,
barrierColor: Colors.black54,
transitionDuration: const Duration(milliseconds: 150),
// transitionBuilder: _buildMaterialDialogTransitions,
useRootNavigator: useRootNavigator,
routeSettings: routeSettings,
context: overlayContext,
builder: (_) {
return child;
},
);
}
static Future<T> defaultDialog<T>(
{Color color,
double opacity = 0.2,
String title = "Alert dialog",
{String title = "Alert dialog",
Widget content,
Widget cancel,
Widget confirm}) {
final child = DefaultDialogGet(
color: color,
opacity: opacity,
title: title,
return dialog(AlertDialog(
title: Text(title, textAlign: TextAlign.center),
content: content,
cancel: cancel,
confirm: confirm,
);
return dialog(child);
actions: <Widget>[cancel, confirm],
));
}
static Future<T> bottomSheet<T>({
... ... @@ -311,7 +238,7 @@ class Get {
assert(isDismissible != null);
assert(enableDrag != null);
return Get.key.currentState.push<T>(GetModalBottomSheetRoute<T>(
return navigator.push<T>(GetModalBottomSheetRoute<T>(
builder: builder,
theme: Theme.of(Get.key.currentContext, shadowThemeOnly: true),
isScrollControlled: isScrollControlled,
... ... @@ -421,6 +348,8 @@ class Get {
{bool enableLog,
bool defaultPopGesture,
bool defaultOpaqueRoute,
Duration defaultDurationTransition,
bool defaultGlobalState,
Transition defaultTransition}) {
if (enableLog != null) {
_enableLog = enableLog;
... ... @@ -434,6 +363,14 @@ class Get {
if (defaultTransition != null) {
_defaultTransition = defaultTransition;
}
if (defaultDurationTransition != null) {
_defaultDurationTransition = defaultDurationTransition;
}
if (defaultGlobalState != null) {
_defaultGlobalState = defaultGlobalState;
}
}
static Map<int, GlobalKey<NavigatorState>> _keys = {};
... ... @@ -443,14 +380,17 @@ class Get {
return _keys[key];
}
static GlobalKey<NavigatorState> global(int key) {
if (!_keys.containsKey(key)) {
static GlobalKey<NavigatorState> global(int k) {
if (k == null) {
return key;
}
if (!_keys.containsKey(k)) {
throw 'route id not found';
}
final recoverKey = _keys[key];
return recoverKey;
return _keys[k];
}
//////////// INSTANCE MANAGER
static Map<dynamic, dynamic> _singl = {};
/// Register a singleton instance of your class
... ... @@ -468,10 +408,13 @@ class Get {
return true;
}
/// check if instance is registred
static bool isRegistred<T>() => _singl.containsKey(T);
/// Recover a singleton instance of your class
static T find<T>(T key) {
static T find<T>() {
if (!_singl.containsKey(T)) {
throw 'key id not found';
throw 'key id ${T.runtimeType} not found';
}
final recoverKey = _singl[T];
return recoverKey;
... ... @@ -480,15 +423,30 @@ class Get {
/// give access to Routing API from GetObserver
static Routing get routing => _routing;
static RouteSettings get routeSettings => _settings;
static Routing _routing;
static Map<String, String> _parameters = {};
static setParameter(Map<String, String> param) {
_parameters = param;
}
static setRouting(Routing rt) {
_routing = rt;
}
static setSettings(RouteSettings settings) {
_settings = settings;
}
/// give current arguments
static get arguments => _routing.args;
/// give current arguments
static Map<String, String> get parameters => _parameters;
/// give arguments from previous route
static get previousArguments => _routing.previousArgs;
... ... @@ -513,6 +471,13 @@ class Get {
/// check if log is enable
static bool get isLogEnable => _enableLog;
/// default duration of transition animation
/// default duration work only API 2.0
static Duration get defaultDurationTransition => _defaultDurationTransition;
/// give global state of all GetState by default
static bool get defaultGlobalState => _defaultGlobalState;
/// check if popGesture is enable
static bool get isPopGestureEnable => _defaultPopGesture;
... ...
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get/src/routes/utils/parse_arguments.dart';
class GetMaterialApp extends StatefulWidget {
const GetMaterialApp({
Key key,
this.navigatorKey,
this.home,
this.routes = const <String, WidgetBuilder>{},
this.initialRoute,
this.onGenerateRoute,
this.onGenerateInitialRoutes,
this.onUnknownRoute,
this.navigatorObservers = const <NavigatorObserver>[],
this.builder,
this.title = '',
this.onGenerateTitle,
this.color,
this.theme,
this.darkTheme,
this.themeMode = ThemeMode.system,
this.locale,
this.localizationsDelegates,
this.localeListResolutionCallback,
this.localeResolutionCallback,
this.supportedLocales = const <Locale>[Locale('en', 'US')],
this.debugShowMaterialGrid = false,
this.showPerformanceOverlay = false,
this.checkerboardRasterCacheImages = false,
this.checkerboardOffscreenLayers = false,
this.showSemanticsDebugger = false,
this.debugShowCheckedModeBanner = true,
this.shortcuts,
this.routingCallback,
this.defaultTransition,
this.actions,
this.opaqueRoute,
this.enableLog,
this.popGesture,
this.transitionDuration,
this.defaultGlobalState,
this.namedRoutes,
this.unknownRoute,
}) : assert(routes != null),
assert(navigatorObservers != null),
assert(title != null),
assert(debugShowMaterialGrid != null),
assert(showPerformanceOverlay != null),
assert(checkerboardRasterCacheImages != null),
assert(checkerboardOffscreenLayers != null),
assert(showSemanticsDebugger != null),
assert(debugShowCheckedModeBanner != null),
super(key: key);
final GlobalKey<NavigatorState> navigatorKey;
final Widget home;
final Map<String, WidgetBuilder> routes;
final String initialRoute;
final RouteFactory onGenerateRoute;
final InitialRouteListFactory onGenerateInitialRoutes;
final RouteFactory onUnknownRoute;
final List<NavigatorObserver> navigatorObservers;
final TransitionBuilder builder;
final String title;
final GenerateAppTitle onGenerateTitle;
final ThemeData theme;
final ThemeData darkTheme;
final ThemeMode themeMode;
final Color color;
final Locale locale;
final Iterable<LocalizationsDelegate<dynamic>> localizationsDelegates;
final LocaleListResolutionCallback localeListResolutionCallback;
final LocaleResolutionCallback localeResolutionCallback;
final Iterable<Locale> supportedLocales;
final bool showPerformanceOverlay;
final bool checkerboardRasterCacheImages;
final bool checkerboardOffscreenLayers;
final bool showSemanticsDebugger;
final bool debugShowCheckedModeBanner;
final Map<LogicalKeySet, Intent> shortcuts;
final Map<LocalKey, ActionFactory> actions;
final bool debugShowMaterialGrid;
final Function(Routing) routingCallback;
final Transition defaultTransition;
final bool opaqueRoute;
final bool enableLog;
final bool popGesture;
final Duration transitionDuration;
final bool defaultGlobalState;
final Map<String, GetRoute> namedRoutes;
final GetRoute unknownRoute;
@override
_GetMaterialAppState createState() => _GetMaterialAppState();
}
class _GetMaterialAppState extends State<GetMaterialApp> {
ParseRoute parse = ParseRoute();
@override
void initState() {
if (widget.namedRoutes != null) {
widget.namedRoutes.forEach((key, value) {
parse.addRoute(key);
});
}
Get.config(
enableLog: widget.enableLog ?? Get.isLogEnable,
defaultTransition: widget.defaultTransition ?? Get.defaultTransition,
defaultOpaqueRoute: widget.opaqueRoute ?? Get.isOpaqueRouteDefault,
defaultPopGesture: widget.popGesture ?? Get.isPopGestureEnable,
defaultDurationTransition:
widget.transitionDuration ?? Get.defaultDurationTransition,
defaultGlobalState: widget.defaultGlobalState ?? Get.defaultGlobalState,
);
super.initState();
}
Route<dynamic> namedRoutesGenerate(RouteSettings settings) {
Get.setSettings(settings);
final parsedString = parse.split(settings.name);
String settingsname = parsedString.route;
Map<String, GetRoute> newNamedRoutes = {};
widget.namedRoutes.forEach((key, value) {
String newName = parse.split(key).route;
newNamedRoutes.addAll({newName: value});
});
if (newNamedRoutes.containsKey(settingsname)) {
Get.setParameter(parsedString.parameters);
return GetRoute(
page: newNamedRoutes[settingsname].page,
title: newNamedRoutes[settingsname].title,
parameter: parsedString.parameters,
settings:
RouteSettings(name: settings.name, arguments: settings.arguments),
maintainState: newNamedRoutes[settingsname].maintainState,
curve: newNamedRoutes[settingsname].curve,
alignment: newNamedRoutes[settingsname].alignment,
opaque: newNamedRoutes[settingsname].opaque,
transitionDuration: (widget.transitionDuration == null
? newNamedRoutes[settingsname].transitionDuration
: widget.transitionDuration),
transition: newNamedRoutes[settingsname].transition,
popGesture: newNamedRoutes[settingsname].popGesture,
fullscreenDialog: newNamedRoutes[settingsname].fullscreenDialog,
);
} else {
return (widget.unknownRoute ??
GetRoute(
page: Scaffold(
body: Center(
child: Text("Route not found :("),
),
)));
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: (widget.navigatorKey == null
? Get.key
: Get.addKey(widget.navigatorKey)),
home: widget.home,
routes: widget.routes ?? const <String, WidgetBuilder>{},
initialRoute: widget.initialRoute,
onGenerateRoute: (widget.namedRoutes == null
? widget.onGenerateRoute
: namedRoutesGenerate),
onGenerateInitialRoutes: widget.onGenerateInitialRoutes,
onUnknownRoute: widget.onUnknownRoute,
navigatorObservers: (widget.navigatorObservers == null
? <NavigatorObserver>[GetObserver(widget.routingCallback)]
: <NavigatorObserver>[GetObserver(widget.routingCallback)]
..addAll(widget.navigatorObservers)),
builder: widget.builder,
title: widget.title ?? '',
onGenerateTitle: widget.onGenerateTitle,
color: widget.color,
theme: widget.theme,
darkTheme: widget.darkTheme,
themeMode: widget.themeMode ?? ThemeMode.system,
locale: widget.locale,
localizationsDelegates: widget.localizationsDelegates,
localeListResolutionCallback: widget.localeListResolutionCallback,
localeResolutionCallback: widget.localeResolutionCallback,
supportedLocales:
widget.supportedLocales ?? const <Locale>[Locale('en', 'US')],
debugShowMaterialGrid: widget.debugShowMaterialGrid ?? false,
showPerformanceOverlay: widget.showPerformanceOverlay ?? false,
checkerboardRasterCacheImages:
widget.checkerboardRasterCacheImages ?? false,
checkerboardOffscreenLayers: widget.checkerboardOffscreenLayers ?? false,
showSemanticsDebugger: widget.showSemanticsDebugger ?? false,
debugShowCheckedModeBanner: widget.debugShowCheckedModeBanner ?? true,
shortcuts: widget.shortcuts,
actions: widget.actions,
);
}
}
... ...
import 'dart:math' as math;
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
class RippleBackdropAnimatePage extends StatefulWidget {
const RippleBackdropAnimatePage({
Key key,
this.child,
this.childFade = false,
this.duration = 300,
this.blurRadius = 15.0,
this.bottomButton,
this.bottomHeight = kBottomNavigationBarHeight,
this.bottomButtonRotate = true,
this.bottomButtonRotateDegree = 45.0,
}) : super(key: key);
/// Child for page.
final Widget child;
/// When enabled, [child] will fade in when animation is going and fade out when popping.
/// [false] is by default.
final bool childFade;
/// Animation's duration,
/// including [Navigator.push], [Navigator.pop].
final int duration;
/// Blur radius for [BackdropFilter].
final double blurRadius;
/// [Widget] for bottom of the page.
final Widget bottomButton;
/// The height which [bottomButton] will occupy.
/// [kBottomNavigationBarHeight] is by default.
final double bottomHeight;
/// When enabled, [bottomButton] will rotate when to animation is going.
/// [true] is by default.
final bool bottomButtonRotate;
/// The degree which [bottomButton] will rotate.
/// 45.0 is by default.
final double bottomButtonRotateDegree;
@override
_RippleBackdropAnimatePageState createState() =>
_RippleBackdropAnimatePageState();
}
class _RippleBackdropAnimatePageState extends State<RippleBackdropAnimatePage>
with TickerProviderStateMixin {
/// Boolean to prevent duplicate pop.
bool _popping = false;
/// Animation.
int _animateDuration;
double _backdropFilterSize = 0.0;
double _popButtonOpacity = 0.0;
double _popButtonRotateAngle = 0.0;
Animation<double> _backDropFilterAnimation;
AnimationController _backDropFilterController;
Animation<double> _popButtonAnimation;
AnimationController _popButtonController;
Animation<double> _popButtonOpacityAnimation;
AnimationController _popButtonOpacityController;
@override
void initState() {
_animateDuration = widget.duration;
SchedulerBinding.instance
.addPostFrameCallback((_) => backDropFilterAnimate(context, true));
super.initState();
}
@override
void dispose() {
_backDropFilterController?.dispose();
_popButtonController?.dispose();
super.dispose();
}
double pythagoreanTheorem(double short, double long) {
return math.sqrt(math.pow(short, 2) + math.pow(long, 2));
}
void popButtonAnimate(context, bool forward) {
if (!forward) {
_popButtonController?.stop();
_popButtonOpacityController?.stop();
}
final double rotateDegree =
widget.bottomButtonRotateDegree * (math.pi / 180) * 3;
_popButtonOpacityController = _popButtonController = AnimationController(
duration: Duration(milliseconds: _animateDuration),
vsync: this,
);
Animation _popButtonCurve = CurvedAnimation(
parent: _popButtonController,
curve: Curves.easeInOut,
);
_popButtonAnimation = Tween(
begin: forward ? 0.0 : _popButtonRotateAngle,
end: forward ? rotateDegree : 0.0,
).animate(_popButtonCurve)
..addListener(() {
setState(() {
_popButtonRotateAngle = _popButtonAnimation.value;
});
});
_popButtonOpacityAnimation = Tween(
begin: forward ? 0.0 : _popButtonOpacity,
end: forward ? 1.0 : 0.0,
).animate(_popButtonCurve)
..addListener(() {
setState(() {
_popButtonOpacity = _popButtonOpacityAnimation.value;
});
});
_popButtonController.forward();
_popButtonOpacityController.forward();
}
Future backDropFilterAnimate(BuildContext context, bool forward) async {
final MediaQueryData m = MediaQuery.of(context);
final Size s = m.size;
final double r =
pythagoreanTheorem(s.width, s.height * 2 + m.padding.top) / 2;
if (!forward) _backDropFilterController?.stop();
popButtonAnimate(context, forward);
_backDropFilterController = AnimationController(
duration: Duration(milliseconds: _animateDuration),
vsync: this,
);
Animation _backDropFilterCurve = CurvedAnimation(
parent: _backDropFilterController,
curve: forward ? Curves.easeInOut : Curves.easeIn,
);
_backDropFilterAnimation = Tween(
begin: forward ? 0.0 : _backdropFilterSize,
end: forward ? r * 2 : 0.0,
).animate(_backDropFilterCurve)
..addListener(() {
setState(() {
_backdropFilterSize = _backDropFilterAnimation.value;
});
});
await _backDropFilterController.forward();
}
Widget popButton() {
Widget button = widget.bottomButton ?? Icon(Icons.add, color: Colors.grey);
if (widget.bottomButtonRotate) {
button = Transform.rotate(
angle: _popButtonRotateAngle,
child: button,
);
}
button = Opacity(
opacity: _popButtonOpacity,
child: SizedBox(
width: widget.bottomHeight,
height: widget.bottomHeight,
child: Center(
child: GestureDetector(
behavior: HitTestBehavior.opaque,
child: button,
onTap: willPop,
),
),
),
);
return button;
}
Widget wrapper(context, {Widget child}) {
final MediaQueryData m = MediaQuery.of(context);
final Size s = m.size;
final double r =
pythagoreanTheorem(s.width, s.height * 2 + m.padding.top) / 2;
final double topOverflow = r - s.height;
final double horizontalOverflow = r - s.width;
return Stack(
overflow: Overflow.visible,
children: <Widget>[
Positioned(
left: -horizontalOverflow,
right: -horizontalOverflow,
top: -topOverflow,
bottom: -r,
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: willPop,
child: Center(
child: SizedBox(
width: _backdropFilterSize,
height: _backdropFilterSize,
child: ClipRRect(
borderRadius: BorderRadius.circular(r * 2),
child: BackdropFilter(
filter: ui.ImageFilter.blur(
sigmaX: widget.blurRadius,
sigmaY: widget.blurRadius,
),
child: Text(" "),
),
),
),
),
),
),
Align(
alignment: Alignment.topCenter,
child: Container(
margin: EdgeInsets.only(top: topOverflow + 10),
width: s.width,
height: s.height,
constraints: BoxConstraints(
maxWidth: s.width,
maxHeight: s.height,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Expanded(
child: Opacity(
opacity: widget.childFade ? _popButtonOpacity : 1.0,
child: child,
),
),
popButton(),
],
),
),
),
],
);
}
Future<bool> willPop() async {
await backDropFilterAnimate(context, false);
if (!_popping) {
_popping = true;
await Future.delayed(Duration(milliseconds: _animateDuration), () {
Navigator.of(context).pop();
});
}
return null;
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.transparent,
body: WillPopScope(
onWillPop: willPop,
child: wrapper(
context,
child: widget.child,
),
),
);
}
}
import 'package:flutter/material.dart';
class TransparentRoute extends PageRoute<void> {
TransparentRoute({
@required this.builder,
RouteSettings settings,
}) : assert(builder != null),
super(settings: settings, fullscreenDialog: false);
final WidgetBuilder builder;
@override
bool get opaque => false;
@override
Color get barrierColor => null;
@override
String get barrierLabel => null;
@override
bool get maintainState => true;
@override
Duration get transitionDuration => Duration.zero;
@override
Widget buildPage(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
final result = builder(context);
return Semantics(
scopesRoute: true,
explicitChildNodes: true,
child: result,
);
}
}
... ... @@ -19,8 +19,6 @@ const int _kMaxDroppedSwipePageForwardAnimationTime = 800; // Milliseconds.
const int _kMaxPageBackAnimationTime = 300;
class GetRoute<T> extends PageRoute<T> {
/// Creates a page route for use in an iOS designed app.
///
/// The [builder], [maintainState], and [fullscreenDialog] arguments must not
/// be null.
GetRoute({
... ... @@ -30,6 +28,7 @@ class GetRoute<T> extends PageRoute<T> {
this.maintainState = true,
this.curve = Curves.linear,
this.alignment,
this.parameter,
this.opaque = true,
this.transitionDuration = const Duration(milliseconds: 400),
this.popGesture,
... ... @@ -49,6 +48,8 @@ class GetRoute<T> extends PageRoute<T> {
// final Duration duration;
final Map<String, String> parameter;
final String title;
final Transition transition;
... ... @@ -231,7 +232,6 @@ class GetRoute<T> extends PageRoute<T> {
Animation<double> secondaryAnimation,
Widget child,
Transition tr,
Duration duration,
Curve curve,
Alignment alignment,
) {
... ... @@ -472,7 +472,6 @@ class GetRoute<T> extends PageRoute<T> {
secondaryAnimation,
child,
transition,
transitionDuration,
curve,
alignment);
}
... ...
... ... @@ -100,6 +100,7 @@ class GetObserver extends NavigatorObserver {
void didReplace({Route newRoute, Route oldRoute}) {
super.didReplace(newRoute: newRoute, oldRoute: oldRoute);
if (Get.isLogEnable) print("[REPLACE ROUTE] ${oldRoute?.settings?.name}");
if (Get.isLogEnable) print("[NEW ROUTE] ${newRoute?.settings?.name}");
final routeSend = Routing(
removed: null, // add '${oldRoute?.settings?.name}' or remain null ???
... ...
import 'package:flutter/material.dart';
class ParseRoute {
final List<ParseRouteSplit> _routeSplits = <ParseRouteSplit>[];
void addRoute(String routePath) {
String path = routePath;
if (path == Navigator.defaultRouteName) {
var routeSplit = ParseRouteSplit(path, ParseRouteSplitType.component);
routeSplit.routes = [routePath];
_routeSplits.add(routeSplit);
return;
}
if (path.startsWith("/")) {
path = path.substring(1);
}
List<String> pathComponents = path.split('/');
ParseRouteSplit parent;
for (int i = 0; i < pathComponents.length; i++) {
String component = pathComponents[i];
ParseRouteSplit routeSplit = _routeSplitForComponent(component, parent);
if (routeSplit == null) {
ParseRouteSplitType type = _typeForComponent(component);
routeSplit = ParseRouteSplit(component, type);
routeSplit.parent = parent;
if (parent == null) {
_routeSplits.add(routeSplit);
} else {
parent.routeSplits.add(routeSplit);
}
}
if (i == pathComponents.length - 1) {
if (routeSplit.routes == null) {
routeSplit.routes = [routePath];
} else {
routeSplit.routes.add(routePath);
}
}
parent = routeSplit;
}
}
AppRouteMatch split(String path) {
String usePath = path;
if (usePath.startsWith("/")) {
usePath = path.substring(1);
}
List<String> components = usePath.split("/");
if (path == Navigator.defaultRouteName) {
components = ["/"];
}
Map<ParseRouteSplit, ParseRouteSplitMatch> routeSplitMatches =
<ParseRouteSplit, ParseRouteSplitMatch>{};
List<ParseRouteSplit> routeSplitsToCheck = _routeSplits;
for (String checkComponent in components) {
Map<ParseRouteSplit, ParseRouteSplitMatch> currentMatches =
<ParseRouteSplit, ParseRouteSplitMatch>{};
List<ParseRouteSplit> nextrouteSplits = <ParseRouteSplit>[];
for (ParseRouteSplit routeSplit in routeSplitsToCheck) {
String pathPart = checkComponent;
Map<String, String> queryMap = {};
if (checkComponent.contains("?") && !checkComponent.contains("=")) {
var splitParam = checkComponent.split("?");
pathPart = splitParam[0];
queryMap = {pathPart: splitParam[1]};
} else if (checkComponent.contains("?")) {
var splitParam = checkComponent.split("?");
var splitParam2 = splitParam[1].split("=");
if (!splitParam2[1].contains("&")) {
pathPart = splitParam[0];
queryMap = {splitParam2[0]: splitParam2[1]};
} else {
pathPart = splitParam[0];
final segunda = splitParam[1];
var other = segunda.split(RegExp(r"[&,=]"));
for (var i = 0; i < (other.length - 1); i++) {
bool impar = (i % 2 == 0);
if (impar) {
queryMap.addAll({other[0 + i]: other[1 + i]});
}
}
}
}
bool isMatch =
(routeSplit.part == pathPart || routeSplit.isParameter());
if (isMatch) {
ParseRouteSplitMatch parentMatch =
routeSplitMatches[routeSplit.parent];
ParseRouteSplitMatch match =
ParseRouteSplitMatch.fromMatch(parentMatch, routeSplit);
if (routeSplit.isParameter()) {
String paramKey = routeSplit.part.substring(1);
match.parameters[paramKey] = pathPart;
}
if (queryMap != null) {
match.parameters.addAll(queryMap);
}
currentMatches[routeSplit] = match;
if (routeSplit.routeSplits != null) {
nextrouteSplits.addAll(routeSplit.routeSplits);
}
}
}
routeSplitMatches = currentMatches;
routeSplitsToCheck = nextrouteSplits;
if (currentMatches.values.length == 0) {
return null;
}
}
List<ParseRouteSplitMatch> matches = routeSplitMatches.values.toList();
if (matches.length > 0) {
ParseRouteSplitMatch match = matches.first;
ParseRouteSplit routeSplitToUse = match.routeSplit;
if (routeSplitToUse != null &&
routeSplitToUse.routes != null &&
routeSplitToUse.routes.length > 0) {
AppRouteMatch routeMatch = AppRouteMatch();
routeMatch.parameters = match.parameters;
if (routeSplitToUse.isParameter()) {
routeMatch.route = match.routeSplit.parent.part;
} else {
routeMatch.route = match.routeSplit.part;
}
return routeMatch;
}
}
return null;
}
ParseRouteSplit _routeSplitForComponent(
String component, ParseRouteSplit parent) {
List<ParseRouteSplit> routeSplits = _routeSplits;
if (parent != null) {
routeSplits = parent.routeSplits;
}
for (ParseRouteSplit routeSplit in routeSplits) {
if (routeSplit.part == component) {
return routeSplit;
}
}
return null;
}
ParseRouteSplitType _typeForComponent(String component) {
ParseRouteSplitType type = ParseRouteSplitType.component;
if (_isParameterComponent(component)) {
type = ParseRouteSplitType.parameter;
}
return type;
}
bool _isParameterComponent(String component) {
return component.startsWith(":");
}
}
enum ParseRouteSplitType {
component,
parameter,
}
class AppRouteMatch {
Map<String, String> parameters = <String, String>{};
String route = '/';
}
class ParseRouteSplitMatch {
ParseRouteSplitMatch(this.routeSplit);
ParseRouteSplitMatch.fromMatch(ParseRouteSplitMatch match, this.routeSplit) {
parameters = <String, String>{};
if (match != null) {
parameters.addAll(match.parameters);
}
}
ParseRouteSplit routeSplit;
Map<String, String> parameters = <String, String>{};
}
class ParseRouteSplit {
ParseRouteSplit(this.part, this.type);
String part;
ParseRouteSplitType type;
List<String> routes = [];
List<ParseRouteSplit> routeSplits = <ParseRouteSplit>[];
ParseRouteSplit parent;
bool isParameter() {
return type == ParseRouteSplitType.parameter;
}
}
... ...
import 'package:flutter/material.dart';
import '../get_main.dart';
class GetController extends State {
Map<GetController, State> _allStates = {};
/// Update GetBuilder with update(this)
void update(GetController id) {
if (id != null) {
final State state = _allStates[id];
if (state != null && state.mounted) state.setState(() {});
}
}
@override
Widget build(_) => throw ("build method can't be called");
}
class GetBuilder<T extends GetController> extends StatefulWidget {
@required
final Widget Function(T) builder;
final bool global;
final bool autoRemove;
final void Function(State state) initState, dispose, didChangeDependencies;
final void Function(GetBuilder oldWidget, State state) didUpdateWidget;
final T controller;
GetBuilder({
Key key,
this.controller,
this.global = true,
this.builder,
this.autoRemove = true,
this.initState,
this.dispose,
this.didChangeDependencies,
this.didUpdateWidget,
}) : assert(builder != null, controller != null),
super(key: key);
@override
_GetBuilderState<T> createState() => _GetBuilderState<T>();
}
class _GetBuilderState<T extends GetController> extends State<GetBuilder<T>> {
T controller;
@override
void initState() {
super.initState();
if (widget.global) {
if (Get.isRegistred<T>()) {
controller = Get.find<T>();
} else {
controller = widget.controller;
controller._allStates[controller] = this;
Get.put(controller);
}
} else {
controller = widget.controller;
controller._allStates[controller] = this;
}
if (widget.initState != null) widget.initState(this);
}
@override
void dispose() {
if (controller != null) {
var b = controller;
if (b._allStates[controller].hashCode == this.hashCode) {
b._allStates.remove(controller);
}
}
if (widget.dispose != null) widget.dispose(this);
if (widget.autoRemove && Get.isRegistred<T>()) {
Get.delete(controller);
}
super.dispose();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
if (widget.didChangeDependencies != null)
widget.didChangeDependencies(this);
}
@override
void didUpdateWidget(GetBuilder oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.didUpdateWidget != null) widget.didUpdateWidget(oldWidget, this);
}
@override
Widget build(BuildContext context) {
return widget.builder(controller);
}
}
... ...
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
archive:
dependency: transitive
description:
name: archive
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.13"
args:
dependency: transitive
description:
name: args
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.0"
async:
dependency: transitive
description:
... ... @@ -29,6 +43,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.14.12"
convert:
dependency: transitive
description:
name: convert
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.4"
flutter:
dependency: "direct main"
description: flutter
... ... @@ -39,6 +67,13 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
image:
dependency: transitive
description:
name: image
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.12"
matcher:
dependency: transitive
description:
... ... @@ -60,6 +95,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.6.4"
petitparser:
dependency: transitive
description:
name: petitparser
url: "https://pub.dartlang.org"
source: hosted
version: "2.4.0"
quiver:
dependency: transitive
description:
... ... @@ -128,5 +170,12 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.8"
xml:
dependency: transitive
description:
name: xml
url: "https://pub.dartlang.org"
source: hosted
version: "3.6.1"
sdks:
dart: ">=2.6.0 <3.0.0"
... ...
name: get
description: Navigate between screens, display snackbars, dialogs and bottomSheets, from anywhere in your code without context with Get.
version: 1.20.0-dev
version: 2.0.0-dev
homepage: https://github.com/jonataslaw/get
environment:
... ...