jonataslaw

Update to version 3.0

## [3.0.1]
- Breaking changes on Rx api and GetController and RxController were merged, and now you only have the 'GetxController'
- Refactor routing system. Now you can add custom transitions and more
- Improved the use of dynamic routes, you can now define two different pages according to your arguments.
- Added GetView widget
- Added internacionalization
- Added validations
- Added Get queqe
- Added GetStorage (with separated package)
- Minor bug fixes.
## [2.14.0]
- Added getPages API.
- Deprecated namedPages
... ... @@ -12,7 +24,7 @@
## [2.13.0]
- Update docs
- Fix Bindings list on GetRouteBase
- Fix Bindings list on GetPageRoute
## [2.12.5]
- Update readme
... ... @@ -64,7 +76,7 @@ Get.lazyPut () will not receive this resource. Initially he had it, but we saw i
## [2.10.0]
- Added SmartManagement, your application's memory is managed intelligently like never before!
- Added Obx, a widget that knows when to rebuild a child, without needing any type.
- Added MIxinBuilder - If you need to use GetBuilder in conjunction with GetX, use GetController with this widget, and the changes will occur either using update (this) or changing some reactive variable. Use only if necessary, for better RAM consumption, prefer widgets in that order:
- Added MIxinBuilder - If you need to use GetBuilder in conjunction with GetX, use GetxController with this widget, and the changes will occur either using update (this) or changing some reactive variable. Use only if necessary, for better RAM consumption, prefer widgets in that order:
Obx => GetX => GetBuilder => MixinBuilder.
Obx is the lightest of all, and MixinBuilder is a mix of the other 3, whenever possible, use the specific widget.
- Refactor: refactor StateManager of Get.
... ...
... ... @@ -10,7 +10,7 @@
</a>
<a href="https://www.buymeacoffee.com/jonataslaw" target="_blank"><img src="https://i.imgur.com/aV6DDA7.png" alt="Buy Me A Coffee" style="height: 41px !important;width: 174px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" > </a>
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
[![All Contributors](https://img.shields.io/badge/all_contributors-5-orange.svg?style=flat-square)](#contributors-)
[![All Contributors](https://img.shields.io/badge/all_contributors-4-orange.svg?style=flat-square)](#contributors-)
<!-- ALL-CONTRIBUTORS-BADGE:END -->
... ... @@ -33,7 +33,7 @@ Create your business logic class and place all variables, methods and controller
You can make any variable observable using a simple ".obs".
```dart
class Controller extends RxController{
class Controller extends GetxController{
var count = 0.obs;
increment() => count.value++;
}
... ... @@ -112,6 +112,7 @@ This is a simple project but it already makes clear how powerful Get is. As your
- [Change Theme](#change-theme)
- [Other Advanced APIs and Manual configurations](#other-advanced-apis-and-manual-configurations)
- [Optional Global Settings](#optional-global-settings)
- [Breaking changes from 2.0](#breaking-changes-from-2.0)
*Want to contribute to the project? We will be proud to highlight you as one of our collaborators. Here are some points where you can contribute and make Get (and Flutter) even better.*
... ... @@ -237,20 +238,14 @@ void main() {
GetMaterialApp(
initialRoute: '/',
getPages: [
GetPage(
name: '/',
page: () => MyHomePage(),
),
GetPage(
name: '/second',
page: () => Second(),
),
GetPage(
name: '/third',
page: () => Third(),
transition: Transition.cupertino
),
],
GetPage(name: '/', page: () => MyHomePage()),
GetPage(name: '/second', page: () => Second()),
GetPage(
name: '/third',
page: () => Third(),
transition: Transition.zoom
),
],
)
);
}
... ... @@ -297,12 +292,13 @@ void main() {
page: () => MyHomePage(),
),
GetPage(
/// Important! :user is not a new route, it is just a parameter
/// specification. Do not use '/second/:user' and '/second'
/// if you need new route to user, use '/second/user/:user'
/// if '/second' is a route.
name: '/second/:user',
page: () => Second(),
name: '/profile/',
page: () => MyProfile(),
),
//You can define a different page for routes with arguments, and another without arguments, but for that you must use the slash '/' on the route that will not receive arguments as above.
GetPage(
name: '/profile/:user',
page: () => UserProfile(),
),
GetPage(
name: '/third',
... ... @@ -333,7 +329,7 @@ And now, all you need to do is use Get.toNamed() to navigate your named routes,
If you want listen Get events to trigger actions, you can to use routingCallback to it
```dart
GetMaterialApp(
routingCallback: (route) {
routingCallback: (routing) {
if(routing.current == '/second'){
openAds();
}
... ... @@ -449,7 +445,8 @@ class Third extends StatelessWidget {
### SnackBars
To have a simple SnackBar with Flutter, you must get the context of Scaffold, or you must use a GlobalKey attached to your Scaffold,
To have a simple SnackBar with Flutter, you must get the context of Scaffold, or you must use a GlobalKey attached to your Scaffold
```dart
final snackBar = SnackBar(
content: Text('Hi!'),
... ... @@ -584,7 +581,7 @@ Navigator(
initialRoute: '/',
onGenerateRoute: (settings) {
if (settings.name == '/') {
return GetRouteBase(
return GetPageRoute(
page: Scaffold(
appBar: AppBar(
title: Text("Main"),
... ... @@ -601,7 +598,7 @@ Navigator(
),
);
} else if (settings.name == '/second') {
return GetRouteBase(
return GetPageRoute(
page: Center(
child: Scaffold(
appBar: AppBar(
... ... @@ -658,8 +655,8 @@ Get has a state manager that is extremely light and easy, which does not use Cha
### Usage
```dart
// Create controller class and extends GetController
class Controller extends GetController {
// Create controller class and extends GetxController
class Controller extends GetxController {
int counter = 0;
void increment() {
counter++;
... ... @@ -700,7 +697,7 @@ class OtherClass extends StatelessWidget {
If you need to use your controller in many other places, and outside of GetBuilder, just create a get in your controller and have it easily. (or use `Get.find<Controller>()`)
```dart
class Controller extends GetController {
class Controller extends GetxController {
/// You do not need that. I recommend using it just for ease of syntax.
/// with static method: Controller.to.counter();
... ... @@ -768,10 +765,10 @@ So to simplify this:
You don't need to call methods in initState and send them by parameter to your controller, nor use your controller constructor for that, you have the onInit() method that is called at the right time for you to start your services.
You do not need to call the device, you have the onClose() method that will be called at the exact moment when your controller is no longer needed and will be removed from memory. That way, leave views for widgets only, refrain from any kind of business logic from it.
Do not call a dispose method inside GetController, it will not do anything, remember that the controller is not a Widget, you should not "dispose" it, and it will be automatically and intelligently removed from memory by Get. If you used any stream on it and want to close it, just insert it into the close method. Example:
Do not call a dispose method inside GetxController, it will not do anything, remember that the controller is not a Widget, you should not "dispose" it, and it will be automatically and intelligently removed from memory by Get. If you used any stream on it and want to close it, just insert it into the close method. Example:
```dart
class Controller extends GetController {
class Controller extends GetxController {
StreamController<User> user = StreamController<User>();
StreamController<String> name = StreamController<String>();
... ... @@ -804,7 +801,7 @@ GetBuilder<Controller>(
You may also need an instance of your controller outside of your GetBuilder, and you can use these approaches to achieve this:
```dart
class Controller extends GetController {
class Controller extends GetxController {
static Controller get to => Get.find();
[...]
}
... ... @@ -818,7 +815,7 @@ GetBuilder<Controller>(
```
or
```dart
class Controller extends GetController {
class Controller extends GetxController {
// static Controller get to => Get.find(); // with no static get
[...]
}
... ... @@ -870,6 +867,34 @@ GetX does this automatically and only reconstructs the widget that uses the exac
## Reactive State Manager
Reactive programming can alienate many people because it is said to be complicated. Getx turns reactive programming into something so simple, that it can be used and learned by those who started at that very moment in Flutter. No, you will not need to create StreamControllers. You also won't need to create a StreamBuilder for each variable. You will not need to create a class for each state. You will not need to create a get for an initial value. Reactive programming with Get is as easy as using setState (or even easier!).
Let's imagine that you have a name variable and want that every time you change it, all widgets that use it are automatically changed.
This is your count variable:
```dart
var name = 'Jonatas Borges';
```
To make it observable, you just need to add ".obs" to the end of it:
```dart
var name = 'Jonatas Borges'.obs;
```
This borders on absurdity when it comes to practicality. What did we do under the hood? We created a stream of Strings, assigned the initial value "Jonatas Borges", we warn all widgets that use "Jonatas Borges" that they now belong to this variable, and when it is changed, they will be changed too. This is the magic of Get, that only dart allows us to do this.
Okay, but as we know, a widget can only be changed if it is inside a function, because static classes do not have the power to "auto-change". You will need to create a StreamBuilder, subscribe to listen to this variable, and create a "cascade" of StreamBuilder if you want to change several variables in the same scope, right?
No, you don't need a StreamBuilder, but you are right about static classes.
Well, in the view we usually have a lot of boilerplate when we want to change a specific widget. With Get you can also forget about this Boilerplate. StreamBuilder? initialValue? builder?
No, you just need to play this variable inside an Obx widget.
```dart
Obx (() => Text (controller.name));
```
What do you need to memorize? "Obx(() =>" You are just passing that widget through an arrow-function into an Obx. Obx is smart, and will only be changed if the value of name is changed. If name is "John" and you change it to "John", it will not have any changes on the screen, and Obx will simply ignore this change, and will not rebuild the widget, to save resources. Isn't that amazing?
What if I have 5 observable variables within an Obx? It will update when any of them are changed. And if I have 30 variables in a class, when I update one, will it update all variables that are in that class? No, just the specific widget that uses that variable. And if I machine-gun my observable variable 1 billion times with the same value, will I have freeze on the screen for unnecessary reconstructions? No, GetX only updates the screen when the variable changes on the screen, if the screen remains the same, it will not reconstruct anything.
### Advantages
GetBuilder is aimed precisely at multiple state control. Imagine that you added 30 products to a cart, you click delete one, at the same time that the list is updated, the price is updated and the badge in the shopping cart is updated to a smaller number. This type of approach makes GetBuilder killer, because it groups states and changes them all at once without any "computational logic" for that. GetBuilder was created with this type of situation in mind, since for ephemeral change of state, you can use setState and you would not need a state manager for this. However, there are situations where you want only the widget where a certain variable has been changed to be rebuilt, and this is what GetX does with a mastery never seen before.
... ... @@ -887,6 +912,29 @@ The state only changes if the values ​​change. That's the main difference be
### Usage
You have 3 ways to turn a variable into an observable.
The first is using Rx{Type}.
```dart
var count = RxString();
```
The second is to use Rx and type it with `Rx<Type>`
```dart
var count = Rx<String>();
```
The third, more practical, easy, and incredible approach, is just to add an .obs to your variable.
```dart
var count = 0.obs;
// or Rxint count = 0.obs;
// or Rx<int> count = 0.obs;
```
As we know, Dart is now heading towards null safety. With that it is a good idea, from now on, you start to use your variables always with an initial value. Transforming a variable into an observable with an initial value with Get is the simplest and most practical approach that currently exists in Flutter. You will literally add a ".obs" to the end of your variable, and that’s it, you’ve made it observable, and its value will be the initial value, this is fantastic!
You can add variables, and if you want to type your widget to get your controller inside, you just need to use GetX widget instead of Obx
```dart
final count1 = 0.obs;
final count2 = 0.obs;
... ... @@ -895,9 +943,9 @@ int get sum => count1.value + count2.value;
```dart
GetX<Controller>(
builder: (_) {
builder: (value) {
print("count 1 rebuild");
return Text('${_.count1.value}');
return Text('${value.count1.value}');
},
),
GetX<Controller>(
... ... @@ -959,7 +1007,7 @@ Without decorations, without a code generator, without complications, GetX will
Do you know Flutter's counter app? Your Controller class might look like this:
```dart
class CountCtl extends RxController {
class CountCtl extends GetxController {
final count = 0.obs;
}
```
... ... @@ -1074,9 +1122,7 @@ interval(count1, (_) => print("interval $_"), time: Duration(seconds: 1));
## Mixing the two state managers
Some people opened a feature request, as they wanted to use only one type of reactive variable, and the other mechanics, and needed to insert an Obx into a GetBuilder for this. Thinking about it MixinBuilder was created. It allows both reactive changes by changing ".obs" variables, and mechanical updates via update(). However, of the 4 widgets he is the one that consumes the most resources, since in addition to having a Subscription to receive change events from his children, he subscribes to the update method of his controller.
- Note: To use GetBuilder and MixinBuilder you must use GetController. To use GetX and Obx you must use RxController.
Probably using a GetController using GetX and Obx will work, but it will not be possible to use an RxController on a GetBuilder.
Extending these controllers is important, as they have life cycles, and can "start" and "end" events in their onInit() and onClose() methods.
Extending GetxController is important, as they have life cycles, and can "start" and "end" events in their onInit() and onClose() methods. You can use any class for this, but I strongly recommend you use the GetxController class to place your variables, whether they are observable or not.
## GetBuilder vs GetX vs Obx vs MixinBuilder
In a decade working with programming I was able to learn some valuable lessons.
... ... @@ -1097,8 +1143,6 @@ There are other situations where reactive programming is really interesting, and
GetX is still more economical than any other reactive state manager, but it consumes a little more RAM than GetBuilder. Thinking about it and aiming to maximize the consumption of resources that Obx was created. Unlike GetX and GetBuilder, you will not be able to initialize a controller inside an Obx, it is just a Widget with a StreamSubscription that receives change events from your children, that's all. It is more economical than GetX, but loses to GetBuilder, which was to be expected, since it is reactive, and GetBuilder has the most simplistic approach that exists, of storing a widget's hashcode and its StateSetter. With Obx you don't need to write your controller type, and you can hear the change from multiple different controllers, but it needs to be initialized before, either using the example approach at the beginning of this readme, or using the Bindings class.
# Dependency Management
... ... @@ -1325,6 +1369,57 @@ Get.config(
)
```
# Breaking changes from 2.0
1- Rx types:
Before: StringX now: RxString
Before: IntX now: RxInt
Before: MapX now: RxMax
Before: ListX now: RxList
Before: NumX now: RxNum
Before: RxDouble now: RxDouble
RxController and GetBuilder now have merged, you no longer need to memorize which controller you want to use, just use GetxController, it will work for simple state management and for reactive as well.
2- NamedRoutes
Before:
```dart
GetMaterialApp(
namedRoutes: {
'/': GetRoute(page: Home()),
}
)
```
Now:
```dart
GetMaterialApp(
getPages: [
GetPage(name: '/', page:()=> Home()),
]
)
```
Why this change?
Often, it may be necessary to decide which page will be displayed from a parameter, or a login token, the previous approach was inflexible, as it did not allow this.
Inserting the page into a function has significantly reduced the RAM consumption, since the routes will not be allocated in memory since the app was started, and it also allowed to do this type of approach:
```dart
GetStorage box = GetStorage();
GetMaterialApp(
getPages: [
GetPage(name: '/', page:(){
return box.hasData('token') ? Home() : Login();
})
]
)
```
This library will always be updated and implementing new features. Feel free to offer PRs and contribute to them.
... ...
... ... @@ -68,3 +68,4 @@ extension MDQ on BuildContext {
/// True if the current device is Tablet
bool get isTablet => isSmallTablet || isLargeTablet;
}
... ...
... ... @@ -6,6 +6,9 @@ export 'src/snackbar/snack.dart';
export 'src/bottomsheet/bottomsheet.dart';
export 'src/snackbar/snack_route.dart';
export 'src/state/get_state.dart';
export 'src/state/get_view.dart';
export 'src/regex/get_utils.dart';
export 'src/queue/get_queue.dart';
export 'src/state/mixin_state.dart';
export 'src/rx/rx_interface.dart';
export 'src/rx/rx_impl.dart';
... ... @@ -21,3 +24,4 @@ export 'src/routes/observers/route_observer.dart';
export 'src/routes/transitions_type.dart';
export 'src/platform/platform.dart';
export 'src/extension_instance.dart';
export 'src/routes/custom_transition.dart';
... ...
... ... @@ -7,8 +7,9 @@ extension Storage on GetImpl {
return GetInstance().lazyPut<S>(builder, tag: tag);
}
Future<S> putAsync<S>(FcBuilderFuncAsync<S> builder, {String tag}) async =>
GetInstance().putAsync<S>(builder, tag: tag);
Future<S> putAsync<S>(FcBuilderFuncAsync<S> builder,
{String tag, bool permanent = false}) async =>
GetInstance().putAsync<S>(builder, tag: tag, permanent: permanent);
S find<S>({String tag, FcBuilderFunc<S> instance}) =>
GetInstance().find<S>(tag: tag, instance: instance);
... ...
... ... @@ -2,7 +2,6 @@ import 'root/smart_management.dart';
import 'rx/rx_interface.dart';
import 'typedefs/typedefs.dart';
class GetConfig {
//////////// INSTANCE MANAGER
static Map<dynamic, dynamic> _singl = {};
... ... @@ -26,8 +25,9 @@ class GetInstance {
GetConfig._factory.putIfAbsent(key, () => builder);
}
Future<S> putAsync<S>(FcBuilderFuncAsync<S> builder, {String tag}) async {
return put<S>(await builder(), tag: tag);
Future<S> putAsync<S>(FcBuilderFuncAsync<S> builder,
{String tag, bool permanent = false}) async {
return put<S>(await builder(), tag: tag, permanent: permanent);
}
/// Inject class on Get Instance Manager
... ... @@ -105,14 +105,13 @@ class GetInstance {
}
void registerRouteInstance<S>({String tag}) {
// print("Register route [$S] as ${currentRoute}");
GetConfig.routesKey
.putIfAbsent(_getKey(S, tag), () => GetConfig.currentRoute);
}
S findByType<S>(Type type, {String tag}) {
String key = _getKey(type, tag);
return GetConfig._singl[key].getSependency();
return GetConfig._singl[key].getSependency() as S;
}
void initController<S>({String tag}) {
... ... @@ -136,7 +135,7 @@ class GetInstance {
callInit = true;
}
FcBuilder builder = GetConfig._singl[key];
FcBuilder builder = GetConfig._singl[key] as FcBuilder;
if (builder == null) {
if (tag == null) {
throw "class ${S.toString()} is not register";
... ... @@ -148,7 +147,7 @@ class GetInstance {
initController<S>(tag: tag);
}
return GetConfig._singl[key].getSependency();
return GetConfig._singl[key].getSependency() as S;
} else {
if (!GetConfig._factory.containsKey(key))
throw " $S not found. You need call put<$S>($S()) before";
... ... @@ -177,7 +176,7 @@ class GetInstance {
/// Remove dependency of [S] on dependency abstraction. For concrete class use delete
void remove<S>({String tag}) {
String key = _getKey(S, tag);
FcBuilder builder = GetConfig._singl[key];
FcBuilder builder = GetConfig._singl[key] as FcBuilder;
final i = builder.dependency;
if (i is DisposableInterface) {
... ... @@ -217,7 +216,7 @@ class GetInstance {
return false;
}
FcBuilder builder = GetConfig._singl[newKey];
FcBuilder builder = GetConfig._singl[newKey] as FcBuilder;
if (builder.permanent) {
(key == null)
? print(
... ...
... ... @@ -184,7 +184,7 @@ abstract class GetService {
Color overlayColor = Colors.transparent,
Form userInputForm});
void snackbar(title, message,
void snackbar(String title, String message,
{Color colorText,
Duration duration,
... ... @@ -224,11 +224,11 @@ abstract class GetService {
/// INSTANCE MANAGER
GetMaterialController getController;
GetMaterialController getxController;
changeTheme(ThemeData theme);
void changeTheme(ThemeData theme);
changeThemeMode(ThemeMode themeMode);
void changeThemeMode(ThemeMode themeMode);
GlobalKey<NavigatorState> addKey(GlobalKey<NavigatorState> newKey);
... ...
... ... @@ -5,6 +5,7 @@ import 'package:get/src/get_instance.dart';
import 'package:get/src/get_interface.dart';
import 'bottomsheet/bottomsheet.dart';
import 'platform/platform.dart';
import 'root/parse_route.dart';
import 'root/root_controller.dart';
import 'routes/bindings_interface.dart';
import 'routes/default_route.dart';
... ... @@ -22,7 +23,7 @@ class GetImpl implements GetService {
bool defaultPopGesture = GetPlatform.isIOS;
bool defaultOpaqueRoute = true;
Transition defaultTransition =
(GetPlatform.isIOS ? Transition.cupertino : Transition.fade);
(GetPlatform.isIOS ? Transition.leftToRight : Transition.fadeIn);
Duration defaultDurationTransition = Duration(milliseconds: 400);
bool defaultGlobalState = true;
RouteSettings settings;
... ... @@ -45,32 +46,42 @@ class GetImpl implements GetService {
bool fullscreenDialog = false,
Object arguments,
Bindings binding,
preventDuplicates = true,
bool popGesture}) {
return global(id).currentState.push(GetRouteBase(
if (preventDuplicates &&
'/' + page.toString().toLowerCase() == currentRoute) {
return null;
}
return global(id).currentState.push(GetPageRoute(
opaque: opaque ?? true,
page: page,
page: () => page,
settings: RouteSettings(
name: '/' + page.toString().toLowerCase(), arguments: arguments),
popGesture: popGesture ?? defaultPopGesture,
transition: transition ?? defaultTransition,
fullscreenDialog: fullscreenDialog,
binding: binding,
transitionDuration: duration ?? defaultDurationTransition));
duration: duration ?? defaultDurationTransition));
}
/// It replaces Navigator.pushNamed, but needs no context, and it doesn't have the Navigator.pushNamed
/// routes rebuild bug present in Flutter. If for some strange reason you want the default behavior
/// of rebuilding every app after a route, use opaque = true as the parameter.
Future<T> toNamed<T>(String page, {Object arguments, int id}) {
// if (key.currentState.mounted) // add this if appear problems on future with route navigate
// when widget don't mounted
Future<T> toNamed<T>(String page,
{Object arguments, int id, preventDuplicates = true}) {
if (preventDuplicates && page == currentRoute) {
return null;
}
return global(id).currentState.pushNamed(page, arguments: arguments);
}
/// It replaces Navigator.pushReplacementNamed, but needs no context.
Future<T> offNamed<T>(String page, {Object arguments, int id}) {
// if (key.currentState.mounted) // add this if appear problems on future with route navigate
// when widget don't mounted
Future<T> offNamed<T>(String page,
{Object arguments, int id, preventDuplicates = true}) {
if (preventDuplicates && page == currentRoute) {
return null;
}
return global(id)
.currentState
.pushReplacementNamed(page, arguments: arguments);
... ... @@ -128,13 +139,21 @@ class GetImpl implements GetService {
(!isSnackbarOpen && !isDialogOpen && !isBottomSheetOpen);
/// It replaces Navigator.pop, but needs no context.
void back({dynamic result, bool closeOverlays = false, int id}) {
void back(
{dynamic result,
bool closeOverlays = false,
bool canPop = true,
int id}) {
if (closeOverlays && isOverlaysOpen) {
navigator.popUntil((route) {
return (isOverlaysClosed);
});
}
if (global(id).currentState.canPop()) {
if (canPop) {
if (global(id).currentState.canPop()) {
global(id).currentState.pop(result);
}
} else {
global(id).currentState.pop(result);
}
}
... ... @@ -162,17 +181,22 @@ class GetImpl implements GetService {
Object arguments,
Bindings binding,
bool fullscreenDialog = false,
preventDuplicates = true,
Duration duration}) {
return global(id).currentState.pushReplacement(GetRouteBase(
if (preventDuplicates &&
'/' + page.toString().toLowerCase() == currentRoute) {
return null;
}
return global(id).currentState.pushReplacement(GetPageRoute(
opaque: opaque ?? true,
page: page,
page: () => page,
binding: binding,
settings: RouteSettings(
name: '/' + page.toString().toLowerCase(), arguments: arguments),
fullscreenDialog: fullscreenDialog,
popGesture: popGesture ?? defaultPopGesture,
transition: transition ?? defaultTransition,
transitionDuration: duration ?? defaultDurationTransition));
duration: duration ?? defaultDurationTransition));
}
/// It replaces Navigator.pushAndRemoveUntil, but needs no context
... ... @@ -184,21 +208,22 @@ class GetImpl implements GetService {
Object arguments,
Bindings binding,
bool fullscreenDialog = false,
Transition transition,
Duration duration}) {
Duration duration,
Transition transition}) {
var route = (Route<dynamic> rota) => false;
return global(id).currentState.pushAndRemoveUntil(
GetRouteBase(
GetPageRoute(
opaque: opaque ?? true,
popGesture: popGesture ?? defaultPopGesture,
page: page,
page: () => page,
binding: binding,
settings: RouteSettings(
name: '/' + page.toString().toLowerCase(), arguments: arguments),
name: '/' + page.runtimeType.toString().toLowerCase(),
arguments: arguments),
fullscreenDialog: fullscreenDialog,
transition: transition ?? defaultTransition,
transitionDuration: duration ?? defaultDurationTransition,
duration: duration ?? defaultDurationTransition,
),
predicate ?? route);
}
... ... @@ -461,7 +486,7 @@ class GetImpl implements GetService {
}
}
void snackbar(title, message,
void snackbar(String title, String message,
{Color colorText,
Duration duration,
... ... @@ -558,6 +583,24 @@ class GetImpl implements GetService {
}
}
ParseRouteTree routeTree;
addPages(List<GetPage> getPages) {
if (getPages != null) {
if (routeTree == null) routeTree = ParseRouteTree();
getPages.forEach((element) {
routeTree.addRoute(element);
});
}
}
addPage(GetPage getPage) {
if (getPage != null) {
if (routeTree == null) routeTree = ParseRouteTree();
routeTree.addRoute(getPage);
}
}
/// change default config of Get
config(
{bool enableLog,
... ... @@ -588,14 +631,27 @@ class GetImpl implements GetService {
}
}
GetMaterialController getController = GetMaterialController();
GetMaterialController getxController = GetMaterialController();
Locale locale;
void updateLocale(Locale l) {
locale = l;
getxController.update();
}
Map<String, Map<String, String>> translations;
void addTranslations(Map<String, Map<String, String>> tr) {
translations.addAll(tr);
}
changeTheme(ThemeData theme) {
getController.setTheme(theme);
void changeTheme(ThemeData theme) {
getxController.setTheme(theme);
}
changeThemeMode(ThemeMode themeMode) {
getController.setThemeMode(themeMode);
void changeThemeMode(ThemeMode themeMode) {
getxController.setThemeMode(themeMode);
}
GlobalKey<NavigatorState> addKey(GlobalKey<NavigatorState> newKey) {
... ...
import 'dart:async';
class GetQueue {
final List<_Item> _queue = [];
bool _active = false;
void _check() async {
if (!_active && _queue.isNotEmpty) {
_active = true;
var item = _queue.removeAt(0);
try {
item.completer.complete(await item.job());
} catch (e) {
item.completer.completeError(e);
}
_active = false;
_check();
}
}
Future<T> add<T>(Function job) {
var completer = Completer<T>();
_queue.add(_Item(completer, job));
_check();
return completer.future;
}
}
class _Item {
final completer;
final job;
_Item(this.completer, this.job);
}
... ...
import 'package:get/src/regex/regex.dart';
class GetUtils {
/// Checks if data is null.
static bool isNull(dynamic s) => s == null;
/// Checks if data is null or blank (empty or only contains whitespace).
static bool isNullOrBlank(dynamic s) {
if (isNull(s)) return true;
switch (s.runtimeType) {
case String:
case List:
case Map:
case Set:
case Iterable:
return s.isEmpty;
break;
default:
return s.toString() == 'null' || s.toString().trim().isEmpty;
}
}
/// Checks if string is int or double.
static bool isNum(String s) {
if (isNull(s)) return false;
return num.tryParse(s) is num ?? false;
}
/// Checks if string consist only numeric.
/// Numeric only doesnt accepting "." which double data type have
static bool isNumericOnly(String s) =>
RegexValidation.hasMatch(s, regex.numericOnly);
/// Checks if string consist only Alphabet. (No Whitespace)
static bool isAlphabetOnly(String s) =>
RegexValidation.hasMatch(s, regex.alphabetOnly);
/// Checks if string is boolean.
static bool isBool(String s) {
if (isNull(s)) return false;
return (s == 'true' || s == 'false');
}
/// Checks if string is an vector file.
static bool isVector(String s) => RegexValidation.hasMatch(s, regex.vector);
/// Checks if string is an image file.
static bool isImage(String s) => RegexValidation.hasMatch(s, regex.image);
/// Checks if string is an audio file.
static bool isAudio(String s) => RegexValidation.hasMatch(s, regex.audio);
/// Checks if string is an video file.
static bool isVideo(String s) => RegexValidation.hasMatch(s, regex.video);
/// Checks if string is an txt file.
static bool isTxt(String s) => RegexValidation.hasMatch(s, regex.txt);
/// Checks if string is an Doc file.
static bool isDocument(String s) => RegexValidation.hasMatch(s, regex.doc);
/// Checks if string is an Excel file.
static bool isExcel(String s) => RegexValidation.hasMatch(s, regex.excel);
/// Checks if string is an PPT file.
static bool isPPT(String s) => RegexValidation.hasMatch(s, regex.ppt);
/// Checks if string is an APK file.
static bool isAPK(String s) => RegexValidation.hasMatch(s, regex.apk);
/// Checks if string is an video file.
static bool isPDF(String s) => RegexValidation.hasMatch(s, regex.pdf);
/// Checks if string is an HTML file.
static bool isHTML(String s) => RegexValidation.hasMatch(s, regex.html);
/// Checks if string is URL.
static bool isURL(String s) => RegexValidation.hasMatch(s, regex.url);
/// Checks if string is email.
static bool isEmail(String s) => RegexValidation.hasMatch(s, regex.txt);
/// Checks if string is phone number.
static bool isPhoneNumber(String s) =>
RegexValidation.hasMatch(s, regex.phone);
/// Checks if string is DateTime (UTC or Iso8601).
static bool isDateTime(String s) =>
RegexValidation.hasMatch(s, regex.basicDateTime);
/// Checks if string is MD5 hash.
static bool isMD5(String s) => RegexValidation.hasMatch(s, regex.md5);
/// Checks if string is SHA1 hash.
static bool isSHA1(String s) => RegexValidation.hasMatch(s, regex.sha1);
/// Checks if string is SHA256 hash.
static bool isSHA256(String s) => RegexValidation.hasMatch(s, regex.sha256);
/// Checks if string is ISBN 10 or 13.
static bool isISBN(String s) => RegexValidation.hasMatch(s, regex.isbn);
/// Checks if string is SSN (Social Security Number).
static bool isSSN(String s) => RegexValidation.hasMatch(s, regex.ssn);
/// Checks if string is binary.
static bool isBinary(String s) => RegexValidation.hasMatch(s, regex.binary);
/// Checks if string is IPv4.
static bool isIPv4(String s) => RegexValidation.hasMatch(s, regex.ipv4);
/// Checks if string is IPv6.
static bool isIPv6(String s) => RegexValidation.hasMatch(s, regex.ipv6);
/// Checks if string is hexadecimal.
/// Example: HexColor => #12F
static bool isHexadecimal(String s) =>
RegexValidation.hasMatch(s, regex.hexadecimal);
/// Checks if string is Palindrom.
static bool isPalindrom(String s) {
bool isPalindrom = true;
for (var i = 0; i < s.length; i++) {
if (s[i] != s[s.length - i - 1]) isPalindrom = false;
}
return isPalindrom;
}
/// Checks if all data have same value.
/// Example: 111111 -> true, wwwww -> true, [1,1,1,1] -> true
static bool isOneAKind(dynamic s) {
if ((s is String || s is List) && !isNullOrBlank(s)) {
var first = s[0];
var isOneAKind = true;
for (var i = 0; i < s.length; i++) {
if (s[i] != first) isOneAKind = false;
}
return isOneAKind;
}
if (s is int) {
String value = s.toString();
var first = value[0];
var isOneAKind = true;
for (var i = 0; i < value.length; i++) {
if (value[i] != first) isOneAKind = false;
}
return isOneAKind;
}
return false;
}
/// Checks if string is Passport No.
static bool isPassport(String s) =>
RegexValidation.hasMatch(s, regex.passport);
/// Checks if string is Currency.
static bool isCurrency(String s) =>
RegexValidation.hasMatch(s, regex.currency);
/// Checks if length of data is LOWER than maxLength.
static bool isLengthLowerThan(dynamic s, int maxLength) {
if (isNull(s)) return (maxLength <= 0) ? true : false;
switch (s.runtimeType) {
case String:
case List:
case Map:
case Set:
case Iterable:
return s.length < maxLength;
break;
case int:
return s.toString().length < maxLength;
break;
case double:
return s.toString().replaceAll('.', '').length < maxLength;
break;
default:
return false;
}
}
/// Checks if length of data is GREATER than maxLength.
static bool isLengthGreaterThan(dynamic s, int maxLength) {
if (isNull(s)) return false;
switch (s.runtimeType) {
case String:
case List:
case Map:
case Set:
case Iterable:
return s.length > maxLength;
break;
case int:
return s.toString().length > maxLength;
break;
case double:
return s.toString().replaceAll('.', '').length > maxLength;
break;
default:
return false;
}
}
/// Checks if length of data is GREATER OR EQUAL to maxLength.
static bool isLengthGreaterOrEqual(dynamic s, int maxLength) {
if (isNull(s)) return false;
switch (s.runtimeType) {
case String:
case List:
case Map:
case Set:
case Iterable:
return s.length >= maxLength;
break;
case int:
return s.toString().length >= maxLength;
break;
case double:
return s.toString().replaceAll('.', '').length >= maxLength;
break;
default:
return false;
}
}
/// Checks if length of data is LOWER OR EQUAL to maxLength.
static bool isLengthLowerOrEqual(dynamic s, int maxLength) {
if (isNull(s)) return false;
switch (s.runtimeType) {
case String:
case List:
case Map:
case Set:
case Iterable:
return s.length <= maxLength;
break;
case int:
return s.toString().length <= maxLength;
break;
case double:
return s.toString().replaceAll('.', '').length <= maxLength;
default:
return false;
}
}
/// Checks if length of data is EQUAL to maxLength.
static bool isLengthEqualTo(dynamic s, int maxLength) {
if (isNull(s)) return false;
switch (s.runtimeType) {
case String:
case List:
case Map:
case Set:
case Iterable:
return s.length == maxLength;
break;
case int:
return s.toString().length == maxLength;
break;
case double:
return s.toString().replaceAll('.', '').length == maxLength;
break;
default:
return false;
}
}
/// Checks if length of data is BETWEEN minLength to maxLength.
static bool isLengthBetween(dynamic s, int minLength, int maxLength) {
if (isNull(s)) return false;
return isLengthGreaterOrEqual(s, minLength) &&
isLengthLowerOrEqual(s, maxLength);
}
/// Checks if a contains b (Treating or interpreting upper- and lowercase letters as being the same).
static bool isCaseInsensitiveContains(String a, String b) =>
a.toLowerCase().contains(b.toLowerCase());
/// Checks if a contains b or b contains a (Treating or interpreting upper- and lowercase letters as being the same).
static bool isCaseInsensitiveContainsAny(String a, String b) {
String lowA = a.toLowerCase();
String lowB = b.toLowerCase();
return lowA.contains(lowB) || lowB.contains(lowA);
}
/// Checks if num a LOWER than num b.
static bool isLowerThan(num a, num b) => a < b;
/// Checks if num a GREATER than num b.
static bool isGreaterThan(num a, num b) => a > b;
/// Checks if num a EQUAL than num b.
static bool isEqual(num a, num b) => a == b;
/// Capitalize each word inside string
/// Example: your name => Your Name, your name => Your name
///
/// If First Only is `true`, the only letter get uppercase is the first letter
static String capitalize(String s, {bool firstOnly = false}) {
if (isNullOrBlank(s)) return null;
if (firstOnly) return capitalizeFirst(s);
List lst = s.split(' ');
String newStr = '';
for (var s in lst) newStr += capitalizeFirst(s);
return newStr;
}
/// Uppercase first letter inside string and let the others lowercase
/// Example: your name => Your name
static String capitalizeFirst(String s) {
if (isNullOrBlank(s)) return null;
return s[0].toUpperCase() + s.substring(1).toLowerCase();
}
/// Remove all whitespace inside string
/// Example: your name => yourname
static String removeAllWhitespace(String s) {
if (isNullOrBlank(s)) return null;
return s.replaceAll(' ', '');
}
/// Camelcase string
/// Example: your name => yourName
static String camelCase(String s) {
if (isNullOrBlank(s)) return null;
return s[0].toLowerCase() + removeAllWhitespace(capitalize(s)).substring(1);
}
/// Extract numeric value of string
/// Example: OTP 12312 27/04/2020 => 1231227042020ß
/// If firstword only is true, then the example return is "12312" (first found numeric word)
static String numericOnly(String s, {bool firstWordOnly = false}) {
String numericOnlyStr = '';
for (var i = 0; i < s.length; i++) {
if (isNumericOnly(s[i])) numericOnlyStr += s[i];
if (firstWordOnly && numericOnlyStr.isNotEmpty && s[i] == " ") break;
}
return numericOnlyStr;
}
static Regex regex = Regex();
}
class RegexValidation {
/// Returns whether the pattern has a match in the string [input].
static bool hasMatch(String s, Pattern p) =>
(s == null) ? false : RegExp(p).hasMatch(s);
}
... ...
class Regex {
/// Username regex
Pattern username = r'^[a-zA-Z0-9][a-zA-Z0-9_.]+[a-zA-Z0-9]$';
/// Email regex
Pattern email =
r'^[a-z0-9]+([-+._][a-z0-9]+){0,2}@.*?(\.(a(?:[cdefgilmnoqrstuwxz]|ero|(?:rp|si)a)|b(?:[abdefghijmnorstvwyz]iz)|c(?:[acdfghiklmnoruvxyz]|at|o(?:m|op))|d[ejkmoz]|e(?:[ceghrstu]|du)|f[ijkmor]|g(?:[abdefghilmnpqrstuwy]|ov)|h[kmnrtu]|i(?:[delmnoqrst]|n(?:fo|t))|j(?:[emop]|obs)|k[eghimnprwyz]|l[abcikrstuvy]|m(?:[acdeghklmnopqrstuvwxyz]|il|obi|useum)|n(?:[acefgilopruz]|ame|et)|o(?:m|rg)|p(?:[aefghklmnrstwy]|ro)|qa|r[eosuw]|s[abcdeghijklmnortuvyz]|t(?:[cdfghjklmnoprtvwz]|(?:rav)?el)|u[agkmsyz]|v[aceginu]|w[fs]|y[etu]|z[amw])\b){1,2}$';
/// URL regex
Pattern url =
r"^((((H|h)(T|t)|(F|f))(T|t)(P|p)((S|s)?))\://)?(www.|[a-zA-Z0-9].)[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,6}(\:[0-9]{1,5})*(/($|[a-zA-Z0-9\.\,\;\?\'\\\+&amp;%\$#\=~_\-]+))*$";
/// Phone Number regex
/// Must started by either, "0", "+", "+XX <X between 2 to 4 digit>", "(+XX <X between 2 to 3 digit>)"
/// Can add whitespace separating digit with "+" or "(+XX)"
/// Example: 05555555555, +555 5555555555, (+123) 5555555555, (555) 5555555555, +5555 5555555555
Pattern phone =
r'^(0|\+|(\+[0-9]{2,4}|\(\+?[0-9]{2,4}\)) ?)([0-9]*|\d{2,4}-\d{2,4}(-\d{2,4})?)$';
/// Hexadecimal regex
Pattern hexadecimal = r'^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$';
/// Image vector regex
Pattern vector = r'.(svg)$';
/// Image regex
Pattern image = r'.(jpeg|jpg|gif|png|bmp)$';
/// Audio regex
Pattern audio = r'.(mp3|wav|wma|amr|ogg)$';
/// Video regex
Pattern video = r'.(mp4|avi|wmv|rmvb|mpg|mpeg|3gp)$';
/// Txt regex
Pattern txt = r'.txt$';
/// Document regex
Pattern doc = r'.(doc|docx)$';
/// Excel regex
Pattern excel = r'.(xls|xlsx)$';
/// PPT regex
Pattern ppt = r'.(ppt|pptx)$';
/// Document regex
Pattern apk = r'.apk$';
/// PDF regex
Pattern pdf = r'.pdf$';
/// HTML regex
Pattern html = r'.html$';
/// DateTime regex (UTC)
/// Unformatted date time (UTC and Iso8601)
/// Example: 2020-04-27 08:14:39.977, 2020-04-27T08:14:39.977, 2020-04-27 01:14:39.977Z
Pattern basicDateTime = r'^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}.\d{3}Z?$';
/// Binary regex
/// Consist only 0 & 1
Pattern binary = r'^[0-1]*$';
/// MD5 regex
Pattern md5 = r'^[a-f0-9]{32}$';
/// SHA1 regex
Pattern sha1 = r'(([A-Fa-f0-9]{2}\:){19}[A-Fa-f0-9]{2}|[A-Fa-f0-9]{40})';
/// SHA256 regex
Pattern sha256 = r'([A-Fa-f0-9]{2}\:){31}[A-Fa-f0-9]{2}|[A-Fa-f0-9]{64}';
/// SSN (Social Security Number) regex
Pattern ssn =
r'^(?!0{3}|6{3}|9[0-9]{2})[0-9]{3}-?(?!0{2})[0-9]{2}-?(?!0{4})[0-9]{4}$';
/// IPv4 regex
Pattern ipv4 = r'^(?:(?:^|\.)(?:2(?:5[0-5]|[0-4]\d)|1?\d?\d)){4}$';
/// IPv6 regex
Pattern ipv6 =
r'^((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$';
/// ISBN 10 & 13 regex
Pattern isbn =
r'(ISBN(\-1[03])?[:]?[ ]?)?(([0-9Xx][- ]?){13}|([0-9Xx][- ]?){10})';
/// Passport No. regex
Pattern passport = r'^(?!^0+$)[a-zA-Z0-9]{6,9}$';
/// Currency regex
Pattern currency =
r'^(S?\$|\₩|Rp|\¥|\€|\₹|\₽|fr|R$|R)?[ ]?[-]?([0-9]{1,3}[,.]([0-9]{3}[,.])*[0-9]{3}|[0-9]+)([,.][0-9]{1,2})?( ?(USD?|AUD|NZD|CAD|CHF|GBP|CNY|EUR|JPY|IDR|MXN|NOK|KRW|TRY|INR|RUB|BRL|ZAR|SGD|MYR))?$';
/// Numeric Only regex (No Whitespace & Symbols)
Pattern numericOnly = r'^\d+$';
/// Alphabet Only regex (No Whitespace & Symbols)
Pattern alphabetOnly = r'^[a-zA-Z]+$';
/// Password (Easy) Regex
/// Allowing all character except 'whitespace'
/// Minimum character: 8
Pattern passwordEasy = r'^\S{8,}$';
/// Password (Easy) Regex
/// Allowing all character
/// Minimum character: 8
Pattern passwordEasyAllowedWhitespace = r'^[\S ]{8,}$';
/// Password (Normal) Regex
/// Allowing all character except 'whitespace'
/// Must contains at least: 1 letter & 1 number
/// Minimum character: 8
Pattern passwordNormal1 = r'^(?=.*[A-Za-z])(?=.*\d)\S{8,}$';
/// Password (Normal) Regex
/// Allowing all character
/// Must contains at least: 1 letter & 1 number
/// Minimum character: 8
Pattern passwordNormal1AllowedWhitespace =
r'^(?=.*[A-Za-z])(?=.*\d)[\S ]{8,}$';
/// Password (Normal) Regex
/// Allowing LETTER and NUMBER only
/// Must contains at least: 1 letter & 1 number
/// Minimum character: 8
Pattern passwordNormal2 = r'^(?=.*[A-Za-z])(?=.*\d)[a-zA-Z0-9]{8,}$';
/// Password (Normal) Regex
/// Allowing LETTER and NUMBER only
/// Must contains: 1 letter & 1 number
/// Minimum character: 8
Pattern passwordNormal2AllowedWhitespace =
r'^(?=.*[A-Za-z])(?=.*\d)[a-zA-Z0-9 ]{8,}$';
/// Password (Normal) Regex
/// Allowing all character except 'whitespace'
/// Must contains at least: 1 uppercase letter, 1 lowecase letter & 1 number
/// Minimum character: 8
Pattern passwordNormal3 = r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)\S{8,}$';
/// Password (Normal) Regex
/// Allowing all character
/// Must contains at least: 1 uppercase letter, 1 lowecase letter & 1 number
/// Minimum character: 8
Pattern passwordNormal3AllowedWhitespace =
r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[\S ]{8,}$';
/// Password (Hard) Regex
/// Allowing all character except 'whitespace'
/// Must contains at least: 1 uppercase letter, 1 lowecase letter, 1 number, & 1 special character (symbol)
/// Minimum character: 8
Pattern passwordHard = r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_])\S{8,}$';
/// Password (Hard) Regex
/// Allowing all character
/// Must contains at least: 1 uppercase letter, 1 lowecase letter, 1 number, & 1 special character (symbol)
/// Minimum character: 8
Pattern passwordHardAllowedWhitespace =
r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_])[\S ]{8,}$';
}
... ...
import 'package:flutter/material.dart';
import 'package:get/src/routes/utils/parse_arguments.dart';
import 'package:get/src/state/get_state.dart';
class GetMaterialController extends GetController {
ParseRoute parse = ParseRoute();
class GetMaterialController extends GetxController {
Key key;
ThemeData theme;
ThemeMode themeMode;
... ...
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get/src/routes/get_route.dart';
import 'package:get/src/routes/utils/parse_arguments.dart';
import '../get_instance.dart';
import 'parse_route.dart';
import 'root_controller.dart';
... ... @@ -19,6 +19,8 @@ class GetMaterialApp extends StatelessWidget {
this.onUnknownRoute,
this.navigatorObservers = const <NavigatorObserver>[],
this.builder,
this.translationsKeys,
this.translations,
this.title = '',
this.onGenerateTitle,
this.color,
... ... @@ -50,27 +52,6 @@ class GetMaterialApp extends StatelessWidget {
this.popGesture,
this.transitionDuration,
this.defaultGlobalState,
// ignore: deprecated_member_use_from_same_package
@Deprecated(
"""Please, use new api getPages. You can now simply create a list of GetPages,
and enter your route name in the 'name' property.
Page now receives a function ()=> Page(), which allows more flexibility.
You can now decide which page you want to display, according to the parameters received on the page.
Example:
GetPage(
name: '/second',
page:(){
if (Get.parameters['id'] == null) {
return Login();
} else {
return Home();
}
});
""")
// ignore: deprecated_member_use_from_same_package
this.namedRoutes,
this.unknownRoute,
}) : assert(routes != null),
assert(navigatorObservers != null),
assert(title != null),
... ... @@ -97,6 +78,8 @@ class GetMaterialApp extends StatelessWidget {
final ThemeData darkTheme;
final ThemeMode themeMode;
final Color color;
final Map<String, Map<String, String>> translationsKeys;
final Translations translations;
final Locale locale;
final Iterable<LocalizationsDelegate<dynamic>> localizationsDelegates;
final LocaleListResolutionCallback localeListResolutionCallback;
... ... @@ -121,135 +104,52 @@ class GetMaterialApp extends StatelessWidget {
final Bindings initialBinding;
final Duration transitionDuration;
final bool defaultGlobalState;
final Map<String, GetRoute> namedRoutes;
final List<GetPage> getPages;
final GetRoute unknownRoute;
Route<dynamic> generator(RouteSettings settings) {
final match = _routeTree.matchRoute(settings.name);
print(settings.name);
final match = Get.routeTree.matchRoute(settings.name);
Get.parameters = match?.parameters;
return GetRouteBase(
page: null,
title: match.route.title,
route: match.route.page,
return GetPageRoute(
page: match.route.page,
parameter: match.route.parameter,
settings:
RouteSettings(name: settings.name, arguments: settings.arguments),
maintainState: match.route.maintainState,
curve: match.route.curve,
alignment: match.route.alignment,
opaque: match.route.opaque,
binding: match.route.binding,
bindings: match.route.bindings,
transitionDuration: (transitionDuration == null
? match.route.transitionDuration
: transitionDuration),
duration: (transitionDuration ?? match.route.transitionDuration),
transition: match.route.transition,
popGesture: match.route.popGesture,
fullscreenDialog: match.route.fullscreenDialog,
);
}
Route<dynamic> namedRoutesGenerate(RouteSettings settings) {
// Get.setSettings(settings);
/// onGenerateRoute to FlutterWeb is Broken on Dev/Master. This is a temporary
/// workaround until they fix it, because the problem is with the 'Flutter engine',
/// which changes the initial route for an empty String, not the main Flutter,
/// so only Team can fix it.
var parsedString = Get.getController.parse.split(
(settings.name == '' || settings.name == null)
? (initialRoute ?? '/')
: settings.name);
if (parsedString == null) {
parsedString = AppRouteMatch();
parsedString.route = settings.name;
}
String settingsName = parsedString.route;
Map<String, GetRoute> newNamedRoutes = {};
namedRoutes.forEach((key, value) {
String newName = Get.getController.parse.split(key).route;
newNamedRoutes.addAll({newName: value});
});
if (newNamedRoutes.containsKey(settingsName)) {
Get.parameters = parsedString.parameters;
return GetRouteBase(
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,
binding: newNamedRoutes[settingsName].binding,
bindings: newNamedRoutes[settingsName].bindings,
transitionDuration: (transitionDuration == null
? newNamedRoutes[settingsName].transitionDuration
: transitionDuration),
transition: newNamedRoutes[settingsName].transition,
popGesture: newNamedRoutes[settingsName].popGesture,
fullscreenDialog: newNamedRoutes[settingsName].fullscreenDialog,
);
} else {
return ((unknownRoute == null
? GetRouteBase(
page: Scaffold(
body: Center(
child: Text("Route not found :("),
),
))
: GetRouteBase(
page: unknownRoute.page,
title: unknownRoute.title,
settings: unknownRoute.settings,
maintainState: unknownRoute.maintainState,
curve: unknownRoute.curve,
alignment: unknownRoute.alignment,
parameter: unknownRoute.parameter,
opaque: unknownRoute.opaque,
binding: unknownRoute.binding,
bindings: unknownRoute.bindings,
transitionDuration: unknownRoute.transitionDuration,
popGesture: unknownRoute.popGesture,
transition: unknownRoute.transition,
fullscreenDialog: unknownRoute.fullscreenDialog,
)));
}
}
@override
Widget build(BuildContext context) {
return GetBuilder<GetMaterialController>(
init: Get.getController,
init: Get.getxController,
dispose: (d) {
onDispose?.call();
},
initState: (i) {
if (getPages != null) {
_routeTree = ParseRouteTree();
getPages.forEach((element) {
_routeTree.addRoute(element);
});
if (locale != null) {
Get.locale = locale;
}
if (translations != null) {
if (Get.locale == null) Get.translations = translations.keys;
}
if (translationsKeys != null) {
Get.translations = translationsKeys;
}
initialBinding?.dependencies();
Get.addPages(getPages);
GetConfig.smartManagement = smartManagement;
onInit?.call();
if (namedRoutes != null) {
namedRoutes.forEach((key, value) {
Get.getController.parse.addRoute(key);
});
}
Get.config(
enableLog: enableLog ?? GetConfig.isLogEnable,
defaultTransition: defaultTransition ?? Get.defaultTransition,
... ... @@ -268,32 +168,29 @@ class GetMaterialApp extends StatelessWidget {
home: home,
routes: routes ?? const <String, WidgetBuilder>{},
initialRoute: initialRoute,
onGenerateRoute: (getPages != null
? generator
: namedRoutes != null ? namedRoutesGenerate : onGenerateRoute),
onGenerateInitialRoutes: onGenerateInitialRoutes ??
(getPages == null || home != null)
? null
onGenerateRoute: (getPages != null ? generator : onGenerateRoute),
onGenerateInitialRoutes: (getPages == null || home != null)
? onGenerateInitialRoutes
: (st) {
final match = _routeTree.matchRoute(initialRoute);
Get.parameters = match.parameters;
GetPageMatch match;
if (initialRoute == null && getPages != null) {
match = Get.routeTree?.matchRoute(getPages.first.name);
} else {
match = Get.routeTree?.matchRoute(initialRoute);
}
Get.parameters = match?.parameters;
return [
GetRouteBase(
page: null,
route: match.route.page,
title: match.route.title,
GetPageRoute(
page: match.route.page,
parameter: match.parameters,
settings:
RouteSettings(name: initialRoute, arguments: null),
maintainState: match.route.maintainState,
curve: match.route.curve,
alignment: match.route.alignment,
opaque: match.route.opaque,
binding: match.route.binding,
bindings: match.route.bindings,
transitionDuration: (transitionDuration == null
? match.route.transitionDuration
: transitionDuration),
duration: (transitionDuration ??
match.route.transitionDuration),
transition: match.route.transition,
popGesture: match.route.popGesture,
fullscreenDialog: match.route.fullscreenDialog,
... ... @@ -312,7 +209,7 @@ class GetMaterialApp extends StatelessWidget {
theme: _.theme ?? theme ?? ThemeData.fallback(),
darkTheme: darkTheme,
themeMode: _.themeMode ?? themeMode ?? ThemeMode.system,
locale: locale,
locale: Get.locale ?? locale,
localizationsDelegates: localizationsDelegates,
localeListResolutionCallback: localeListResolutionCallback,
localeResolutionCallback: localeResolutionCallback,
... ... @@ -332,4 +229,29 @@ class GetMaterialApp extends StatelessWidget {
}
}
ParseRouteTree _routeTree;
abstract class Translations {
Map<String, Map<String, String>> get keys;
}
extension Trans on String {
String get tr {
if (Get.translations
.containsKey("${Get.locale.languageCode}_${Get.locale.countryCode}")) {
return Get.translations[
"${Get.locale.languageCode}_${Get.locale.countryCode}"][this];
} else if (Get.translations.containsKey(Get.locale.languageCode)) {
return Get.translations[Get.locale.languageCode][this];
}
return Get.translations.values.first[this];
}
String trArgs([List<String> args]) {
String key = tr;
if (args != null) {
args.forEach((arg) {
key = key.replaceFirst(RegExp(r'%s'), arg.toString());
});
}
return key;
}
}
... ...
abstract class Bindings {
void dependencies();
dependencies();
}
// abstract class INavigation {}
... ...
import 'package:flutter/widgets.dart';
abstract class CustomTransition {
Widget buildTransition(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
);
}
... ...
import 'dart:math';
import 'dart:ui' show lerpDouble;
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:get/src/get_instance.dart';
import 'package:get/src/get_main.dart';
import 'package:get/src/routes/bindings_interface.dart';
import '../platform/platform.dart';
import 'package:get/src/platform/platform.dart';
import 'bindings_interface.dart';
import 'custom_transition.dart';
import 'transitions_filter.dart';
import 'transitions_type.dart';
const double _kBackGestureWidth = 20.0;
const double _kMinFlingVelocity = 1.0;
const int _kMaxDroppedSwipePageForwardAnimationTime = 800; // Milliseconds.
// The maximum time for a page to get reset to it's original position if the
// user releases a page mid swipe.
const int _kMaxPageBackAnimationTime = 300;
class GetPageRoute<T> extends PageRouteBuilder<T> {
//final TransitionComponent transitionComponent;
final Duration duration;
final bool popGesture;
final Transition transition;
final Curve curve;
final GetPageBuilder page;
final CustomTransition customTransition;
final Bindings binding;
final Map<String, String> parameter;
final List<Bindings> bindings;
class GetRouteBase<T> extends PageRoute<T> {
/// The [builder], [maintainState], and [fullscreenDialog] arguments must not
/// be null.
GetRouteBase({
@required this.page,
this.title,
GetPageRoute({
// this.transitionComponent,
RouteSettings settings,
this.maintainState = true,
this.curve = Curves.linear,
this.alignment,
this.parameter,
this.duration,
this.transition = Transition.native,
this.binding,
this.route,
@required this.page,
this.bindings,
this.customBuildPageTransitions,
this.opaque = true,
this.transitionDuration = const Duration(milliseconds: 400),
this.parameter,
this.fullscreenDialog = false,
this.curve,
this.popGesture,
this.transition,
// this.duration = const Duration(milliseconds: 400),
bool fullscreenDialog = false,
}) : // assert(page != null),
assert(maintainState != null),
assert(fullscreenDialog != null),
// assert(opaque),
super(settings: settings, fullscreenDialog: fullscreenDialog) {
/// prebuild dependencies
if (binding != null) {
binding.dependencies();
}
if (bindings != null) {
bindings.forEach((element) => element.dependencies());
}
}
/// Builds the primary contents of the route.
final Widget page;
final GetPageBuilder route;
final Widget customBuildPageTransitions;
final bool popGesture;
final Bindings binding;
final List<Bindings> bindings;
// final Duration duration;
final Map<String, String> parameter;
final String title;
final Transition transition;
final Curve curve;
final Alignment alignment;
ValueNotifier<String> _previousTitle;
/// The title string of the previous [GetRoute].
///
/// The [ValueListenable]'s value is readable after the route is installed
/// onto a [Navigator]. The [ValueListenable] will also notify its listeners
/// if the value changes (such as by replacing the previous route).
///
/// The [ValueListenable] itself will be null before the route is installed.
/// Its content value will be null if the previous route has no title or
/// is not a [GetRoute].
///
/// See also:
///
/// * [ValueListenableBuilder], which can be used to listen and rebuild
/// widgets based on a ValueListenable.
ValueListenable<String> get previousTitle {
assert(
_previousTitle != null,
'Cannot read the previousTitle for a route that has not yet been installed',
);
return _previousTitle;
}
this.customTransition,
}) : super(
pageBuilder: (context, anim1, anim2) {
if (binding != null) {
binding.dependencies();
}
if (bindings != null) {
for (Bindings element in bindings) {
element.dependencies();
}
}
GetConfig.currentRoute = settings.name;
return page();
},
settings: settings,
);
@override
void didChangePrevious(Route<dynamic> previousRoute) {
final String previousTitleString =
previousRoute is GetRouteBase ? previousRoute.title : null;
if (_previousTitle == null) {
_previousTitle = ValueNotifier<String>(previousTitleString);
} else {
_previousTitle.value = previousTitleString;
}
super.didChangePrevious(previousRoute);
}
@override
final bool maintainState;
/// Allows you to set opaque to false to prevent route reconstruction.
@override
final bool opaque;
@override
final Duration transitionDuration;
final bool fullscreenDialog;
@override
Color get barrierColor => null; //Color(0x00FFFFFF);
Widget buildTransitions(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) {
if (this.customTransition != null) {
return this.customTransition.buildTransition(
context,
animation,
secondaryAnimation,
popGesture ?? Get.defaultPopGesture
? _CupertinoBackGestureDetector<T>(
enabledCallback: () => _isPopGestureEnabled<T>(this),
onStartPopGesture: () => _startPopGesture<T>(this),
child: child)
: child);
}
@override
String get barrierLabel => null;
if (transition == Transition.native) {
return Theme.of(context).pageTransitionsTheme.buildTransitions(
this,
context,
animation,
secondaryAnimation,
GetPlatform.isIOS
? _CupertinoBackGestureDetector<T>(
enabledCallback: () => _isPopGestureEnabled<T>(this),
onStartPopGesture: () => _startPopGesture<T>(this),
child: child)
: child);
}
@override
bool canTransitionTo(TransitionRoute<dynamic> nextRoute) {
// Don't perform outgoing animation if the next route is a fullscreen dialog.
return nextRoute is GetRouteBase && !nextRoute.fullscreenDialog;
}
final curvedAnimation = CurvedAnimation(
parent: animation,
curve: this.curve ?? Curves.linear,
);
/// True if an iOS-style back swipe pop gesture is currently underway for [route].
///
/// This just check the route's [NavigatorState.userGestureInProgress].
///
/// See also:
///
/// * [popGestureEnabled], which returns true if a user-triggered pop gesture
/// would be allowed.
static bool isPopGestureInProgress(PageRoute<dynamic> route) {
return route.navigator.userGestureInProgress;
return TransitionFilter.newTransitionComponent(transition)
.buildChildWithTransition(
context,
curvedAnimation,
secondaryAnimation,
popGesture ?? Get.defaultPopGesture
? _CupertinoBackGestureDetector<T>(
enabledCallback: () => _isPopGestureEnabled<T>(this),
onStartPopGesture: () => _startPopGesture<T>(this),
child: child)
: child);
}
/// True if an iOS-style back swipe pop gesture is currently underway for this route.
///
/// See also:
///
/// * [isPopGestureInProgress], which returns true if a Cupertino pop gesture
/// is currently underway for specific route.
/// * [popGestureEnabled], which returns true if a user-triggered pop gesture
/// would be allowed.
bool get popGestureInProgress => isPopGestureInProgress(this);
/// Whether a pop gesture can be started by the user.
///
/// Returns true if the user can edge-swipe to a previous route.
///
/// Returns false once [isPopGestureInProgress] is true, but
/// [isPopGestureInProgress] can only become true if [popGestureEnabled] was
/// true first.
///
/// This should only be used between frames, not during build.
bool get popGestureEnabled => _isPopGestureEnabled(this);
@override
Duration get transitionDuration =>
this.duration ?? Duration(milliseconds: 300);
static bool _isPopGestureEnabled<T>(PageRoute<T> route) {
// If there's nothing to go back to, then obviously we don't support
// the back gesture.
if (route.isFirst) return false;
// If the route wouldn't actually pop if we popped it, then the gesture
// would be really confusing (or would skip internal routes), so disallow it.
if (route.willHandlePopInternally) return false;
// If attempts to dismiss this route might be vetoed such as in a page
// with forms, then do not allow the user to dismiss the route with a swipe.
if (route.hasScopedWillPopCallback) return false;
// Fullscreen dialogs aren't dismissible by back swipe.
if (route.fullscreenDialog) return false;
// If we're in an animation already, we cannot be manually swiped.
if (route.animation.status != AnimationStatus.completed) return false;
// If we're being popped into, we also cannot be swiped until the pop above
// it completes. This translates to our secondary animation being
// dismissed.
if (route.secondaryAnimation.status != AnimationStatus.dismissed)
return false;
// If we're in a gesture already, we cannot start another.
if (isPopGestureInProgress(route)) return false;
// Looks like a back gesture would be welcome!
return true;
}
@override
Widget buildPage(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation) {
final Widget result = Semantics(
scopesRoute: true,
explicitChildNodes: true,
child: (route == null ? page : route()),
);
assert(() {
if (route == null && page == null) {
throw FlutterError.fromParts(<DiagnosticsNode>[
ErrorSummary(
'The builder for route "${settings.name}" returned null.'),
ErrorDescription('Route builders must never return null.'),
]);
}
return true;
}());
return result;
}
// Called by _CupertinoBackGestureDetector when a pop ("back") drag start
// gesture is detected. The returned controller handles all of the subsequent
// drag events.
static _CupertinoBackGestureController<T> _startPopGesture<T>(
PageRoute<T> route) {
assert(_isPopGestureEnabled(route));
return _CupertinoBackGestureController<T>(
navigator: route.navigator,
controller: route.controller, // protected access
controller: route.controller,
);
}
/// Returns a [CupertinoFullscreenDialogTransition] if [route] is a full
/// screen dialog, otherwise a [CupertinoPageTransition] is returned.
///
/// Used by [GetRoute.buildTransitions].
///
/// This method can be applied to any [PageRoute], not just
/// [GetRoute]. It's typically used to provide a Cupertino style
/// horizontal transition for material widgets when the target platform
/// is [TargetPlatform.iOS].
///
/// See also:
///
/// * [CupertinoPageTransitionsBuilder], which uses this method to define a
/// [PageTransitionsBuilder] for the [PageTransitionsTheme].
Widget buildPageTransitions<T>(
PageRoute<T> route,
BuildContext context,
bool popGesture,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child,
Transition tr,
Curve curve,
Alignment alignment,
) {
Transition transition = (tr ?? Get.defaultTransition);
if (route.fullscreenDialog) {
final bool linearTransition = isPopGestureInProgress(route);
return CupertinoFullscreenDialogTransition(
primaryRouteAnimation: animation,
secondaryRouteAnimation: secondaryAnimation,
child: child,
linearTransition: linearTransition,
);
} else {
switch (transition) {
case Transition.fade:
final PageTransitionsBuilder matchingBuilder =
FadeUpwardsPageTransitionsBuilder();
return matchingBuilder.buildTransitions<T>(
route,
context,
animation,
secondaryAnimation,
popGesture
? _CupertinoBackGestureDetector<T>(
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child);
break;
case Transition.rightToLeft:
return SlideTransition(
transformHitTests: false,
position: new Tween<Offset>(
begin: const Offset(1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: new SlideTransition(
position: new Tween<Offset>(
begin: Offset.zero,
end: const Offset(-1.0, 0.0),
).animate(secondaryAnimation),
child: popGesture
? _CupertinoBackGestureDetector<T>(
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child),
);
break;
case Transition.leftToRight:
return SlideTransition(
transformHitTests: false,
position: Tween<Offset>(
begin: const Offset(-1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: new SlideTransition(
position: new Tween<Offset>(
begin: Offset.zero,
end: const Offset(1.0, 0.0),
).animate(secondaryAnimation),
child: popGesture
? _CupertinoBackGestureDetector<T>(
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child),
);
break;
case Transition.upToDown:
return SlideTransition(
transformHitTests: false,
position: Tween<Offset>(
begin: const Offset(0.0, -1.0),
end: Offset.zero,
).animate(animation),
child: new SlideTransition(
position: new Tween<Offset>(
begin: Offset.zero,
end: const Offset(0.0, 1.0),
).animate(secondaryAnimation),
child: popGesture
? _CupertinoBackGestureDetector<T>(
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child),
);
break;
case Transition.downToUp:
return SlideTransition(
transformHitTests: false,
position: Tween<Offset>(
begin: const Offset(0.0, 1.0),
end: Offset.zero,
).animate(animation),
child: new SlideTransition(
position: new Tween<Offset>(
begin: Offset.zero,
end: const Offset(0.0, -1.0),
).animate(secondaryAnimation),
child: popGesture
? _CupertinoBackGestureDetector<T>(
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child),
);
break;
case Transition.scale:
return ScaleTransition(
alignment: alignment,
scale: CurvedAnimation(
parent: animation,
curve: Interval(
0.00,
0.50,
curve: curve,
),
),
child: popGesture
? _CupertinoBackGestureDetector<T>(
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child);
break;
case Transition.rotate:
return RotationTransition(
alignment: alignment,
turns: animation,
child: ScaleTransition(
alignment: alignment,
scale: animation,
child: FadeTransition(
opacity: animation,
child: popGesture
? _CupertinoBackGestureDetector<T>(
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child),
),
);
break;
case Transition.rightToLeftWithFade:
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: FadeTransition(
opacity: animation,
child: SlideTransition(
position: Tween<Offset>(
begin: Offset.zero,
end: const Offset(-1.0, 0.0),
).animate(secondaryAnimation),
child: popGesture
? _CupertinoBackGestureDetector<T>(
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child),
),
);
break;
case Transition.leftToRightWithFade:
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(-1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: FadeTransition(
opacity: animation,
child: SlideTransition(
position: Tween<Offset>(
begin: Offset.zero,
end: const Offset(1.0, 0.0),
).animate(secondaryAnimation),
child: popGesture
? _CupertinoBackGestureDetector<T>(
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child),
),
);
break;
case Transition.cupertino:
return CupertinoPageTransition(
primaryRouteAnimation: animation,
secondaryRouteAnimation: secondaryAnimation,
// Check if the route has an animation that's currently participating
// in a back swipe gesture.
//
// In the middle of a back gesture drag, let the transition be linear to
// match finger motions.
linearTransition: isPopGestureInProgress(route),
child: _CupertinoBackGestureDetector<T>(
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child,
),
);
break;
default:
return CupertinoPageTransition(
primaryRouteAnimation: animation,
secondaryRouteAnimation: secondaryAnimation,
// Check if the route has an animation that's currently participating
// in a back swipe gesture.
//
// In the middle of a back gesture drag, let the transition be linear to
// match finger motions.
linearTransition: isPopGestureInProgress(route),
child: popGesture
? _CupertinoBackGestureDetector<T>(
enabledCallback: () => _isPopGestureEnabled<T>(route),
onStartPopGesture: () => _startPopGesture<T>(route),
child: child)
: child,
);
}
}
}
@override
Widget buildTransitions(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) {
if (customBuildPageTransitions != null) {
return customBuildPageTransitions;
} else {
return buildPageTransitions<T>(
this,
context,
popGesture ?? GetPlatform.isIOS,
animation,
secondaryAnimation,
child,
transition,
curve,
alignment);
}
static bool isPopGestureInProgress(PageRoute<dynamic> route) {
return route.navigator.userGestureInProgress;
}
@override
String get debugLabel => '${super.debugLabel}(${settings.name})';
bool get popGestureInProgress => isPopGestureInProgress(this);
}
const double _kBackGestureWidth = 20.0;
const double _kMinFlingVelocity = 1.0;
const int _kMaxDroppedSwipePageForwardAnimationTime = 800; // Milliseconds.
// The maximum time for a page to get reset to it's original position if the
// user releases a page mid swipe.
const int _kMaxPageBackAnimationTime = 300;
class _CupertinoBackGestureDetector<T> extends StatefulWidget {
const _CupertinoBackGestureDetector({
Key key,
... ... @@ -655,10 +305,11 @@ class _CupertinoBackGestureController<T> {
// If the user releases the page before mid screen with sufficient velocity,
// or after mid screen, we should animate the page out. Otherwise, the page
// should be animated back in.
if (velocity.abs() >= _kMinFlingVelocity)
if (velocity.abs() >= _kMinFlingVelocity) {
animateForward = velocity <= 0;
else
} else {
animateForward = controller.value > 0.5;
}
if (animateForward) {
// The closer the panel is to dismissing, the shorter the animation is.
... ... @@ -704,3 +355,655 @@ class _CupertinoBackGestureController<T> {
}
}
}
// import 'package:flutter/cupertino.dart';
// import 'package:flutter/foundation.dart';
// import 'package:flutter/gestures.dart';
// import 'package:flutter/material.dart';
// import 'package:get/src/get_main.dart';
// import 'package:get/src/routes/bindings_interface.dart';
// import '../platform/platform.dart';
// import 'transitions_type.dart';
// const double _kBackGestureWidth = 20.0;
// const double _kMinFlingVelocity = 1.0;
// const int _kMaxDroppedSwipePageForwardAnimationTime = 800; // Milliseconds.
// // The maximum time for a page to get reset to it's original position if the
// // user releases a page mid swipe.
// const int _kMaxPageBackAnimationTime = 300;
// class GetPageRoute<T> extends PageRoute<T> {
// /// The [builder], [maintainState], and [fullscreenDialog] arguments must not
// /// be null.
// GetPageRoute({
// @required this.page,
// this.title,
// RouteSettings settings,
// this.maintainState = true,
// this.curve = Curves.linear,
// this.alignment,
// this.parameter,
// this.binding,
// this.route,
// this.bindings,
// this.customBuildPageTransitions,
// this.opaque = true,
// this.transitionDuration = const Duration(milliseconds: 400),
// this.popGesture,
// this.transition,
// // this.duration = const Duration(milliseconds: 400),
// bool fullscreenDialog = false,
// }) : // assert(page != null),
// assert(maintainState != null),
// assert(fullscreenDialog != null),
// // assert(opaque),
// super(settings: settings, fullscreenDialog: fullscreenDialog) {
// /// prebuild dependencies
// if (binding != null) {
// binding.dependencies();
// }
// if (bindings != null) {
// bindings.forEach((element) => element.dependencies());
// }
// }
// /// Builds the primary contents of the route.
// final Widget page;
// final GetPageBuilder route;
// final Widget customBuildPageTransitions;
// final bool popGesture;
// final Bindings binding;
// final List<Bindings> bindings;
// // final Duration duration;
// final Map<String, String> parameter;
// final String title;
// final Transition transition;
// final Curve curve;
// final Alignment alignment;
// ValueNotifier<String> _previousTitle;
// /// The title string of the previous [GetRoute].
// ///
// /// The [ValueListenable]'s value is readable after the route is installed
// /// onto a [Navigator]. The [ValueListenable] will also notify its listeners
// /// if the value changes (such as by replacing the previous route).
// ///
// /// The [ValueListenable] itself will be null before the route is installed.
// /// Its content value will be null if the previous route has no title or
// /// is not a [GetRoute].
// ///
// /// See also:
// ///
// /// * [ValueListenableBuilder], which can be used to listen and rebuild
// /// widgets based on a ValueListenable.
// ValueListenable<String> get previousTitle {
// assert(
// _previousTitle != null,
// 'Cannot read the previousTitle for a route that has not yet been installed',
// );
// return _previousTitle;
// }
// @override
// void didChangePrevious(Route<dynamic> previousRoute) {
// final String previousTitleString =
// previousRoute is GetPageRoute ? previousRoute.title : null;
// if (_previousTitle == null) {
// _previousTitle = ValueNotifier<String>(previousTitleString);
// } else {
// _previousTitle.value = previousTitleString;
// }
// super.didChangePrevious(previousRoute);
// }
// @override
// final bool maintainState;
// /// Allows you to set opaque to false to prevent route reconstruction.
// @override
// final bool opaque;
// @override
// final Duration transitionDuration;
// @override
// Color get barrierColor => null; //Color(0x00FFFFFF);
// @override
// String get barrierLabel => null;
// @override
// bool canTransitionTo(TransitionRoute<dynamic> nextRoute) {
// // Don't perform outgoing animation if the next route is a fullscreen dialog.
// return nextRoute is GetPageRoute && !nextRoute.fullscreenDialog;
// }
// /// True if an iOS-style back swipe pop gesture is currently underway for [route].
// ///
// /// This just check the route's [NavigatorState.userGestureInProgress].
// ///
// /// See also:
// ///
// /// * [popGestureEnabled], which returns true if a user-triggered pop gesture
// /// would be allowed.
// static bool isPopGestureInProgress(PageRoute<dynamic> route) {
// return route.navigator.userGestureInProgress;
// }
// /// True if an iOS-style back swipe pop gesture is currently underway for this route.
// ///
// /// See also:
// ///
// /// * [isPopGestureInProgress], which returns true if a Cupertino pop gesture
// /// is currently underway for specific route.
// /// * [popGestureEnabled], which returns true if a user-triggered pop gesture
// /// would be allowed.
// bool get popGestureInProgress => isPopGestureInProgress(this);
// /// Whether a pop gesture can be started by the user.
// ///
// /// Returns true if the user can edge-swipe to a previous route.
// ///
// /// Returns false once [isPopGestureInProgress] is true, but
// /// [isPopGestureInProgress] can only become true if [popGestureEnabled] was
// /// true first.
// ///
// /// This should only be used between frames, not during build.
// bool get popGestureEnabled => _isPopGestureEnabled(this);
// static bool _isPopGestureEnabled<T>(PageRoute<T> route) {
// // If there's nothing to go back to, then obviously we don't support
// // the back gesture.
// if (route.isFirst) return false;
// // If the route wouldn't actually pop if we popped it, then the gesture
// // would be really confusing (or would skip internal routes), so disallow it.
// if (route.willHandlePopInternally) return false;
// // If attempts to dismiss this route might be vetoed such as in a page
// // with forms, then do not allow the user to dismiss the route with a swipe.
// if (route.hasScopedWillPopCallback) return false;
// // Fullscreen dialogs aren't dismissible by back swipe.
// if (route.fullscreenDialog) return false;
// // If we're in an animation already, we cannot be manually swiped.
// if (route.animation.status != AnimationStatus.completed) return false;
// // If we're being popped into, we also cannot be swiped until the pop above
// // it completes. This translates to our secondary animation being
// // dismissed.
// if (route.secondaryAnimation.status != AnimationStatus.dismissed)
// return false;
// // If we're in a gesture already, we cannot start another.
// if (isPopGestureInProgress(route)) return false;
// // Looks like a back gesture would be welcome!
// return true;
// }
// @override
// Widget buildPage(BuildContext context, Animation<double> animation,
// Animation<double> secondaryAnimation) {
// final Widget result = Semantics(
// scopesRoute: true,
// explicitChildNodes: true,
// child: (route == null ? page : route()),
// );
// assert(() {
// if (route == null && page == null) {
// throw FlutterError.fromParts(<DiagnosticsNode>[
// ErrorSummary(
// 'The builder for route "${settings.name}" returned null.'),
// ErrorDescription('Route builders must never return null.'),
// ]);
// }
// return true;
// }());
// return result;
// }
// // Called by _CupertinoBackGestureDetector when a pop ("back") drag start
// // gesture is detected. The returned controller handles all of the subsequent
// // drag events.
// static _CupertinoBackGestureController<T> _startPopGesture<T>(
// PageRoute<T> route) {
// assert(_isPopGestureEnabled(route));
// return _CupertinoBackGestureController<T>(
// navigator: route.navigator,
// controller: route.controller, // protected access
// );
// }
// /// Returns a [CupertinoFullscreenDialogTransition] if [route] is a full
// /// screen dialog, otherwise a [CupertinoPageTransition] is returned.
// ///
// /// Used by [GetRoute.buildTransitions].
// ///
// /// This method can be applied to any [PageRoute], not just
// /// [GetRoute]. It's typically used to provide a Cupertino style
// /// horizontal transition for material widgets when the target platform
// /// is [TargetPlatform.iOS].
// ///
// /// See also:
// ///
// /// * [CupertinoPageTransitionsBuilder], which uses this method to define a
// /// [PageTransitionsBuilder] for the [PageTransitionsTheme].
// Widget buildPageTransitions<T>(
// PageRoute<T> route,
// BuildContext context,
// bool popGesture,
// Animation<double> animation,
// Animation<double> secondaryAnimation,
// Widget child,
// Transition tr,
// Curve curve,
// Alignment alignment,
// ) {
// Transition transition = (tr ?? Get.defaultTransition);
// if (route.fullscreenDialog) {
// final bool linearTransition = isPopGestureInProgress(route);
// return CupertinoFullscreenDialogTransition(
// primaryRouteAnimation: animation,
// secondaryRouteAnimation: secondaryAnimation,
// child: child,
// linearTransition: linearTransition,
// );
// } else {
// switch (transition) {
// case Transition.fade:
// final PageTransitionsBuilder matchingBuilder =
// FadeUpwardsPageTransitionsBuilder();
// return matchingBuilder.buildTransitions<T>(
// route,
// context,
// animation,
// secondaryAnimation,
// popGesture
// ? _CupertinoBackGestureDetector<T>(
// enabledCallback: () => _isPopGestureEnabled<T>(route),
// onStartPopGesture: () => _startPopGesture<T>(route),
// child: child)
// : child);
// break;
// case Transition.rightToLeft:
// return SlideTransition(
// transformHitTests: false,
// position: new Tween<Offset>(
// begin: const Offset(1.0, 0.0),
// end: Offset.zero,
// ).animate(animation),
// child: new SlideTransition(
// position: new Tween<Offset>(
// begin: Offset.zero,
// end: const Offset(-1.0, 0.0),
// ).animate(secondaryAnimation),
// child: popGesture
// ? _CupertinoBackGestureDetector<T>(
// enabledCallback: () => _isPopGestureEnabled<T>(route),
// onStartPopGesture: () => _startPopGesture<T>(route),
// child: child)
// : child),
// );
// break;
// case Transition.leftToRight:
// return SlideTransition(
// transformHitTests: false,
// position: Tween<Offset>(
// begin: const Offset(-1.0, 0.0),
// end: Offset.zero,
// ).animate(animation),
// child: new SlideTransition(
// position: new Tween<Offset>(
// begin: Offset.zero,
// end: const Offset(1.0, 0.0),
// ).animate(secondaryAnimation),
// child: popGesture
// ? _CupertinoBackGestureDetector<T>(
// enabledCallback: () => _isPopGestureEnabled<T>(route),
// onStartPopGesture: () => _startPopGesture<T>(route),
// child: child)
// : child),
// );
// break;
// case Transition.upToDown:
// return SlideTransition(
// transformHitTests: false,
// position: Tween<Offset>(
// begin: const Offset(0.0, -1.0),
// end: Offset.zero,
// ).animate(animation),
// child: new SlideTransition(
// position: new Tween<Offset>(
// begin: Offset.zero,
// end: const Offset(0.0, 1.0),
// ).animate(secondaryAnimation),
// child: popGesture
// ? _CupertinoBackGestureDetector<T>(
// enabledCallback: () => _isPopGestureEnabled<T>(route),
// onStartPopGesture: () => _startPopGesture<T>(route),
// child: child)
// : child),
// );
// break;
// case Transition.downToUp:
// return SlideTransition(
// transformHitTests: false,
// position: Tween<Offset>(
// begin: const Offset(0.0, 1.0),
// end: Offset.zero,
// ).animate(animation),
// child: new SlideTransition(
// position: new Tween<Offset>(
// begin: Offset.zero,
// end: const Offset(0.0, -1.0),
// ).animate(secondaryAnimation),
// child: popGesture
// ? _CupertinoBackGestureDetector<T>(
// enabledCallback: () => _isPopGestureEnabled<T>(route),
// onStartPopGesture: () => _startPopGesture<T>(route),
// child: child)
// : child),
// );
// break;
// case Transition.rightToLeftWithFade:
// return SlideTransition(
// position: Tween<Offset>(
// begin: const Offset(1.0, 0.0),
// end: Offset.zero,
// ).animate(animation),
// child: FadeTransition(
// opacity: animation,
// child: SlideTransition(
// position: Tween<Offset>(
// begin: Offset.zero,
// end: const Offset(-1.0, 0.0),
// ).animate(secondaryAnimation),
// child: popGesture
// ? _CupertinoBackGestureDetector<T>(
// enabledCallback: () => _isPopGestureEnabled<T>(route),
// onStartPopGesture: () => _startPopGesture<T>(route),
// child: child)
// : child),
// ),
// );
// break;
// case Transition.leftToRightWithFade:
// return SlideTransition(
// position: Tween<Offset>(
// begin: const Offset(-1.0, 0.0),
// end: Offset.zero,
// ).animate(animation),
// child: FadeTransition(
// opacity: animation,
// child: SlideTransition(
// position: Tween<Offset>(
// begin: Offset.zero,
// end: const Offset(1.0, 0.0),
// ).animate(secondaryAnimation),
// child: popGesture
// ? _CupertinoBackGestureDetector<T>(
// enabledCallback: () => _isPopGestureEnabled<T>(route),
// onStartPopGesture: () => _startPopGesture<T>(route),
// child: child)
// : child),
// ),
// );
// break;
// default:
// return CupertinoPageTransition(
// primaryRouteAnimation: animation,
// secondaryRouteAnimation: secondaryAnimation,
// // Check if the route has an animation that's currently participating
// // in a back swipe gesture.
// //
// // In the middle of a back gesture drag, let the transition be linear to
// // match finger motions.
// linearTransition: isPopGestureInProgress(route),
// child: popGesture
// ? _CupertinoBackGestureDetector<T>(
// enabledCallback: () => _isPopGestureEnabled<T>(route),
// onStartPopGesture: () => _startPopGesture<T>(route),
// child: child)
// : child,
// );
// }
// }
// }
// @override
// Widget buildTransitions(BuildContext context, Animation<double> animation,
// Animation<double> secondaryAnimation, Widget child) {
// if (customBuildPageTransitions != null) {
// return customBuildPageTransitions;
// } else {
// return buildPageTransitions<T>(
// this,
// context,
// popGesture ?? GetPlatform.isIOS,
// animation,
// secondaryAnimation,
// child,
// transition,
// curve,
// alignment);
// }
// }
// @override
// String get debugLabel => '${super.debugLabel}(${settings.name})';
// }
// class _CupertinoBackGestureDetector<T> extends StatefulWidget {
// const _CupertinoBackGestureDetector({
// Key key,
// @required this.enabledCallback,
// @required this.onStartPopGesture,
// @required this.child,
// }) : assert(enabledCallback != null),
// assert(onStartPopGesture != null),
// assert(child != null),
// super(key: key);
// final Widget child;
// final ValueGetter<bool> enabledCallback;
// final ValueGetter<_CupertinoBackGestureController<T>> onStartPopGesture;
// @override
// _CupertinoBackGestureDetectorState<T> createState() =>
// _CupertinoBackGestureDetectorState<T>();
// }
// class _CupertinoBackGestureDetectorState<T>
// extends State<_CupertinoBackGestureDetector<T>> {
// _CupertinoBackGestureController<T> _backGestureController;
// HorizontalDragGestureRecognizer _recognizer;
// @override
// void initState() {
// super.initState();
// _recognizer = HorizontalDragGestureRecognizer(debugOwner: this)
// ..onStart = _handleDragStart
// ..onUpdate = _handleDragUpdate
// ..onEnd = _handleDragEnd
// ..onCancel = _handleDragCancel;
// }
// @override
// void dispose() {
// _recognizer.dispose();
// super.dispose();
// }
// void _handleDragStart(DragStartDetails details) {
// assert(mounted);
// assert(_backGestureController == null);
// _backGestureController = widget.onStartPopGesture();
// }
// void _handleDragUpdate(DragUpdateDetails details) {
// assert(mounted);
// assert(_backGestureController != null);
// _backGestureController.dragUpdate(
// _convertToLogical(details.primaryDelta / context.size.width));
// }
// void _handleDragEnd(DragEndDetails details) {
// assert(mounted);
// assert(_backGestureController != null);
// _backGestureController.dragEnd(_convertToLogical(
// details.velocity.pixelsPerSecond.dx / context.size.width));
// _backGestureController = null;
// }
// void _handleDragCancel() {
// assert(mounted);
// // This can be called even if start is not called, paired with the "down" event
// // that we don't consider here.
// _backGestureController?.dragEnd(0.0);
// _backGestureController = null;
// }
// void _handlePointerDown(PointerDownEvent event) {
// if (widget.enabledCallback()) _recognizer.addPointer(event);
// }
// double _convertToLogical(double value) {
// switch (Directionality.of(context)) {
// case TextDirection.rtl:
// return -value;
// case TextDirection.ltr:
// return value;
// }
// return null;
// }
// @override
// Widget build(BuildContext context) {
// assert(debugCheckHasDirectionality(context));
// // For devices with notches, the drag area needs to be larger on the side
// // that has the notch.
// double dragAreaWidth = Directionality.of(context) == TextDirection.ltr
// ? MediaQuery.of(context).padding.left
// : MediaQuery.of(context).padding.right;
// dragAreaWidth = max(dragAreaWidth, _kBackGestureWidth);
// return Stack(
// fit: StackFit.passthrough,
// children: <Widget>[
// widget.child,
// PositionedDirectional(
// start: 0.0,
// width: dragAreaWidth,
// top: 0.0,
// bottom: 0.0,
// child: Listener(
// onPointerDown: _handlePointerDown,
// behavior: HitTestBehavior.translucent,
// ),
// ),
// ],
// );
// }
// }
// class _CupertinoBackGestureController<T> {
// /// Creates a controller for an iOS-style back gesture.
// ///
// /// The [navigator] and [controller] arguments must not be null.
// _CupertinoBackGestureController({
// @required this.navigator,
// @required this.controller,
// }) : assert(navigator != null),
// assert(controller != null) {
// navigator.didStartUserGesture();
// }
// final AnimationController controller;
// final NavigatorState navigator;
// /// The drag gesture has changed by [fractionalDelta]. The total range of the
// /// drag should be 0.0 to 1.0.
// void dragUpdate(double delta) {
// controller.value -= delta;
// }
// /// The drag gesture has ended with a horizontal motion of
// /// [fractionalVelocity] as a fraction of screen width per second.
// void dragEnd(double velocity) {
// // Fling in the appropriate direction.
// // AnimationController.fling is guaranteed to
// // take at least one frame.
// //
// // This curve has been determined through rigorously eyeballing native iOS
// // animations.
// const Curve animationCurve = Curves.fastLinearToSlowEaseIn;
// bool animateForward;
// // If the user releases the page before mid screen with sufficient velocity,
// // or after mid screen, we should animate the page out. Otherwise, the page
// // should be animated back in.
// if (velocity.abs() >= _kMinFlingVelocity)
// animateForward = velocity <= 0;
// else
// animateForward = controller.value > 0.5;
// if (animateForward) {
// // The closer the panel is to dismissing, the shorter the animation is.
// // We want to cap the animation time, but we want to use a linear curve
// // to determine it.
// final int droppedPageForwardAnimationTime = min(
// lerpDouble(
// _kMaxDroppedSwipePageForwardAnimationTime, 0, controller.value)
// .floor(),
// _kMaxPageBackAnimationTime,
// );
// controller.animateTo(1.0,
// duration: Duration(milliseconds: droppedPageForwardAnimationTime),
// curve: animationCurve);
// } else {
// // This route is destined to pop at this point. Reuse navigator's pop.
// navigator.pop();
// // The popping may have finished inline if already at the target destination.
// if (controller.isAnimating) {
// // Otherwise, use a custom popping animation duration and curve.
// final int droppedPageBackAnimationTime = lerpDouble(
// 0, _kMaxDroppedSwipePageForwardAnimationTime, controller.value)
// .floor();
// controller.animateBack(0.0,
// duration: Duration(milliseconds: droppedPageBackAnimationTime),
// curve: animationCurve);
// }
// }
// if (controller.isAnimating) {
// // Keep the userGestureInProgress in true state so we don't change the
// // curve of the page transition mid-flight since CupertinoPageTransition
// // depends on userGestureInProgress.
// AnimationStatusListener animationStatusCallback;
// animationStatusCallback = (AnimationStatus status) {
// navigator.didStopUserGesture();
// controller.removeStatusListener(animationStatusCallback);
// };
// controller.addStatusListener(animationStatusCallback);
// } else {
// navigator.didStopUserGesture();
// }
// }
// }
... ...
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'transitions_component.dart';
class LeftToRightFadeTransition extends TransitionInterface {
LeftToRightFadeTransition({
TransitionComponent transitionComponent,
}) : super(transitionComponent: transitionComponent);
@override
Widget buildChildWithTransition(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(-1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: FadeTransition(
opacity: animation,
child: SlideTransition(
position: Tween<Offset>(
begin: Offset.zero,
end: const Offset(1.0, 0.0),
).animate(secondaryAnimation),
child: child),
),
);
}
}
class RightToLeftFadeTransition extends TransitionInterface {
RightToLeftFadeTransition({
TransitionComponent transitionComponent,
}) : super(transitionComponent: transitionComponent);
@override
Widget buildChildWithTransition(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
return SlideTransition(
position: Tween<Offset>(
begin: const Offset(1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: FadeTransition(
opacity: animation,
child: SlideTransition(
position: Tween<Offset>(
begin: Offset.zero,
end: const Offset(-1.0, 0.0),
).animate(secondaryAnimation),
child: child),
),
);
}
}
class NoTransition extends TransitionInterface {
NoTransition({
TransitionComponent transitionComponent,
}) : super(transitionComponent: transitionComponent);
@override
Widget buildChildWithTransition(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
return transitionComponent.buildChildWithTransition(
context, animation, secondaryAnimation, child);
}
}
class FadeInTransition extends TransitionInterface {
FadeInTransition({
TransitionComponent transitionComponent,
}) : super(transitionComponent: transitionComponent);
@override
Widget buildChildWithTransition(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
return FadeTransition(
opacity: animation,
child: transitionComponent.buildChildWithTransition(
context, animation, secondaryAnimation, child),
);
}
}
class SlideDownTransition extends TransitionInterface {
SlideDownTransition({
TransitionComponent transitionComponent,
}) : super(transitionComponent: transitionComponent);
@override
Widget buildChildWithTransition(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
return SlideTransition(
position: Tween<Offset>(
begin: Offset(0.0, 1.0),
end: Offset.zero,
).animate(animation),
child: transitionComponent.buildChildWithTransition(
context, animation, secondaryAnimation, child),
);
}
}
class SlideLeftTransition extends TransitionInterface {
SlideLeftTransition({
TransitionComponent transitionComponent,
}) : super(transitionComponent: transitionComponent);
@override
Widget buildChildWithTransition(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
return SlideTransition(
position: Tween<Offset>(
begin: Offset(-1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: transitionComponent.buildChildWithTransition(
context, animation, secondaryAnimation, child),
);
}
}
class SlideRightTransition extends TransitionInterface {
SlideRightTransition({
TransitionComponent transitionComponent,
}) : super(transitionComponent: transitionComponent);
@override
Widget buildChildWithTransition(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
return SlideTransition(
position: Tween<Offset>(
begin: Offset(1.0, 0.0),
end: Offset.zero,
).animate(animation),
child: transitionComponent.buildChildWithTransition(
context, animation, secondaryAnimation, child),
);
}
}
class SlideTopTransition extends TransitionInterface {
SlideTopTransition({
TransitionComponent transitionComponent,
}) : super(transitionComponent: transitionComponent);
@override
Widget buildChildWithTransition(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
return SlideTransition(
position: Tween<Offset>(
begin: Offset(0.0, -1.0),
end: Offset.zero,
).animate(animation),
child: transitionComponent.buildChildWithTransition(
context, animation, secondaryAnimation, child),
);
}
}
class ZoomInTransition extends TransitionInterface {
ZoomInTransition({
TransitionComponent transitionComponent,
}) : super(transitionComponent: transitionComponent);
@override
Widget buildChildWithTransition(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
return ScaleTransition(
scale: animation,
child: transitionComponent.buildChildWithTransition(
context, animation, secondaryAnimation, child),
);
}
}
abstract class TransitionInterface implements TransitionComponent {
TransitionComponent transitionComponent;
TransitionInterface({this.transitionComponent});
}
... ...
... ... @@ -2,47 +2,6 @@ import 'package:flutter/widgets.dart';
import 'package:get/src/routes/bindings_interface.dart';
import 'transitions_type.dart';
class GetRoute {
final Widget page;
final String name;
final bool popGesture;
final Map<String, String> parameter;
final String title;
final Transition transition;
final Curve curve;
final Alignment alignment;
final bool maintainState;
final GetPageBuilder route;
final bool opaque;
final Bindings binding;
final List<Bindings> bindings;
final Widget customTransition;
final Duration transitionDuration;
final bool fullscreenDialog;
final RouteSettings settings;
const GetRoute({
@required this.page,
this.title,
this.name,
this.settings,
this.maintainState = true,
this.curve = Curves.linear,
this.alignment,
this.route,
this.parameter,
this.opaque = true,
this.transitionDuration = const Duration(milliseconds: 400),
this.popGesture,
this.binding,
this.bindings,
this.transition,
this.customTransition,
this.fullscreenDialog = false,
}) : assert(page != null),
assert(maintainState != null),
assert(fullscreenDialog != null);
}
class GetPage {
final String name;
... ...
import 'package:flutter/widgets.dart';
class TransitionComponent {
Widget buildChildWithTransition(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
Widget child) {
return child;
}
}
... ...
import 'default_transitions.dart';
import 'transitions_component.dart';
import 'transitions_type.dart';
class TransitionFilter {
static TransitionComponent newTransitionComponent(
Transition transition,
) {
TransitionComponent transitionComponent = TransitionComponent();
switch (transition) {
case Transition.leftToRight:
return SlideLeftTransition(transitionComponent: transitionComponent);
case Transition.downToUp:
return SlideDownTransition(transitionComponent: transitionComponent);
case Transition.upToDown:
return SlideTopTransition(transitionComponent: transitionComponent);
case Transition.rightToLeft:
return SlideRightTransition(transitionComponent: transitionComponent);
case Transition.zoom:
return ZoomInTransition(transitionComponent: transitionComponent);
case Transition.fadeIn:
return FadeInTransition(transitionComponent: transitionComponent);
case Transition.rightToLeftWithFade:
return RightToLeftFadeTransition(
transitionComponent: transitionComponent);
case Transition.leftToRightWithFade:
return LeftToRightFadeTransition(
transitionComponent: transitionComponent);
default:
return FadeInTransition(transitionComponent: transitionComponent);
}
}
}
... ...
... ... @@ -2,17 +2,16 @@ import 'package:flutter/widgets.dart';
enum Transition {
fade,
fadeIn,
rightToLeft,
leftToRight,
upToDown,
downToUp,
scale,
rotate,
size,
rightToLeftWithFade,
leftToRightWithFade,
cupertino,
custom
zoom,
noTransition,
native
}
typedef GetPageBuilder = Widget Function();
... ...
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;
}
}
typedef void ValueCallback<T>(T v);
typedef ValueCallback<T> = Function(T v);
... ...
... ... @@ -12,6 +12,7 @@ class GetX<T extends DisposableInterface> extends StatefulWidget {
final bool autoRemove;
final bool assignId;
final void Function(State state) initState, dispose, didChangeDependencies;
final void Function(GetX oldWidget, State state) didUpdateWidget;
final T init;
const GetX({
this.builder,
... ... @@ -22,6 +23,7 @@ class GetX<T extends DisposableInterface> extends StatefulWidget {
// this.stream,
this.dispose,
this.didChangeDependencies,
this.didUpdateWidget,
this.init,
// this.streamController
});
... ... @@ -66,6 +68,20 @@ class GetImplXState<T extends DisposableInterface> extends State<GetX<T>> {
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
if (widget.didChangeDependencies != null) {
widget.didChangeDependencies(this);
}
}
@override
void didUpdateWidget(GetX oldWidget) {
super.didUpdateWidget(oldWidget as GetX<T>);
if (widget.didUpdateWidget != null) widget.didUpdateWidget(oldWidget, this);
}
@override
void dispose() {
if (widget.dispose != null) widget.dispose(this);
if (isCreator || widget.assignId) {
... ...
... ... @@ -51,25 +51,26 @@ class _RxImpl<T> implements RxInterface<T> {
Stream<R> map<R>(R mapper(T data)) => stream.map(mapper);
}
class StringX<String> extends _RxImpl<String> {
StringX([String initial]) {
class RxString<String> extends _RxImpl<String> {
RxString([String initial]) {
_value = initial;
}
}
class IntX<int> extends _RxImpl<int> {
IntX([int initial]) {
class RxInt<int> extends _RxImpl<int> {
RxInt([int initial]) {
_value = initial;
}
}
class MapX<K, V> extends RxInterface implements Map<K, V> {
MapX([Map<K, V> initial]) {
class RxMap<K, V> extends RxInterface implements Map<K, V> {
RxMap([Map<K, V> initial]) {
_value = initial;
}
@override
StreamController subject = StreamController<Map<K, V>>.broadcast();
Map<Stream<Map<K, V>>, StreamSubscription> _subscriptions = Map();
final Map<Stream<Map<K, V>>, StreamSubscription> _subscriptions = {};
Map<K, V> _value;
Map<K, V> get value {
... ... @@ -81,7 +82,8 @@ class MapX<K, V> extends RxInterface implements Map<K, V> {
String get string => value.toString();
close() {
@override
void close() {
_subscriptions.forEach((observable, subscription) {
subscription.cancel();
});
... ... @@ -89,7 +91,8 @@ class MapX<K, V> extends RxInterface implements Map<K, V> {
subject.close();
}
addListener(Stream rxGetx) {
@override
void addListener(Stream rxGetx) {
if (_subscriptions.containsKey(rxGetx)) {
return;
}
... ... @@ -118,7 +121,7 @@ class MapX<K, V> extends RxInterface implements Map<K, V> {
subject.add(_value);
}
void addIf(/* bool | Condition */ condition, K key, V value) {
void addIf(condition, K key, V value) {
if (condition is Condition) condition = condition();
if (condition is bool && condition) {
_value[key] = value;
... ... @@ -126,7 +129,7 @@ class MapX<K, V> extends RxInterface implements Map<K, V> {
}
}
void addAllIf(/* bool | Condition */ condition, Map<K, V> values) {
void addAllIf(condition, Map<K, V> values) {
if (condition is Condition) condition = condition();
if (condition is bool && condition) addAll(values);
}
... ... @@ -234,8 +237,8 @@ class MapX<K, V> extends RxInterface implements Map<K, V> {
}
/// Create a list similar to `List<T>`
class ListX<E> extends Iterable<E> implements RxInterface<E> {
ListX([List<E> initial]) {
class RxList<E> extends Iterable<E> implements RxInterface<E> {
RxList([List<E> initial]) {
_list = initial;
}
... ... @@ -411,20 +414,20 @@ typedef bool Condition();
typedef E ChildrenListComposer<S, E>(S value);
class BoolX<bool> extends _RxImpl<bool> {
BoolX([bool initial]) {
class RxBool<bool> extends _RxImpl<bool> {
RxBool([bool initial]) {
_value = initial;
}
}
class DoubleX<double> extends _RxImpl<double> {
DoubleX([double initial]) {
class RxDouble<double> extends _RxImpl<double> {
RxDouble([double initial]) {
_value = initial;
}
}
class NumX<num> extends _RxImpl<num> {
NumX([num initial]) {
class RxNum<num> extends _RxImpl<num> {
RxNum([num initial]) {
_value = initial;
}
}
... ... @@ -436,36 +439,36 @@ class Rx<T> extends _RxImpl<T> {
}
extension StringExtension on String {
StringX<String> get obs => StringX(this);
RxString<String> get obs => RxString(this);
}
extension IntExtension on int {
IntX<int> get obs => IntX(this);
RxInt<int> get obs => RxInt(this);
}
extension DoubleExtension on double {
DoubleX<double> get obs => DoubleX(this);
RxDouble<double> get obs => RxDouble(this);
}
extension BoolExtension on bool {
BoolX<bool> get obs => BoolX(this);
RxBool<bool> get obs => RxBool(this);
}
extension MapExtension<K, V> on Map<K, V> {
MapX<K, V> get obs {
RxMap<K, V> get obs {
if (this != null)
return MapX<K, V>({})..addAll(this);
return RxMap<K, V>({})..addAll(this);
else
return MapX<K, V>(null);
return RxMap<K, V>(null);
}
}
extension ListExtension<E> on List<E> {
ListX<E> get obs {
RxList<E> get obs {
if (this != null)
return ListX<E>([])..addAllNonNull(this);
return RxList<E>([])..addAllNonNull(this);
else
return ListX<E>(null);
return RxList<E>(null);
}
}
... ...
... ... @@ -25,17 +25,6 @@ abstract class RxInterface<T> {
// Stream<S> map<S>(S mapper(T data));
}
class RxController extends DisposableInterface {
@override
void onInit() async {}
@override
void onReady() async {}
@override
void onClose() async {}
}
abstract class DisposableInterface {
/// Called at the exact moment that the widget is allocated in memory.
/// Do not overwrite this method.
... ... @@ -53,5 +42,5 @@ abstract class DisposableInterface {
/// Called before the onDelete method. onClose is used to close events
/// before the controller is destroyed, such as closing streams, for example.
onClose() async {}
onClose() async {}
}
... ...
// import 'dart:async';
// import 'package:flutter/widgets.dart';
// import 'package:get/src/get_main.dart';
// import 'rx_impl.dart';
// import 'rx_interface.dart';
// class ListViewX<T extends RxController> extends StatefulWidget {
// final Widget Function(T, int) builder;
// final bool global;
// final ListX Function(T) list;
// final bool autoRemove;
// final void Function(State state) initState, dispose, didChangeDependencies;
// final T init;
// final int itemCount;
// ListViewX({
// this.builder,
// this.global = true,
// this.autoRemove = true,
// this.initState,
// @required this.list,
// this.itemCount,
// this.dispose,
// this.didChangeDependencies,
// this.init,
// });
// _ListViewXState<T> createState() => _ListViewXState<T>();
// }
// class _ListViewXState<T extends RxController> extends State<ListViewX<T>> {
// RxInterface _observer;
// StreamSubscription _listenSubscription;
// T controller;
// _ListViewXState() {
// _observer = ListX();
// }
// @override
// void initState() {
// if (widget.global) {
// if (Get.isRegistred<T>()) {
// controller = Get.find<T>();
// } else {
// controller = widget.init;
// Get.put<T>(controller);
// }
// } else {
// controller = widget.init;
// }
// if (widget.initState != null) widget.initState(this);
// try {
// controller?.onInit();
// } catch (e) {
// if (Get.isLogEnable) print("Failure on call onInit");
// }
// _listenSubscription = widget.list.call(controller).listen((data) {
// setState(() {});
// });
// super.initState();
// }
// @override
// void dispose() {
// controller?.onClose();
// _listenSubscription?.cancel();
// _observer?.close();
// super.dispose();
// }
// @override
// Widget build(BuildContext context) {
// _observer.close();
// final observer = Get.obs;
// Get.obs = this._observer;
// final result = ListView.builder(
// itemCount: widget.itemCount ?? widget.list.call(controller).length,
// itemBuilder: (context, index) {
// return widget.builder(controller, index);
// });
// Get.obs = observer;
// return result;
// }
// }
... ... @@ -6,7 +6,7 @@ class Debouncer {
Debouncer({this.delay});
call(Function action) {
call(void Function() action) {
_timer?.cancel();
_timer = Timer(delay, action);
}
... ...
import 'dart:math' as math;
class DelegatingList<E> extends DelegatingIterable<E> implements List<E> {
const DelegatingList(List<E> base) : super(base);
List<E> get _listBase => _base;
E operator [](int index) => _listBase[index];
void operator []=(int index, E value) {
_listBase[index] = value;
}
List<E> operator +(List<E> other) => _listBase + other;
void add(E value) {
_listBase.add(value);
}
void addAll(Iterable<E> iterable) {
_listBase.addAll(iterable);
}
Map<int, E> asMap() => _listBase.asMap();
List<T> cast<T>() => _listBase.cast<T>();
void clear() {
_listBase.clear();
}
void fillRange(int start, int end, [E fillValue]) {
_listBase.fillRange(start, end, fillValue);
}
set first(E value) {
if (this.isEmpty) throw RangeError.index(0, this);
this[0] = value;
}
Iterable<E> getRange(int start, int end) => _listBase.getRange(start, end);
int indexOf(E element, [int start = 0]) => _listBase.indexOf(element, start);
int indexWhere(bool test(E element), [int start = 0]) =>
_listBase.indexWhere(test, start);
void insert(int index, E element) {
_listBase.insert(index, element);
}
insertAll(int index, Iterable<E> iterable) {
_listBase.insertAll(index, iterable);
}
set last(E value) {
if (this.isEmpty) throw RangeError.index(0, this);
this[this.length - 1] = value;
}
int lastIndexOf(E element, [int start]) =>
_listBase.lastIndexOf(element, start);
int lastIndexWhere(bool test(E element), [int start]) =>
_listBase.lastIndexWhere(test, start);
set length(int newLength) {
_listBase.length = newLength;
}
bool remove(Object value) => _listBase.remove(value);
E removeAt(int index) => _listBase.removeAt(index);
E removeLast() => _listBase.removeLast();
void removeRange(int start, int end) {
_listBase.removeRange(start, end);
}
void removeWhere(bool test(E element)) {
_listBase.removeWhere(test);
}
void replaceRange(int start, int end, Iterable<E> iterable) {
_listBase.replaceRange(start, end, iterable);
}
void retainWhere(bool test(E element)) {
_listBase.retainWhere(test);
}
@deprecated
List<T> retype<T>() => cast<T>();
Iterable<E> get reversed => _listBase.reversed;
void setAll(int index, Iterable<E> iterable) {
_listBase.setAll(index, iterable);
}
void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
_listBase.setRange(start, end, iterable, skipCount);
}
void shuffle([math.Random random]) {
_listBase.shuffle(random);
}
void sort([int compare(E a, E b)]) {
_listBase.sort(compare);
}
List<E> sublist(int start, [int end]) => _listBase.sublist(start, end);
}
class DelegatingIterable<E> extends _DelegatingIterableBase<E> {
final Iterable<E> _base;
const DelegatingIterable(Iterable<E> base) : _base = base;
}
abstract class _DelegatingIterableBase<E> implements Iterable<E> {
Iterable<E> get _base;
const _DelegatingIterableBase();
bool any(bool test(E element)) => _base.any(test);
Iterable<T> cast<T>() => _base.cast<T>();
bool contains(Object element) => _base.contains(element);
E elementAt(int index) => _base.elementAt(index);
bool every(bool test(E element)) => _base.every(test);
Iterable<T> expand<T>(Iterable<T> f(E element)) => _base.expand(f);
E get first => _base.first;
E firstWhere(bool test(E element), {E orElse()}) =>
_base.firstWhere(test, orElse: orElse);
T fold<T>(T initialValue, T combine(T previousValue, E element)) =>
_base.fold(initialValue, combine);
Iterable<E> followedBy(Iterable<E> other) => _base.followedBy(other);
void forEach(void f(E element)) => _base.forEach(f);
bool get isEmpty => _base.isEmpty;
bool get isNotEmpty => _base.isNotEmpty;
Iterator<E> get iterator => _base.iterator;
String join([String separator = ""]) => _base.join(separator);
E get last => _base.last;
E lastWhere(bool test(E element), {E orElse()}) =>
_base.lastWhere(test, orElse: orElse);
int get length => _base.length;
Iterable<T> map<T>(T f(E element)) => _base.map(f);
E reduce(E combine(E value, E element)) => _base.reduce(combine);
@deprecated
Iterable<T> retype<T>() => cast<T>();
E get single => _base.single;
E singleWhere(bool test(E element), {E orElse()}) {
return _base.singleWhere(test, orElse: orElse);
}
Iterable<E> skip(int n) => _base.skip(n);
Iterable<E> skipWhile(bool test(E value)) => _base.skipWhile(test);
Iterable<E> take(int n) => _base.take(n);
Iterable<E> takeWhile(bool test(E value)) => _base.takeWhile(test);
List<E> toList({bool growable = true}) => _base.toList(growable: growable);
Set<E> toSet() => _base.toSet();
Iterable<E> where(bool test(E element)) => _base.where(test);
Iterable<T> whereType<T>() => _base.whereType<T>();
String toString() => _base.toString();
}
... ... @@ -215,7 +215,7 @@ class GetBar<T extends Object> extends StatefulWidget {
Future<T> show() async {
_snackRoute = route.showSnack<T>(
snack: this,
);
) as SnackRoute<T>;
return await Get.key.currentState.push(_snackRoute);
}
... ...
... ... @@ -3,8 +3,8 @@ import 'package:get/src/get_instance.dart';
import 'package:get/src/root/smart_management.dart';
import 'package:get/src/rx/rx_interface.dart';
class GetController extends DisposableInterface {
List<Updater> _updaters = [];
class GetxController extends DisposableInterface {
final List<Updater> _updaters = [];
/// Update GetBuilder with update();
void update([List<String> ids, bool condition = true]) {
... ... @@ -18,15 +18,17 @@ class GetController extends DisposableInterface {
.forEach((rs) => rs.updater(() {}));
}
@override
void onInit() async {}
@override
void onReady() async {}
@override
void onClose() async {}
}
class GetBuilder<T extends GetController> extends StatefulWidget {
@required
class GetBuilder<T extends GetxController> extends StatefulWidget {
final Widget Function(T) builder;
final bool global;
final String id;
... ... @@ -40,7 +42,7 @@ class GetBuilder<T extends GetController> extends StatefulWidget {
Key key,
this.init,
this.global = true,
this.builder,
@required this.builder,
this.autoRemove = true,
this.assignId = false,
this.initState,
... ... @@ -55,7 +57,7 @@ class GetBuilder<T extends GetController> extends StatefulWidget {
_GetBuilderState<T> createState() => _GetBuilderState<T>();
}
class _GetBuilderState<T extends GetController> extends State<GetBuilder<T>> {
class _GetBuilderState<T extends GetxController> extends State<GetBuilder<T>> {
T controller;
Updater real;
bool isCreator = false;
... ... @@ -64,8 +66,8 @@ class _GetBuilderState<T extends GetController> extends State<GetBuilder<T>> {
super.initState();
if (widget.global) {
bool isPrepared = GetInstance().isPrepared<T>(tag: widget.tag);
bool isRegistred = GetInstance().isRegistred<T>(tag: widget.tag);
final isPrepared = GetInstance().isPrepared<T>(tag: widget.tag);
final isRegistred = GetInstance().isRegistred<T>(tag: widget.tag);
if (isPrepared) {
if (GetConfig.smartManagement != SmartManagement.keepFactory) {
... ... @@ -116,13 +118,14 @@ class _GetBuilderState<T extends GetController> extends State<GetBuilder<T>> {
@override
void didChangeDependencies() {
super.didChangeDependencies();
if (widget.didChangeDependencies != null)
if (widget.didChangeDependencies != null) {
widget.didChangeDependencies(this);
}
}
@override
void didUpdateWidget(GetBuilder oldWidget) {
super.didUpdateWidget(oldWidget);
super.didUpdateWidget(oldWidget as GetBuilder<T>);
if (widget.didUpdateWidget != null) widget.didUpdateWidget(oldWidget, this);
}
... ...
import 'package:flutter/widgets.dart';
import 'package:get/src/get_instance.dart';
abstract class GetView<T> extends StatelessWidget {
const GetView({Key key}) : super(key: key);
T get controller => GetInstance().find();
@override
Widget build(BuildContext context);
}
... ...
... ... @@ -2,7 +2,7 @@ import 'package:flutter/widgets.dart';
import 'package:get/src/rx/rx_obx.dart';
import 'get_state.dart';
class MixinBuilder<T extends GetController> extends StatelessWidget {
class MixinBuilder<T extends GetxController> extends StatelessWidget {
@required
final Widget Function(T) builder;
final bool global;
... ...
... ... @@ -15,6 +15,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.0"
characters:
dependency: transitive
description:
name: characters
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
charcode:
dependency: transitive
description:
... ... @@ -35,7 +42,7 @@ packages:
name: collection
url: "https://pub.dartlang.org"
source: hosted
version: "1.14.12"
version: "1.14.13"
fake_async:
dependency: transitive
description:
... ... @@ -59,7 +66,7 @@ packages:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
version: "0.12.6"
version: "0.12.8"
meta:
dependency: transitive
description:
... ... @@ -120,7 +127,7 @@ packages:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.16"
version: "0.2.17"
typed_data:
dependency: transitive
description:
... ...
name: get
description: Open screens/snackbars/dialogs/bottomSheets without context, manage states and inject dependencies easily with Get.
version: 2.14.0
version: 3.0.1
homepage: https://github.com/jonataslaw/get
environment:
... ...
... ... @@ -242,7 +242,7 @@ void main() {
await tester.pumpWidget(
Wrapper(
child: Container(),
defaultTransition: Transition.cupertino,
defaultTransition: Transition.fadeIn,
),
);
... ...
... ... @@ -77,7 +77,7 @@ void main() {
);
}
class Controller extends GetController {
class Controller extends GetxController {
static Controller get to => Get.find();
int count = 0;
var counter = 0.obs;
... ...
... ... @@ -4,7 +4,7 @@ import 'package:get/get.dart';
void main() {
Controller controller = Get.put<Controller>(Controller());
testWidgets("GetController smoke test", (tester) async {
testWidgets("GetxController smoke test", (tester) async {
await tester.pumpWidget(
MaterialApp(
home: Column(
... ... @@ -65,7 +65,7 @@ void main() {
});
}
class Controller extends RxController {
class Controller extends GetxController {
static Controller get to => Get.find();
var counter = 0.obs;
... ...
... ... @@ -4,7 +4,7 @@ import 'package:get/get.dart';
void main() {
Get.lazyPut<Controller2>(() => Controller2());
testWidgets("GetController smoke test", (tester) async {
testWidgets("GetxController smoke test", (tester) async {
await tester.pumpWidget(
MaterialApp(
home: GetX<Controller>(
... ... @@ -76,15 +76,15 @@ void main() {
});
}
class Controller2 extends RxController {
class Controller2 extends GetxController {
int lazy = 0;
}
class ControllerNonGlobal extends RxController {
class ControllerNonGlobal extends GetxController {
int nonGlobal = 0;
}
class Controller extends RxController {
class Controller extends GetxController {
static Controller get to => Get.find();
var counter = 0.obs;
... ...
... ... @@ -4,7 +4,7 @@ import 'package:get/get.dart';
void main() {
Get.lazyPut<Controller2>(() => Controller2());
testWidgets("GetController smoke test", (test) async {
testWidgets("GetxController smoke test", (test) async {
await test.pumpWidget(
MaterialApp(
home: GetBuilder<Controller>(
... ... @@ -81,7 +81,7 @@ void main() {
);
}
class Controller extends GetController {
class Controller extends GetxController {
static Controller get to => Get.find();
int counter = 0;
... ... @@ -96,10 +96,10 @@ class Controller extends GetController {
}
}
class Controller2 extends GetController {
class Controller2 extends GetxController {
int test = 0;
}
class ControllerNonGlobal extends GetController {
class ControllerNonGlobal extends GetxController {
int nonGlobal = 0;
}
... ...
... ... @@ -4,16 +4,18 @@ import 'package:get/src/routes/get_route.dart';
void main() {
testWidgets(
"GetRoute page null",
'GetPage page null',
(WidgetTester testr) async {
expect(() => GetRoute(page: null), throwsAssertionError);
expect(() => GetPage(page: null, name: null), throwsAssertionError);
},
);
testWidgets(
"GetRoute maintainState null",
(WidgetTester testr) async {
expect(() => GetRoute(page: Scaffold(), maintainState: null),
expect(
() =>
GetPage(page: () => Scaffold(), maintainState: null, name: null),
throwsAssertionError);
},
);
... ... @@ -21,7 +23,9 @@ void main() {
testWidgets(
"GetRoute fullscreenDialog null",
(WidgetTester testr) async {
expect(() => GetRoute(page: Scaffold(), fullscreenDialog: null),
expect(
() => GetPage(
page: () => Scaffold(), fullscreenDialog: null, name: null),
throwsAssertionError);
},
);
... ...
... ... @@ -4,9 +4,9 @@ import 'package:get/get.dart';
void main() {
test('once', () async {
final count = 0.obs;
int result = -1;
var result = -1;
once(count, (_) {
result = _;
result = _ as int;
});
count.value++;
await Future.delayed(Duration.zero);
... ... @@ -21,9 +21,9 @@ void main() {
test('ever', () async {
final count = 0.obs;
int result = -1;
var result = -1;
ever(count, (_) {
result = _;
result = _ as int;
});
count.value++;
await Future.delayed(Duration.zero);
... ... @@ -38,10 +38,10 @@ void main() {
test('debounce', () async {
final count = 0.obs;
int result = -1;
var result = -1;
debounce(count, (_) {
print(_);
result = _;
result = _ as int;
}, time: Duration(milliseconds: 100));
count.value++;
... ... @@ -56,10 +56,10 @@ void main() {
test('interval', () async {
final count = 0.obs;
int result = -1;
var result = -1;
interval(count, (_) {
print(_);
result = _;
result = _ as int;
}, time: Duration(milliseconds: 100));
count.value++;
... ...