Jonny Borges
Committed by GitHub

Update to 2.14.0

Added getPages 
Deprecated namedRoutes
Fix transitionDefault
  1 +## [2.14.0]
  2 +- Added getPages API.
  3 +- Deprecated namedPages
  4 +- Fix default transition
  5 +
1 ## [2.13.1] 6 ## [2.13.1]
2 - Added sort to ListX 7 - Added sort to ListX
3 - Prepared the framework for version 3 8 - Prepared the framework for version 3
@@ -102,7 +102,7 @@ This is a simple project but it already makes clear how powerful Get is. As your @@ -102,7 +102,7 @@ This is a simple project but it already makes clear how powerful Get is. As your
102 - [Obx()](#obx) 102 - [Obx()](#obx)
103 - [Workers:](#workers) 103 - [Workers:](#workers)
104 - [Mixing the two state managers](#mixing-the-two-state-managers) 104 - [Mixing the two state managers](#mixing-the-two-state-managers)
105 - - [GetBuilder vs GetX && Obx vs MixinBuilder](#getbuilder-vs-getx--obx-vs-mixinbuilder) 105 + - [GetBuilder vs GetX && Obx vs MixinBuilder](#getbuilder-vs-getx-vs-obx-vs-mixinbuilder)
106 - [Dependency Management](#dependency-management) 106 - [Dependency Management](#dependency-management)
107 - [Simple Instance Manager](#simple-instance-manager) 107 - [Simple Instance Manager](#simple-instance-manager)
108 - [Bindings](#bindings) 108 - [Bindings](#bindings)
@@ -236,11 +236,21 @@ void main() { @@ -236,11 +236,21 @@ void main() {
236 runApp( 236 runApp(
237 GetMaterialApp( 237 GetMaterialApp(
238 initialRoute: '/', 238 initialRoute: '/',
239 - namedRoutes: {  
240 - '/': GetRoute(page: MyHomePage()),  
241 - '/second': GetRoute(page: Second()),  
242 - '/third': GetRoute(page: Third(),transition: Transition.cupertino);  
243 - }, 239 + getPages: [
  240 + GetPage(
  241 + name: '/',
  242 + page: () => MyHomePage(),
  243 + ),
  244 + GetPage(
  245 + name: '/second',
  246 + page: () => Second(),
  247 + ),
  248 + GetPage(
  249 + name: '/third',
  250 + page: () => Third(),
  251 + transition: Transition.cupertino
  252 + ),
  253 + ],
244 ) 254 )
245 ); 255 );
246 } 256 }
@@ -281,15 +291,25 @@ void main() { @@ -281,15 +291,25 @@ void main() {
281 runApp( 291 runApp(
282 GetMaterialApp( 292 GetMaterialApp(
283 initialRoute: '/', 293 initialRoute: '/',
284 - namedRoutes: {  
285 - '/': GetRoute(page: MyHomePage()), 294 + getPages: [
  295 + GetPage(
  296 + name: '/',
  297 + page: () => MyHomePage(),
  298 + ),
  299 + GetPage(
286 /// Important! :user is not a new route, it is just a parameter 300 /// Important! :user is not a new route, it is just a parameter
287 /// specification. Do not use '/second/:user' and '/second' 301 /// specification. Do not use '/second/:user' and '/second'
288 /// if you need new route to user, use '/second/user/:user' 302 /// if you need new route to user, use '/second/user/:user'
289 /// if '/second' is a route. 303 /// if '/second' is a route.
290 - '/second/:user': GetRoute(page: Second()), // receive ID  
291 - '/third': GetRoute(page: Third(),transition: Transition.cupertino);  
292 - }, 304 + name: '/second/:user',
  305 + page: () => Second(),
  306 + ),
  307 + GetPage(
  308 + name: '/third',
  309 + page: () => Third(),
  310 + transition: Transition.cupertino
  311 + ),
  312 + ],
293 ) 313 )
294 ); 314 );
295 } 315 }
@@ -900,6 +920,34 @@ If we change count 2, only count2 and 3 are reconstructed, because the value of @@ -900,6 +920,34 @@ If we change count 2, only count2 and 3 are reconstructed, because the value of
900 920
901 If we add the number 1 to count 1, which already contains 1, no widget is reconstructed. If we add a value of 1 for count 1 and a value of 2 for count 2, only 2 and 3 will be reconstructed, simply because GetX not only changes what is necessary, it avoids duplicating events. 921 If we add the number 1 to count 1, which already contains 1, no widget is reconstructed. If we add a value of 1 for count 1 and a value of 2 for count 2, only 2 and 3 will be reconstructed, simply because GetX not only changes what is necessary, it avoids duplicating events.
902 922
  923 +- NOTE: By default, the first event will allow rebuild even if it is the same. We created this behavior due to dualistic variables, such as Boolean.
  924 +Imagine you did this:
  925 +
  926 +```dart
  927 +var isLogged = false.obs;
  928 +```
  929 +
  930 +and then you check if a user is logged in to trigger an event in "ever".
  931 +
  932 +```dart
  933 +onInit(){
  934 + ever(isLogged, fireRoute);
  935 + isLogged.value = await Preferences.hasToken();
  936 +}
  937 +
  938 +fireRoute(logged) {
  939 + if (logged) {
  940 + Get.off(Home());
  941 + } else {
  942 + Get.off(Login());
  943 + }
  944 +}
  945 +```
  946 +
  947 +if hasToken was false, there would be no change to isLogged, so ever would never be called. To avoid this type of behavior, the first change to an observable will always trigger an event, even if it is the same.
  948 +You can remove this behavior if you want, using:
  949 +`isLogged.firstRebuild = false;`
  950 +
903 In addition, Get provides refined state control. You can condition an event (such as adding an object to a list), on a certain condition. 951 In addition, Get provides refined state control. You can condition an event (such as adding an object to a list), on a certain condition.
904 952
905 ```dart 953 ```dart
@@ -962,6 +1010,7 @@ Camila @@ -962,6 +1010,7 @@ Camila
962 1010
963 ``` 1011 ```
964 1012
  1013 +
965 ### Note about Lists 1014 ### Note about Lists
966 Working with Lists using Get is the best and most enjoyable thing in the world. They are completely observable as are the objects within it. That way, if you add a value to a list, it will automatically rebuild the widgets that use it. 1015 Working with Lists using Get is the best and most enjoyable thing in the world. They are completely observable as are the objects within it. That way, if you add a value to a list, it will automatically rebuild the widgets that use it.
967 You also don't need to use ".value" with lists, the amazing dart api allowed us to remove that, unfortunate primitive types like String and int cannot be extended, making the use of .value mandatory, but that won't be a problem if you work with gets and setters for these. 1016 You also don't need to use ".value" with lists, the amazing dart api allowed us to remove that, unfortunate primitive types like String and int cannot be extended, making the use of .value mandatory, but that won't be a problem if you work with gets and setters for these.
@@ -1029,7 +1078,7 @@ Some people opened a feature request, as they wanted to use only one type of rea @@ -1029,7 +1078,7 @@ Some people opened a feature request, as they wanted to use only one type of rea
1029 Probably using a GetController using GetX and Obx will work, but it will not be possible to use an RxController on a GetBuilder. 1078 Probably using a GetController using GetX and Obx will work, but it will not be possible to use an RxController on a GetBuilder.
1030 Extending these controllers is important, as they have life cycles, and can "start" and "end" events in their onInit() and onClose() methods. 1079 Extending these controllers is important, as they have life cycles, and can "start" and "end" events in their onInit() and onClose() methods.
1031 1080
1032 -## GetBuilder vs GetX && Obx vs MixinBuilder 1081 +## GetBuilder vs GetX vs Obx vs MixinBuilder
1033 In a decade working with programming I was able to learn some valuable lessons. 1082 In a decade working with programming I was able to learn some valuable lessons.
1034 1083
1035 My first contact with reactive programming was so "wow, this is incredible" and in fact reactive programming is incredible. 1084 My first contact with reactive programming was so "wow, this is incredible" and in fact reactive programming is incredible.
@@ -27,4 +27,10 @@ extension Storage on GetImpl { @@ -27,4 +27,10 @@ extension Storage on GetImpl {
27 bool reset({bool clearFactory = true, bool clearRouteBindings = true}) => 27 bool reset({bool clearFactory = true, bool clearRouteBindings = true}) =>
28 GetInstance().reset( 28 GetInstance().reset(
29 clearFactory: clearFactory, clearRouteBindings: clearRouteBindings); 29 clearFactory: clearFactory, clearRouteBindings: clearRouteBindings);
  30 +
  31 + /// Delete class instance on [S] and clean memory
  32 + Future<bool> delete<S>({String tag, String key}) async =>
  33 + GetInstance().delete<S>(tag: tag, key: key);
  34 +
  35 + bool isRegistred<S>({String tag}) => GetInstance().isRegistred<S>(tag: tag);
30 } 36 }
@@ -152,7 +152,7 @@ abstract class GetService { @@ -152,7 +152,7 @@ abstract class GetService {
152 Widget titleText, 152 Widget titleText,
153 Widget messageText, 153 Widget messageText,
154 Widget icon, 154 Widget icon,
155 - bool instantInit = false, 155 + bool instantInit = true,
156 bool shouldIconPulse = true, 156 bool shouldIconPulse = true,
157 double maxWidth, 157 double maxWidth,
158 EdgeInsets margin = const EdgeInsets.all(0.0), 158 EdgeInsets margin = const EdgeInsets.all(0.0),
@@ -239,7 +239,7 @@ abstract class GetService { @@ -239,7 +239,7 @@ abstract class GetService {
239 GlobalKey<NavigatorState> global(int k); 239 GlobalKey<NavigatorState> global(int k);
240 //////////// INSTANCE MANAGER 240 //////////// INSTANCE MANAGER
241 241
242 - setParameter(Map<String, String> param); 242 + // setParameter(Map<String, String> param);
243 243
244 /// give current arguments 244 /// give current arguments
245 Object get arguments; 245 Object get arguments;
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
2 import 'package:flutter/scheduler.dart'; 2 import 'package:flutter/scheduler.dart';
3 import 'package:get/get.dart'; 3 import 'package:get/get.dart';
  4 +import 'package:get/src/get_instance.dart';
4 import 'package:get/src/get_interface.dart'; 5 import 'package:get/src/get_interface.dart';
5 import 'bottomsheet/bottomsheet.dart'; 6 import 'bottomsheet/bottomsheet.dart';
6 import 'platform/platform.dart'; 7 import 'platform/platform.dart';
@@ -133,8 +134,10 @@ class GetImpl implements GetService { @@ -133,8 +134,10 @@ class GetImpl implements GetService {
133 return (isOverlaysClosed); 134 return (isOverlaysClosed);
134 }); 135 });
135 } 136 }
  137 + if (global(id).currentState.canPop()) {
136 global(id).currentState.pop(result); 138 global(id).currentState.pop(result);
137 } 139 }
  140 + }
138 141
139 /// It will close as many screens as you define. Times must be> 0; 142 /// It will close as many screens as you define. Times must be> 0;
140 void close(int times, [int id]) { 143 void close(int times, [int id]) {
@@ -380,7 +383,7 @@ class GetImpl implements GetService { @@ -380,7 +383,7 @@ class GetImpl implements GetService {
380 Widget titleText, 383 Widget titleText,
381 Widget messageText, 384 Widget messageText,
382 Widget icon, 385 Widget icon,
383 - bool instantInit = false, 386 + bool instantInit = true,
384 bool shouldIconPulse = true, 387 bool shouldIconPulse = true,
385 double maxWidth, 388 double maxWidth,
386 EdgeInsets margin = const EdgeInsets.all(0.0), 389 EdgeInsets margin = const EdgeInsets.all(0.0),
@@ -562,24 +565,24 @@ class GetImpl implements GetService { @@ -562,24 +565,24 @@ class GetImpl implements GetService {
562 bool defaultGlobalState, 565 bool defaultGlobalState,
563 Transition defaultTransition}) { 566 Transition defaultTransition}) {
564 if (enableLog != null) { 567 if (enableLog != null) {
565 - enableLog = enableLog; 568 + GetConfig.isLogEnable = enableLog;
566 } 569 }
567 if (defaultPopGesture != null) { 570 if (defaultPopGesture != null) {
568 - defaultPopGesture = defaultPopGesture; 571 + this.defaultPopGesture = defaultPopGesture;
569 } 572 }
570 if (defaultOpaqueRoute != null) { 573 if (defaultOpaqueRoute != null) {
571 - defaultOpaqueRoute = defaultOpaqueRoute; 574 + this.defaultOpaqueRoute = defaultOpaqueRoute;
572 } 575 }
573 if (defaultTransition != null) { 576 if (defaultTransition != null) {
574 - defaultTransition = defaultTransition; 577 + this.defaultTransition = defaultTransition;
575 } 578 }
576 579
577 if (defaultDurationTransition != null) { 580 if (defaultDurationTransition != null) {
578 - defaultDurationTransition = defaultDurationTransition; 581 + this.defaultDurationTransition = defaultDurationTransition;
579 } 582 }
580 583
581 if (defaultGlobalState != null) { 584 if (defaultGlobalState != null) {
582 - defaultGlobalState = defaultGlobalState; 585 + this.defaultGlobalState = defaultGlobalState;
583 } 586 }
584 } 587 }
585 588
@@ -624,11 +627,7 @@ class GetImpl implements GetService { @@ -624,11 +627,7 @@ class GetImpl implements GetService {
624 627
625 Routing _routing = Routing(); 628 Routing _routing = Routing();
626 629
627 - Map<String, String> _parameters = {};  
628 -  
629 - setParameter(Map<String, String> param) {  
630 - _parameters = param;  
631 - } 630 + Map<String, String> parameters = {};
632 631
633 setRouting(Routing rt) { 632 setRouting(Routing rt) {
634 _routing = rt; 633 _routing = rt;
@@ -641,9 +640,6 @@ class GetImpl implements GetService { @@ -641,9 +640,6 @@ class GetImpl implements GetService {
641 /// give current arguments 640 /// give current arguments
642 Object get arguments => _routing.args; 641 Object get arguments => _routing.args;
643 642
644 - /// give current arguments  
645 - Map<String, String> get parameters => _parameters;  
646 -  
647 /// give name from current route 643 /// give name from current route
648 get currentRoute => _routing.current; 644 get currentRoute => _routing.current;
649 645
  1 +import 'package:flutter/widgets.dart';
  2 +import 'package:get/src/routes/get_route.dart';
  3 +
  4 +class GetPageMatch {
  5 + GetPageMatch(this.route);
  6 +
  7 + GetPage route;
  8 + Map<String, String> parameters = <String, String>{};
  9 +}
  10 +
  11 +class ParseRouteTree {
  12 + final List<ParseRouteTreeNode> _nodes = <ParseRouteTreeNode>[];
  13 + bool _hasDefaultRoute = false;
  14 +
  15 + void addRoute(GetPage route) {
  16 + String path = route.name;
  17 +
  18 + if (path == Navigator.defaultRouteName) {
  19 + if (_hasDefaultRoute) {
  20 + throw ("Default route was already defined");
  21 + }
  22 + var node = ParseRouteTreeNode(path, ParseRouteTreeNodeType.component);
  23 + node.routes = [route];
  24 + _nodes.add(node);
  25 + _hasDefaultRoute = true;
  26 + return;
  27 + }
  28 + if (path.startsWith("/")) {
  29 + path = path.substring(1);
  30 + }
  31 + List<String> pathComponents = path.split('/');
  32 + ParseRouteTreeNode parent;
  33 + for (int i = 0; i < pathComponents.length; i++) {
  34 + String component = pathComponents[i];
  35 + ParseRouteTreeNode node = _nodeForComponent(component, parent);
  36 + if (node == null) {
  37 + ParseRouteTreeNodeType type = _typeForComponent(component);
  38 + node = ParseRouteTreeNode(component, type);
  39 + node.parent = parent;
  40 + if (parent == null) {
  41 + _nodes.add(node);
  42 + } else {
  43 + parent.nodes.add(node);
  44 + }
  45 + }
  46 + if (i == pathComponents.length - 1) {
  47 + if (node.routes == null) {
  48 + node.routes = [route];
  49 + } else {
  50 + node.routes.add(route);
  51 + }
  52 + }
  53 + parent = node;
  54 + }
  55 + }
  56 +
  57 + GetPageMatch matchRoute(String path) {
  58 + String usePath = path;
  59 + if (usePath.startsWith("/")) {
  60 + usePath = path.substring(1);
  61 + }
  62 + List<String> components = usePath.split("/");
  63 + if (path == Navigator.defaultRouteName) {
  64 + components = ["/"];
  65 + }
  66 +
  67 + Map<ParseRouteTreeNode, ParseRouteTreeNodeMatch> nodeMatches =
  68 + <ParseRouteTreeNode, ParseRouteTreeNodeMatch>{};
  69 + List<ParseRouteTreeNode> nodesToCheck = _nodes;
  70 + for (String checkComponent in components) {
  71 + Map<ParseRouteTreeNode, ParseRouteTreeNodeMatch> currentMatches =
  72 + <ParseRouteTreeNode, ParseRouteTreeNodeMatch>{};
  73 + List<ParseRouteTreeNode> nextNodes = <ParseRouteTreeNode>[];
  74 + for (ParseRouteTreeNode node in nodesToCheck) {
  75 + String pathPart = checkComponent;
  76 + Map<String, String> queryMap = {};
  77 +
  78 + if (checkComponent.contains("?") && !checkComponent.contains("=")) {
  79 + var splitParam = checkComponent.split("?");
  80 + pathPart = splitParam[0];
  81 + queryMap = {pathPart: splitParam[1]};
  82 + } else if (checkComponent.contains("?")) {
  83 + var splitParam = checkComponent.split("?");
  84 + var splitParam2 = splitParam[1].split("=");
  85 + if (!splitParam2[1].contains("&")) {
  86 + pathPart = splitParam[0];
  87 + queryMap = {splitParam2[0]: splitParam2[1]};
  88 + } else {
  89 + pathPart = splitParam[0];
  90 + final segunda = splitParam[1];
  91 + var other = segunda.split(RegExp(r"[&,=]"));
  92 + for (var i = 0; i < (other.length - 1); i++) {
  93 + bool impar = (i % 2 == 0);
  94 + if (impar) {
  95 + queryMap.addAll({other[0 + i]: other[1 + i]});
  96 + }
  97 + }
  98 + }
  99 + }
  100 +
  101 + bool isMatch = (node.part == pathPart || node.isParameter());
  102 + if (isMatch) {
  103 + ParseRouteTreeNodeMatch parentMatch = nodeMatches[node.parent];
  104 + ParseRouteTreeNodeMatch match =
  105 + ParseRouteTreeNodeMatch.fromMatch(parentMatch, node);
  106 + if (node.isParameter()) {
  107 + String paramKey = node.part.substring(1);
  108 + match.parameters[paramKey] = pathPart;
  109 + }
  110 + if (queryMap != null) {
  111 + match.parameters.addAll(queryMap);
  112 + }
  113 +
  114 + currentMatches[node] = match;
  115 + if (node.nodes != null) {
  116 + nextNodes.addAll(node.nodes);
  117 + }
  118 + }
  119 + }
  120 + nodeMatches = currentMatches;
  121 + nodesToCheck = nextNodes;
  122 + if (currentMatches.values.length == 0) {
  123 + return null;
  124 + }
  125 + }
  126 + List<ParseRouteTreeNodeMatch> matches = nodeMatches.values.toList();
  127 + if (matches.length > 0) {
  128 + ParseRouteTreeNodeMatch match = matches.first;
  129 + ParseRouteTreeNode nodeToUse = match.node;
  130 +
  131 + if (nodeToUse != null &&
  132 + nodeToUse.routes != null &&
  133 + nodeToUse.routes.length > 0) {
  134 + List<GetPage> routes = nodeToUse.routes;
  135 + GetPageMatch routeMatch = GetPageMatch(routes[0]);
  136 +
  137 + routeMatch.parameters = match.parameters;
  138 +
  139 + return routeMatch;
  140 + }
  141 + }
  142 + return null;
  143 + }
  144 +
  145 + ParseRouteTreeNode _nodeForComponent(
  146 + String component, ParseRouteTreeNode parent) {
  147 + List<ParseRouteTreeNode> nodes = _nodes;
  148 + if (parent != null) {
  149 + nodes = parent.nodes;
  150 + }
  151 + for (ParseRouteTreeNode node in nodes) {
  152 + if (node.part == component) {
  153 + return node;
  154 + }
  155 + }
  156 + return null;
  157 + }
  158 +
  159 + ParseRouteTreeNodeType _typeForComponent(String component) {
  160 + ParseRouteTreeNodeType type = ParseRouteTreeNodeType.component;
  161 + if (_isParameterComponent(component)) {
  162 + type = ParseRouteTreeNodeType.parameter;
  163 + }
  164 + return type;
  165 + }
  166 +
  167 + bool _isParameterComponent(String component) {
  168 + return component.startsWith(":");
  169 + }
  170 +
  171 + Map<String, String> parseQueryString(String query) {
  172 + var search = RegExp('([^&=]+)=?([^&]*)');
  173 + var params = Map<String, String>();
  174 + if (query.startsWith('?')) query = query.substring(1);
  175 + decode(String s) => Uri.decodeComponent(s.replaceAll('+', ' '));
  176 + for (Match match in search.allMatches(query)) {
  177 + String key = decode(match.group(1));
  178 + String value = decode(match.group(2));
  179 + params[key] = value;
  180 + }
  181 + return params;
  182 + }
  183 +}
  184 +
  185 +class ParseRouteTreeNodeMatch {
  186 + ParseRouteTreeNodeMatch(this.node);
  187 +
  188 + ParseRouteTreeNodeMatch.fromMatch(ParseRouteTreeNodeMatch match, this.node) {
  189 + parameters = <String, String>{};
  190 + if (match != null) {
  191 + parameters.addAll(match.parameters);
  192 + }
  193 + }
  194 +
  195 + ParseRouteTreeNode node;
  196 + Map<String, String> parameters = <String, String>{};
  197 +}
  198 +
  199 +class ParseRouteTreeNode {
  200 + ParseRouteTreeNode(this.part, this.type);
  201 +
  202 + String part;
  203 + ParseRouteTreeNodeType type;
  204 + List<GetPage> routes = <GetPage>[];
  205 + List<ParseRouteTreeNode> nodes = <ParseRouteTreeNode>[];
  206 + ParseRouteTreeNode parent;
  207 +
  208 + bool isParameter() {
  209 + return type == ParseRouteTreeNodeType.parameter;
  210 + }
  211 +}
  212 +
  213 +enum ParseRouteTreeNodeType {
  214 + component,
  215 + parameter,
  216 +}
@@ -3,6 +3,7 @@ import 'package:get/get.dart'; @@ -3,6 +3,7 @@ import 'package:get/get.dart';
3 import 'package:get/src/routes/get_route.dart'; 3 import 'package:get/src/routes/get_route.dart';
4 import 'package:get/src/routes/utils/parse_arguments.dart'; 4 import 'package:get/src/routes/utils/parse_arguments.dart';
5 import '../get_instance.dart'; 5 import '../get_instance.dart';
  6 +import 'parse_route.dart';
6 import 'root_controller.dart'; 7 import 'root_controller.dart';
7 import 'smart_management.dart'; 8 import 'smart_management.dart';
8 9
@@ -43,11 +44,31 @@ class GetMaterialApp extends StatelessWidget { @@ -43,11 +44,31 @@ class GetMaterialApp extends StatelessWidget {
43 this.routingCallback, 44 this.routingCallback,
44 this.defaultTransition, 45 this.defaultTransition,
45 // this.actions, 46 // this.actions,
  47 + this.getPages,
46 this.opaqueRoute, 48 this.opaqueRoute,
47 this.enableLog, 49 this.enableLog,
48 this.popGesture, 50 this.popGesture,
49 this.transitionDuration, 51 this.transitionDuration,
50 this.defaultGlobalState, 52 this.defaultGlobalState,
  53 + // ignore: deprecated_member_use_from_same_package
  54 + @Deprecated(
  55 + """Please, use new api getPages. You can now simply create a list of GetPages,
  56 + and enter your route name in the 'name' property.
  57 + Page now receives a function ()=> Page(), which allows more flexibility.
  58 + You can now decide which page you want to display, according to the parameters received on the page.
  59 + Example:
  60 + GetPage(
  61 + name: '/second',
  62 + page:(){
  63 + if (Get.parameters['id'] == null) {
  64 + return Login();
  65 + } else {
  66 + return Home();
  67 + }
  68 + });
  69 +
  70 + """)
  71 + // ignore: deprecated_member_use_from_same_package
51 this.namedRoutes, 72 this.namedRoutes,
52 this.unknownRoute, 73 this.unknownRoute,
53 }) : assert(routes != null), 74 }) : assert(routes != null),
@@ -100,11 +121,41 @@ class GetMaterialApp extends StatelessWidget { @@ -100,11 +121,41 @@ class GetMaterialApp extends StatelessWidget {
100 final Bindings initialBinding; 121 final Bindings initialBinding;
101 final Duration transitionDuration; 122 final Duration transitionDuration;
102 final bool defaultGlobalState; 123 final bool defaultGlobalState;
  124 +
103 final Map<String, GetRoute> namedRoutes; 125 final Map<String, GetRoute> namedRoutes;
  126 + final List<GetPage> getPages;
104 final GetRoute unknownRoute; 127 final GetRoute unknownRoute;
105 128
  129 + Route<dynamic> generator(RouteSettings settings) {
  130 + final match = _routeTree.matchRoute(settings.name);
  131 + print(settings.name);
  132 +
  133 + Get.parameters = match?.parameters;
  134 +
  135 + return GetRouteBase(
  136 + page: null,
  137 + title: match.route.title,
  138 + route: match.route.page,
  139 + parameter: match.route.parameter,
  140 + settings:
  141 + RouteSettings(name: settings.name, arguments: settings.arguments),
  142 + maintainState: match.route.maintainState,
  143 + curve: match.route.curve,
  144 + alignment: match.route.alignment,
  145 + opaque: match.route.opaque,
  146 + binding: match.route.binding,
  147 + bindings: match.route.bindings,
  148 + transitionDuration: (transitionDuration == null
  149 + ? match.route.transitionDuration
  150 + : transitionDuration),
  151 + transition: match.route.transition,
  152 + popGesture: match.route.popGesture,
  153 + fullscreenDialog: match.route.fullscreenDialog,
  154 + );
  155 + }
  156 +
106 Route<dynamic> namedRoutesGenerate(RouteSettings settings) { 157 Route<dynamic> namedRoutesGenerate(RouteSettings settings) {
107 - Get.setSettings(settings); 158 + // Get.setSettings(settings);
108 159
109 /// onGenerateRoute to FlutterWeb is Broken on Dev/Master. This is a temporary 160 /// onGenerateRoute to FlutterWeb is Broken on Dev/Master. This is a temporary
110 /// workaround until they fix it, because the problem is with the 'Flutter engine', 161 /// workaround until they fix it, because the problem is with the 'Flutter engine',
@@ -129,7 +180,7 @@ class GetMaterialApp extends StatelessWidget { @@ -129,7 +180,7 @@ class GetMaterialApp extends StatelessWidget {
129 }); 180 });
130 181
131 if (newNamedRoutes.containsKey(settingsName)) { 182 if (newNamedRoutes.containsKey(settingsName)) {
132 - Get.setParameter(parsedString.parameters); 183 + Get.parameters = parsedString.parameters;
133 184
134 return GetRouteBase( 185 return GetRouteBase(
135 page: newNamedRoutes[settingsName].page, 186 page: newNamedRoutes[settingsName].page,
@@ -185,6 +236,12 @@ class GetMaterialApp extends StatelessWidget { @@ -185,6 +236,12 @@ class GetMaterialApp extends StatelessWidget {
185 onDispose?.call(); 236 onDispose?.call();
186 }, 237 },
187 initState: (i) { 238 initState: (i) {
  239 + if (getPages != null) {
  240 + _routeTree = ParseRouteTree();
  241 + getPages.forEach((element) {
  242 + _routeTree.addRoute(element);
  243 + });
  244 + }
188 initialBinding?.dependencies(); 245 initialBinding?.dependencies();
189 GetConfig.smartManagement = smartManagement; 246 GetConfig.smartManagement = smartManagement;
190 onInit?.call(); 247 onInit?.call();
@@ -211,10 +268,40 @@ class GetMaterialApp extends StatelessWidget { @@ -211,10 +268,40 @@ class GetMaterialApp extends StatelessWidget {
211 home: home, 268 home: home,
212 routes: routes ?? const <String, WidgetBuilder>{}, 269 routes: routes ?? const <String, WidgetBuilder>{},
213 initialRoute: initialRoute, 270 initialRoute: initialRoute,
214 - onGenerateRoute: (namedRoutes == null || onUnknownRoute != null  
215 - ? onGenerateRoute  
216 - : namedRoutesGenerate),  
217 - onGenerateInitialRoutes: onGenerateInitialRoutes, 271 + onGenerateRoute: (getPages != null
  272 + ? generator
  273 + : namedRoutes != null ? namedRoutesGenerate : onGenerateRoute),
  274 + onGenerateInitialRoutes: onGenerateInitialRoutes ??
  275 + (getPages == null || home != null)
  276 + ? null
  277 + : (st) {
  278 + final match = _routeTree.matchRoute(initialRoute);
  279 + print(initialRoute);
  280 + print(match.parameters);
  281 + Get.parameters = match.parameters;
  282 + return [
  283 + GetRouteBase(
  284 + page: null,
  285 + route: match.route.page,
  286 + title: match.route.title,
  287 + parameter: match.parameters,
  288 + settings:
  289 + RouteSettings(name: initialRoute, arguments: null),
  290 + maintainState: match.route.maintainState,
  291 + curve: match.route.curve,
  292 + alignment: match.route.alignment,
  293 + opaque: match.route.opaque,
  294 + binding: match.route.binding,
  295 + bindings: match.route.bindings,
  296 + transitionDuration: (transitionDuration == null
  297 + ? match.route.transitionDuration
  298 + : transitionDuration),
  299 + transition: match.route.transition,
  300 + popGesture: match.route.popGesture,
  301 + fullscreenDialog: match.route.fullscreenDialog,
  302 + )
  303 + ];
  304 + },
218 onUnknownRoute: onUnknownRoute, 305 onUnknownRoute: onUnknownRoute,
219 navigatorObservers: (navigatorObservers == null 306 navigatorObservers: (navigatorObservers == null
220 ? <NavigatorObserver>[GetObserver(routingCallback)] 307 ? <NavigatorObserver>[GetObserver(routingCallback)]
@@ -246,3 +333,5 @@ class GetMaterialApp extends StatelessWidget { @@ -246,3 +333,5 @@ class GetMaterialApp extends StatelessWidget {
246 }); 333 });
247 } 334 }
248 } 335 }
  336 +
  337 +ParseRouteTree _routeTree;
@@ -31,6 +31,7 @@ class GetRouteBase<T> extends PageRoute<T> { @@ -31,6 +31,7 @@ class GetRouteBase<T> extends PageRoute<T> {
31 this.alignment, 31 this.alignment,
32 this.parameter, 32 this.parameter,
33 this.binding, 33 this.binding,
  34 + this.route,
34 this.bindings, 35 this.bindings,
35 this.customBuildPageTransitions, 36 this.customBuildPageTransitions,
36 this.opaque = true, 37 this.opaque = true,
@@ -39,7 +40,7 @@ class GetRouteBase<T> extends PageRoute<T> { @@ -39,7 +40,7 @@ class GetRouteBase<T> extends PageRoute<T> {
39 this.transition, 40 this.transition,
40 // this.duration = const Duration(milliseconds: 400), 41 // this.duration = const Duration(milliseconds: 400),
41 bool fullscreenDialog = false, 42 bool fullscreenDialog = false,
42 - }) : assert(page != null), 43 + }) : // assert(page != null),
43 assert(maintainState != null), 44 assert(maintainState != null),
44 assert(fullscreenDialog != null), 45 assert(fullscreenDialog != null),
45 // assert(opaque), 46 // assert(opaque),
@@ -56,6 +57,8 @@ class GetRouteBase<T> extends PageRoute<T> { @@ -56,6 +57,8 @@ class GetRouteBase<T> extends PageRoute<T> {
56 /// Builds the primary contents of the route. 57 /// Builds the primary contents of the route.
57 final Widget page; 58 final Widget page;
58 59
  60 + final GetPageBuilder route;
  61 +
59 final Widget customBuildPageTransitions; 62 final Widget customBuildPageTransitions;
60 63
61 final bool popGesture; 64 final bool popGesture;
@@ -196,14 +199,13 @@ class GetRouteBase<T> extends PageRoute<T> { @@ -196,14 +199,13 @@ class GetRouteBase<T> extends PageRoute<T> {
196 @override 199 @override
197 Widget buildPage(BuildContext context, Animation<double> animation, 200 Widget buildPage(BuildContext context, Animation<double> animation,
198 Animation<double> secondaryAnimation) { 201 Animation<double> secondaryAnimation) {
199 - final Widget child = page;  
200 final Widget result = Semantics( 202 final Widget result = Semantics(
201 scopesRoute: true, 203 scopesRoute: true,
202 explicitChildNodes: true, 204 explicitChildNodes: true,
203 - child: child, 205 + child: (route == null ? page : route()),
204 ); 206 );
205 assert(() { 207 assert(() {
206 - if (child == null) { 208 + if (route == null && page == null) {
207 throw FlutterError.fromParts(<DiagnosticsNode>[ 209 throw FlutterError.fromParts(<DiagnosticsNode>[
208 ErrorSummary( 210 ErrorSummary(
209 'The builder for route "${settings.name}" returned null.'), 211 'The builder for route "${settings.name}" returned null.'),
@@ -4,6 +4,7 @@ import 'transitions_type.dart'; @@ -4,6 +4,7 @@ import 'transitions_type.dart';
4 4
5 class GetRoute { 5 class GetRoute {
6 final Widget page; 6 final Widget page;
  7 + final String name;
7 final bool popGesture; 8 final bool popGesture;
8 final Map<String, String> parameter; 9 final Map<String, String> parameter;
9 final String title; 10 final String title;
@@ -11,6 +12,7 @@ class GetRoute { @@ -11,6 +12,7 @@ class GetRoute {
11 final Curve curve; 12 final Curve curve;
12 final Alignment alignment; 13 final Alignment alignment;
13 final bool maintainState; 14 final bool maintainState;
  15 + final GetPageBuilder route;
14 final bool opaque; 16 final bool opaque;
15 final Bindings binding; 17 final Bindings binding;
16 final List<Bindings> bindings; 18 final List<Bindings> bindings;
@@ -22,10 +24,12 @@ class GetRoute { @@ -22,10 +24,12 @@ class GetRoute {
22 const GetRoute({ 24 const GetRoute({
23 @required this.page, 25 @required this.page,
24 this.title, 26 this.title,
  27 + this.name,
25 this.settings, 28 this.settings,
26 this.maintainState = true, 29 this.maintainState = true,
27 this.curve = Curves.linear, 30 this.curve = Curves.linear,
28 this.alignment, 31 this.alignment,
  32 + this.route,
29 this.parameter, 33 this.parameter,
30 this.opaque = true, 34 this.opaque = true,
31 this.transitionDuration = const Duration(milliseconds: 400), 35 this.transitionDuration = const Duration(milliseconds: 400),
@@ -39,3 +43,45 @@ class GetRoute { @@ -39,3 +43,45 @@ class GetRoute {
39 assert(maintainState != null), 43 assert(maintainState != null),
40 assert(fullscreenDialog != null); 44 assert(fullscreenDialog != null);
41 } 45 }
  46 +
  47 +class GetPage {
  48 + final String name;
  49 + final GetPageBuilder page;
  50 + final bool popGesture;
  51 + final Map<String, String> parameter;
  52 + final String title;
  53 + final Transition transition;
  54 + final Curve curve;
  55 + final Alignment alignment;
  56 + final bool maintainState;
  57 + final bool opaque;
  58 + final Bindings binding;
  59 + final List<Bindings> bindings;
  60 + final Widget customTransition;
  61 + final Duration transitionDuration;
  62 + final bool fullscreenDialog;
  63 + final RouteSettings settings;
  64 +
  65 + const GetPage({
  66 + @required this.name,
  67 + @required this.page,
  68 + this.title,
  69 + this.settings,
  70 + this.maintainState = true,
  71 + this.curve = Curves.linear,
  72 + this.alignment,
  73 + this.parameter,
  74 + this.opaque = true,
  75 + this.transitionDuration = const Duration(milliseconds: 400),
  76 + this.popGesture,
  77 + this.binding,
  78 + this.bindings,
  79 + this.transition,
  80 + this.customTransition,
  81 + this.fullscreenDialog = false,
  82 + }) : assert(page != null),
  83 + assert(name != null),
  84 + assert(maintainState != null),
  85 + assert(fullscreenDialog != null);
  86 +}
  87 +
  1 +import 'package:flutter/widgets.dart';
  2 +
1 enum Transition { 3 enum Transition {
2 fade, 4 fade,
3 rightToLeft, 5 rightToLeft,
@@ -12,3 +14,5 @@ enum Transition { @@ -12,3 +14,5 @@ enum Transition {
12 cupertino, 14 cupertino,
13 custom 15 custom
14 } 16 }
  17 +
  18 +typedef GetPageBuilder = Widget Function();
@@ -32,8 +32,11 @@ class _RxImpl<T> implements RxInterface<T> { @@ -32,8 +32,11 @@ class _RxImpl<T> implements RxInterface<T> {
32 }); 32 });
33 } 33 }
34 34
  35 + bool firstRebuild = true;
  36 +
35 set value(T val) { 37 set value(T val) {
36 - if (_value == val) return; 38 + if (_value == val && !firstRebuild) return;
  39 + firstRebuild = false;
37 _value = val; 40 _value = val;
38 subject.add(_value); 41 subject.add(_value);
39 } 42 }
@@ -240,10 +243,10 @@ class ListX<E> extends Iterable<E> implements RxInterface<E> { @@ -240,10 +243,10 @@ class ListX<E> extends Iterable<E> implements RxInterface<E> {
240 Iterator<E> get iterator => _list.iterator; 243 Iterator<E> get iterator => _list.iterator;
241 244
242 @override 245 @override
243 - bool get isEmpty => _list.isEmpty; 246 + bool get isEmpty => value.isEmpty;
244 247
245 @override 248 @override
246 - bool get isNotEmpty => _list.isNotEmpty; 249 + bool get isNotEmpty => value.isNotEmpty;
247 250
248 StreamController<E> subject = StreamController<E>.broadcast(); 251 StreamController<E> subject = StreamController<E>.broadcast();
249 Map<Stream<E>, StreamSubscription> _subscriptions = Map(); 252 Map<Stream<E>, StreamSubscription> _subscriptions = Map();
1 name: get 1 name: get
2 description: Open screens/snackbars/dialogs/bottomSheets without context, manage states and inject dependencies easily with Get. 2 description: Open screens/snackbars/dialogs/bottomSheets without context, manage states and inject dependencies easily with Get.
3 -version: 2.13.1 3 +version: 2.14.0
4 homepage: https://github.com/jonataslaw/get 4 homepage: https://github.com/jonataslaw/get
5 5
6 environment: 6 environment:
@@ -20,11 +20,11 @@ void main() { @@ -20,11 +20,11 @@ void main() {
20 await tester.pumpWidget( 20 await tester.pumpWidget(
21 Wrapper( 21 Wrapper(
22 initialRoute: '/', 22 initialRoute: '/',
23 - namedRoutes: {  
24 - '/': GetRoute(page: FirstScreen()),  
25 - '/second': GetRoute(page: SecondScreen()),  
26 - '/third': GetRoute(page: ThirdScreen())  
27 - }, 23 + namedRoutes: [
  24 + GetPage(page: () => FirstScreen(), name: '/'),
  25 + GetPage(page: () => SecondScreen(), name: '/second'),
  26 + GetPage(page: () => ThirdScreen(), name: '/third'),
  27 + ],
28 child: Container(), 28 child: Container(),
29 ), 29 ),
30 ); 30 );
@@ -58,12 +58,12 @@ void main() { @@ -58,12 +58,12 @@ void main() {
58 await tester.pumpWidget( 58 await tester.pumpWidget(
59 Wrapper( 59 Wrapper(
60 initialRoute: '/', 60 initialRoute: '/',
61 - namedRoutes: {  
62 - '/': GetRoute(page: Container()),  
63 - '/first': GetRoute(page: FirstScreen()),  
64 - '/second': GetRoute(page: SecondScreen()),  
65 - '/third': GetRoute(page: ThirdScreen())  
66 - }, 61 + namedRoutes: [
  62 + GetPage(name: '/', page: () => Container()),
  63 + GetPage(name: '/first', page: () => FirstScreen()),
  64 + GetPage(name: '/second', page: () => SecondScreen()),
  65 + GetPage(name: '/third', page: () => ThirdScreen()),
  66 + ],
67 child: Container(), 67 child: Container(),
68 ), 68 ),
69 ); 69 );
@@ -109,12 +109,12 @@ void main() { @@ -109,12 +109,12 @@ void main() {
109 await tester.pumpWidget( 109 await tester.pumpWidget(
110 Wrapper( 110 Wrapper(
111 initialRoute: '/', 111 initialRoute: '/',
112 - namedRoutes: {  
113 - '/': GetRoute(page: Container()),  
114 - '/first': GetRoute(page: FirstScreen()),  
115 - '/second': GetRoute(page: SecondScreen()),  
116 - '/third': GetRoute(page: ThirdScreen())  
117 - }, 112 + namedRoutes: [
  113 + GetPage(page: () => Container(), name: '/'),
  114 + GetPage(page: () => FirstScreen(), name: '/first'),
  115 + GetPage(page: () => SecondScreen(), name: '/second'),
  116 + GetPage(page: () => ThirdScreen(), name: '/third'),
  117 + ],
118 child: Container(), 118 child: Container(),
119 ), 119 ),
120 ); 120 );
@@ -142,12 +142,12 @@ void main() { @@ -142,12 +142,12 @@ void main() {
142 await tester.pumpWidget( 142 await tester.pumpWidget(
143 Wrapper( 143 Wrapper(
144 initialRoute: '/', 144 initialRoute: '/',
145 - namedRoutes: {  
146 - '/': GetRoute(page: Container()),  
147 - '/first': GetRoute(page: FirstScreen()),  
148 - '/second': GetRoute(page: SecondScreen()),  
149 - '/third': GetRoute(page: ThirdScreen())  
150 - }, 145 + namedRoutes: [
  146 + GetPage(page: () => Container(), name: '/'),
  147 + GetPage(page: () => FirstScreen(), name: '/first'),
  148 + GetPage(page: () => SecondScreen(), name: '/second'),
  149 + GetPage(page: () => ThirdScreen(), name: '/third'),
  150 + ],
151 child: Container(), 151 child: Container(),
152 ), 152 ),
153 ); 153 );
@@ -191,12 +191,12 @@ void main() { @@ -191,12 +191,12 @@ void main() {
191 await tester.pumpWidget( 191 await tester.pumpWidget(
192 Wrapper( 192 Wrapper(
193 initialRoute: '/', 193 initialRoute: '/',
194 - namedRoutes: {  
195 - '/': GetRoute(page: Container()),  
196 - '/first': GetRoute(page: FirstScreen()),  
197 - '/second': GetRoute(page: SecondScreen()),  
198 - '/third': GetRoute(page: ThirdScreen())  
199 - }, 194 + namedRoutes: [
  195 + GetPage(page: () => Container(), name: '/'),
  196 + GetPage(page: () => FirstScreen(), name: '/first'),
  197 + GetPage(page: () => SecondScreen(), name: '/second'),
  198 + GetPage(page: () => ThirdScreen(), name: '/third'),
  199 + ],
200 child: Container(), 200 child: Container(),
201 ), 201 ),
202 ); 202 );
@@ -373,8 +373,6 @@ void main() { @@ -373,8 +373,6 @@ void main() {
373 expect(Get.isSnackbarOpen, true); 373 expect(Get.isSnackbarOpen, true);
374 await tester.pump(const Duration(seconds: 1)); 374 await tester.pump(const Duration(seconds: 1));
375 }); 375 });
376 -  
377 -  
378 } 376 }
379 377
380 class FirstScreen extends StatelessWidget { 378 class FirstScreen extends StatelessWidget {
@@ -3,7 +3,7 @@ import 'package:get/get.dart'; @@ -3,7 +3,7 @@ import 'package:get/get.dart';
3 3
4 class Wrapper extends StatelessWidget { 4 class Wrapper extends StatelessWidget {
5 final Widget child; 5 final Widget child;
6 - final Map<String, GetRoute> namedRoutes; 6 + final List<GetPage> namedRoutes;
7 final String initialRoute; 7 final String initialRoute;
8 final Transition defaultTransition; 8 final Transition defaultTransition;
9 9
@@ -20,7 +20,7 @@ class Wrapper extends StatelessWidget { @@ -20,7 +20,7 @@ class Wrapper extends StatelessWidget {
20 return GetMaterialApp( 20 return GetMaterialApp(
21 defaultTransition: defaultTransition, 21 defaultTransition: defaultTransition,
22 initialRoute: initialRoute, 22 initialRoute: initialRoute,
23 - namedRoutes: namedRoutes, 23 + getPages: namedRoutes,
24 home: Scaffold( 24 home: Scaffold(
25 body: child, 25 body: child,
26 ), 26 ),