Committed by
GitHub
Merge pull request #827 from jonataslaw/dev
Added GetPage childs and middleware
Showing
10 changed files
with
452 additions
and
93 deletions
@@ -9,6 +9,7 @@ export 'src/routes/custom_transition.dart'; | @@ -9,6 +9,7 @@ export 'src/routes/custom_transition.dart'; | ||
9 | export 'src/routes/default_route.dart'; | 9 | export 'src/routes/default_route.dart'; |
10 | export 'src/routes/get_route.dart'; | 10 | export 'src/routes/get_route.dart'; |
11 | export 'src/routes/observers/route_observer.dart'; | 11 | export 'src/routes/observers/route_observer.dart'; |
12 | +export 'src/routes/route_middleware.dart'; | ||
12 | export 'src/routes/transitions_type.dart'; | 13 | export 'src/routes/transitions_type.dart'; |
13 | export 'src/snackbar/snack.dart'; | 14 | export 'src/snackbar/snack.dart'; |
14 | export 'src/snackbar/snack_route.dart'; | 15 | export 'src/snackbar/snack_route.dart'; |
@@ -1043,15 +1043,17 @@ Since version 2.8 it is possible to access the properties | @@ -1043,15 +1043,17 @@ Since version 2.8 it is possible to access the properties | ||
1043 | return WidgetsBinding.instance; | 1043 | return WidgetsBinding.instance; |
1044 | } | 1044 | } |
1045 | 1045 | ||
1046 | - ///The window to which this binding is bound. | ||
1047 | - ui.Window get window => ui.window; | 1046 | + //TODO: Change to ui.SingletonFlutterWindow rather dynamic |
1047 | + //when Flutter update stable. dynamic is used to avoid Breaking Changes | ||
1048 | + /// The window to which this binding is bound. | ||
1049 | + dynamic get window => ui.window; | ||
1048 | 1050 | ||
1049 | - Locale get deviceLocale => window.locale; | 1051 | + Locale get deviceLocale => ui.window.locale; |
1050 | 1052 | ||
1051 | ///The number of device pixels for each logical pixel. | 1053 | ///The number of device pixels for each logical pixel. |
1052 | - double get pixelRatio => window.devicePixelRatio; | 1054 | + double get pixelRatio => ui.window.devicePixelRatio; |
1053 | 1055 | ||
1054 | - Size get size => window.physicalSize / pixelRatio; | 1056 | + Size get size => ui.window.physicalSize / pixelRatio; |
1055 | 1057 | ||
1056 | ///The horizontal extent of this size. | 1058 | ///The horizontal extent of this size. |
1057 | double get width => size.width; | 1059 | double get width => size.width; |
@@ -1061,14 +1063,14 @@ Since version 2.8 it is possible to access the properties | @@ -1061,14 +1063,14 @@ Since version 2.8 it is possible to access the properties | ||
1061 | 1063 | ||
1062 | ///The distance from the top edge to the first unpadded pixel, | 1064 | ///The distance from the top edge to the first unpadded pixel, |
1063 | ///in physical pixels. | 1065 | ///in physical pixels. |
1064 | - double get statusBarHeight => window.padding.top; | 1066 | + double get statusBarHeight => ui.window.padding.top; |
1065 | 1067 | ||
1066 | ///The distance from the bottom edge to the first unpadded pixel, | 1068 | ///The distance from the bottom edge to the first unpadded pixel, |
1067 | ///in physical pixels. | 1069 | ///in physical pixels. |
1068 | - double get bottomBarHeight => window.padding.bottom; | 1070 | + double get bottomBarHeight => ui.window.padding.bottom; |
1069 | 1071 | ||
1070 | ///The system-reported text scale. | 1072 | ///The system-reported text scale. |
1071 | - double get textScaleFactor => window.textScaleFactor; | 1073 | + double get textScaleFactor => ui.window.textScaleFactor; |
1072 | 1074 | ||
1073 | /// give access to TextTheme.of(context) | 1075 | /// give access to TextTheme.of(context) |
1074 | TextTheme get textTheme => theme?.textTheme; | 1076 | TextTheme get textTheme => theme?.textTheme; |
@@ -1080,7 +1082,8 @@ Since version 2.8 it is possible to access the properties | @@ -1080,7 +1082,8 @@ Since version 2.8 it is possible to access the properties | ||
1080 | bool get isDarkMode => (theme.brightness == Brightness.dark); | 1082 | bool get isDarkMode => (theme.brightness == Brightness.dark); |
1081 | 1083 | ||
1082 | /// Check if dark mode theme is enable on platform on android Q+ | 1084 | /// Check if dark mode theme is enable on platform on android Q+ |
1083 | - bool get isPlatformDarkMode => (window.platformBrightness == Brightness.dark); | 1085 | + bool get isPlatformDarkMode => |
1086 | + (ui.window.platformBrightness == Brightness.dark); | ||
1084 | 1087 | ||
1085 | /// give access to Theme.of(context).iconTheme.color | 1088 | /// give access to Theme.of(context).iconTheme.color |
1086 | Color get iconColor => theme?.iconTheme?.color; | 1089 | Color get iconColor => theme?.iconTheme?.color; |
@@ -188,44 +188,7 @@ class GetCupertinoApp extends StatelessWidget { | @@ -188,44 +188,7 @@ class GetCupertinoApp extends StatelessWidget { | ||
188 | super(key: key); | 188 | super(key: key); |
189 | 189 | ||
190 | Route<dynamic> generator(RouteSettings settings) { | 190 | Route<dynamic> generator(RouteSettings settings) { |
191 | - final match = Get.routeTree.matchRoute(settings.name); | ||
192 | - Get.parameters = match?.parameters; | ||
193 | - | ||
194 | - if (match?.route == null) { | ||
195 | - return GetPageRoute( | ||
196 | - page: unknownRoute.page, | ||
197 | - parameter: unknownRoute.parameter, | ||
198 | - settings: | ||
199 | - RouteSettings(name: settings.name, arguments: settings.arguments), | ||
200 | - curve: unknownRoute.curve, | ||
201 | - opaque: unknownRoute.opaque, | ||
202 | - customTransition: unknownRoute.customTransition, | ||
203 | - binding: unknownRoute.binding, | ||
204 | - bindings: unknownRoute.bindings, | ||
205 | - transitionDuration: | ||
206 | - (unknownRoute.transitionDuration ?? Get.defaultTransitionDuration), | ||
207 | - transition: unknownRoute.transition, | ||
208 | - popGesture: unknownRoute.popGesture, | ||
209 | - fullscreenDialog: unknownRoute.fullscreenDialog, | ||
210 | - ); | ||
211 | - } | ||
212 | - | ||
213 | - return GetPageRoute( | ||
214 | - page: match.route.page, | ||
215 | - parameter: match.route.parameter, | ||
216 | - settings: | ||
217 | - RouteSettings(name: settings.name, arguments: settings.arguments), | ||
218 | - curve: match.route.curve, | ||
219 | - opaque: match.route.opaque, | ||
220 | - customTransition: match.route.customTransition, | ||
221 | - binding: match.route.binding, | ||
222 | - bindings: match.route.bindings, | ||
223 | - transitionDuration: | ||
224 | - (match.route.transitionDuration ?? Get.defaultTransitionDuration), | ||
225 | - transition: match.route.transition, | ||
226 | - popGesture: match.route.popGesture, | ||
227 | - fullscreenDialog: match.route.fullscreenDialog, | ||
228 | - ); | 191 | + return PageRedirect(settings, unknownRoute).page(); |
229 | } | 192 | } |
230 | 193 | ||
231 | List<Route<dynamic>> initialRoutesGenerate(String name) { | 194 | List<Route<dynamic>> initialRoutesGenerate(String name) { |
@@ -199,44 +199,7 @@ class GetMaterialApp extends StatelessWidget { | @@ -199,44 +199,7 @@ class GetMaterialApp extends StatelessWidget { | ||
199 | super(key: key); | 199 | super(key: key); |
200 | 200 | ||
201 | Route<dynamic> generator(RouteSettings settings) { | 201 | Route<dynamic> generator(RouteSettings settings) { |
202 | - final match = Get.routeTree.matchRoute(settings.name); | ||
203 | - Get.parameters = match?.parameters; | ||
204 | - | ||
205 | - if (match?.route == null) { | ||
206 | - return GetPageRoute( | ||
207 | - page: unknownRoute.page, | ||
208 | - parameter: unknownRoute.parameter, | ||
209 | - settings: | ||
210 | - RouteSettings(name: settings.name, arguments: settings.arguments), | ||
211 | - curve: unknownRoute.curve, | ||
212 | - opaque: unknownRoute.opaque, | ||
213 | - customTransition: unknownRoute.customTransition, | ||
214 | - binding: unknownRoute.binding, | ||
215 | - bindings: unknownRoute.bindings, | ||
216 | - transitionDuration: | ||
217 | - (unknownRoute.transitionDuration ?? Get.defaultTransitionDuration), | ||
218 | - transition: unknownRoute.transition, | ||
219 | - popGesture: unknownRoute.popGesture, | ||
220 | - fullscreenDialog: unknownRoute.fullscreenDialog, | ||
221 | - ); | ||
222 | - } | ||
223 | - | ||
224 | - return GetPageRoute( | ||
225 | - page: match.route.page, | ||
226 | - parameter: match.route.parameter, | ||
227 | - settings: | ||
228 | - RouteSettings(name: settings.name, arguments: settings.arguments), | ||
229 | - curve: match.route.curve, | ||
230 | - opaque: match.route.opaque, | ||
231 | - customTransition: match.route.customTransition, | ||
232 | - binding: match.route.binding, | ||
233 | - bindings: match.route.bindings, | ||
234 | - transitionDuration: | ||
235 | - (match.route.transitionDuration ?? Get.defaultTransitionDuration), | ||
236 | - transition: match.route.transition, | ||
237 | - popGesture: match.route.popGesture, | ||
238 | - fullscreenDialog: match.route.fullscreenDialog, | ||
239 | - ); | 202 | + return PageRedirect(settings, unknownRoute).page(); |
240 | } | 203 | } |
241 | 204 | ||
242 | List<Route<dynamic>> initialRoutesGenerate(String name) { | 205 | List<Route<dynamic>> initialRoutesGenerate(String name) { |
1 | import 'package:flutter/widgets.dart'; | 1 | import 'package:flutter/widgets.dart'; |
2 | +import 'package:get/get.dart'; | ||
2 | import '../routes/get_route.dart'; | 3 | import '../routes/get_route.dart'; |
3 | 4 | ||
4 | class ParseRouteTree { | 5 | class ParseRouteTree { |
5 | final List<_ParseRouteTreeNode> _nodes = <_ParseRouteTreeNode>[]; | 6 | final List<_ParseRouteTreeNode> _nodes = <_ParseRouteTreeNode>[]; |
6 | 7 | ||
7 | // bool _hasDefaultRoute = false; | 8 | // bool _hasDefaultRoute = false; |
8 | - | ||
9 | void addRoute(GetPage route) { | 9 | void addRoute(GetPage route) { |
10 | var path = route.name; | 10 | var path = route.name; |
11 | 11 | ||
@@ -46,7 +46,56 @@ class ParseRouteTree { | @@ -46,7 +46,56 @@ class ParseRouteTree { | ||
46 | } | 46 | } |
47 | parent = node; | 47 | parent = node; |
48 | } | 48 | } |
49 | + | ||
50 | + // Add Page children. | ||
51 | + for (var page in _flattenPage(route)) { | ||
52 | + addRoute(page); | ||
53 | + } | ||
54 | + } | ||
55 | + | ||
56 | + List<GetPage> _flattenPage(GetPage route) { | ||
57 | + final result = <GetPage>[]; | ||
58 | + if (route.children == null || route.children.isEmpty) { | ||
59 | + return result; | ||
60 | + } | ||
61 | + | ||
62 | + final parentPath = route.name; | ||
63 | + for (var page in route.children) { | ||
64 | + // Add Parent middlewares to children | ||
65 | + final pageMiddlewares = page.middlewares ?? <GetMiddleware>[]; | ||
66 | + pageMiddlewares.addAll(route.middlewares ?? <GetMiddleware>[]); | ||
67 | + result.add(_addChild(page, parentPath, pageMiddlewares)); | ||
68 | + final children = _flattenPage(page); | ||
69 | + for (var child in children) { | ||
70 | + pageMiddlewares.addAll(child.middlewares ?? <GetMiddleware>[]); | ||
71 | + result.add(_addChild(child, parentPath, pageMiddlewares)); | ||
72 | + } | ||
49 | } | 73 | } |
74 | + return result; | ||
75 | + } | ||
76 | + | ||
77 | + /// Change the Path for a [GetPage] | ||
78 | + GetPage _addChild( | ||
79 | + GetPage origin, String parentPath, List<GetMiddleware> middlewares) => | ||
80 | + GetPage( | ||
81 | + name: parentPath + origin.name, | ||
82 | + page: origin.page, | ||
83 | + title: origin.title, | ||
84 | + alignment: origin.alignment, | ||
85 | + transition: origin.transition, | ||
86 | + binding: origin.binding, | ||
87 | + bindings: origin.bindings, | ||
88 | + curve: origin.curve, | ||
89 | + customTransition: origin.customTransition, | ||
90 | + fullscreenDialog: origin.fullscreenDialog, | ||
91 | + maintainState: origin.maintainState, | ||
92 | + opaque: origin.opaque, | ||
93 | + parameter: origin.parameter, | ||
94 | + popGesture: origin.popGesture, | ||
95 | + settings: origin.settings, | ||
96 | + transitionDuration: origin.transitionDuration, | ||
97 | + middlewares: middlewares, | ||
98 | + ); | ||
50 | 99 | ||
51 | _GetPageMatch matchRoute(String path) { | 100 | _GetPageMatch matchRoute(String path) { |
52 | var usePath = path; | 101 | var usePath = path; |
@@ -11,8 +11,8 @@ import 'default_transitions.dart'; | @@ -11,8 +11,8 @@ import 'default_transitions.dart'; | ||
11 | import 'transitions_type.dart'; | 11 | import 'transitions_type.dart'; |
12 | 12 | ||
13 | class GetPageRoute<T> extends PageRoute<T> { | 13 | class GetPageRoute<T> extends PageRoute<T> { |
14 | - GetPageRoute({ | ||
15 | - RouteSettings settings, | 14 | + GetPageRoute( |
15 | + {RouteSettings settings, | ||
16 | this.transitionDuration = const Duration(milliseconds: 300), | 16 | this.transitionDuration = const Duration(milliseconds: 300), |
17 | this.opaque = true, | 17 | this.opaque = true, |
18 | this.parameter, | 18 | this.parameter, |
@@ -30,7 +30,8 @@ class GetPageRoute<T> extends PageRoute<T> { | @@ -30,7 +30,8 @@ class GetPageRoute<T> extends PageRoute<T> { | ||
30 | this.barrierLabel, | 30 | this.barrierLabel, |
31 | this.maintainState = true, | 31 | this.maintainState = true, |
32 | bool fullscreenDialog = false, | 32 | bool fullscreenDialog = false, |
33 | - }) : assert(opaque != null), | 33 | + this.middlewares}) |
34 | + : assert(opaque != null), | ||
34 | assert(barrierDismissible != null), | 35 | assert(barrierDismissible != null), |
35 | assert(maintainState != null), | 36 | assert(maintainState != null), |
36 | assert(fullscreenDialog != null), | 37 | assert(fullscreenDialog != null), |
@@ -68,6 +69,8 @@ class GetPageRoute<T> extends PageRoute<T> { | @@ -68,6 +69,8 @@ class GetPageRoute<T> extends PageRoute<T> { | ||
68 | 69 | ||
69 | final Alignment alignment; | 70 | final Alignment alignment; |
70 | 71 | ||
72 | + final List<GetMiddleware> middlewares; | ||
73 | + | ||
71 | @override | 74 | @override |
72 | final Color barrierColor; | 75 | final Color barrierColor; |
73 | 76 | ||
@@ -113,15 +116,21 @@ class GetPageRoute<T> extends PageRoute<T> { | @@ -113,15 +116,21 @@ class GetPageRoute<T> extends PageRoute<T> { | ||
113 | Animation<double> animation, | 116 | Animation<double> animation, |
114 | Animation<double> secondaryAnimation, | 117 | Animation<double> secondaryAnimation, |
115 | ) { | 118 | ) { |
119 | + | ||
116 | // Get.reference = settings.name ?? routeName; | 120 | // Get.reference = settings.name ?? routeName; |
121 | + | ||
122 | + final middlewareRunner = MiddlewareRunner(middlewares); | ||
123 | + final bindingsToBind = middlewareRunner.runOnBindingsStart(bindings); | ||
124 | + | ||
117 | binding?.dependencies(); | 125 | binding?.dependencies(); |
118 | - if (bindings != null) { | ||
119 | - for (final binding in bindings) { | 126 | + if (bindingsToBind != null) { |
127 | + for (final binding in bindingsToBind) { | ||
120 | binding.dependencies(); | 128 | binding.dependencies(); |
121 | } | 129 | } |
122 | } | 130 | } |
123 | - // final pageWidget = page(); | ||
124 | - return page(); | 131 | + |
132 | + final pageToBuild = middlewareRunner.runOnPageBuildStart(page); | ||
133 | + return middlewareRunner.runOnPageBuilt(pageToBuild()); | ||
125 | } | 134 | } |
126 | 135 | ||
127 | static bool isPopGestureInProgress(PageRoute<dynamic> route) { | 136 | static bool isPopGestureInProgress(PageRoute<dynamic> route) { |
@@ -384,6 +393,10 @@ class GetPageRoute<T> extends PageRoute<T> { | @@ -384,6 +393,10 @@ class GetPageRoute<T> extends PageRoute<T> { | ||
384 | WidgetsBinding.instance.addPostFrameCallback( | 393 | WidgetsBinding.instance.addPostFrameCallback( |
385 | (_) => GetInstance().removeDependencyByRoute("$reference")); | 394 | (_) => GetInstance().removeDependencyByRoute("$reference")); |
386 | } | 395 | } |
396 | + | ||
397 | + final middlewareRunner = MiddlewareRunner(middlewares); | ||
398 | + middlewareRunner.runOnPageDispose(); | ||
399 | + | ||
387 | } | 400 | } |
388 | } | 401 | } |
389 | 402 |
1 | import 'package:flutter/widgets.dart'; | 1 | import 'package:flutter/widgets.dart'; |
2 | + | ||
2 | import '../../../get_instance/get_instance.dart'; | 3 | import '../../../get_instance/get_instance.dart'; |
4 | +import '../../get_navigation.dart'; | ||
3 | import 'custom_transition.dart'; | 5 | import 'custom_transition.dart'; |
4 | import 'transitions_type.dart'; | 6 | import 'transitions_type.dart'; |
5 | 7 | ||
@@ -20,6 +22,8 @@ class GetPage { | @@ -20,6 +22,8 @@ class GetPage { | ||
20 | final Duration transitionDuration; | 22 | final Duration transitionDuration; |
21 | final bool fullscreenDialog; | 23 | final bool fullscreenDialog; |
22 | final RouteSettings settings; | 24 | final RouteSettings settings; |
25 | + final List<GetPage> children; | ||
26 | + final List<GetMiddleware> middlewares; | ||
23 | 27 | ||
24 | const GetPage({ | 28 | const GetPage({ |
25 | @required this.name, | 29 | @required this.name, |
@@ -38,8 +42,52 @@ class GetPage { | @@ -38,8 +42,52 @@ class GetPage { | ||
38 | this.transition, | 42 | this.transition, |
39 | this.customTransition, | 43 | this.customTransition, |
40 | this.fullscreenDialog = false, | 44 | this.fullscreenDialog = false, |
45 | + this.children, | ||
46 | + this.middlewares, | ||
41 | }) : assert(page != null), | 47 | }) : assert(page != null), |
42 | assert(name != null), | 48 | assert(name != null), |
43 | assert(maintainState != null), | 49 | assert(maintainState != null), |
44 | assert(fullscreenDialog != null); | 50 | assert(fullscreenDialog != null); |
51 | + | ||
52 | + GetPage copyWith({ | ||
53 | + String name, | ||
54 | + GetPageBuilder page, | ||
55 | + bool popGesture, | ||
56 | + Map<String, String> parameter, | ||
57 | + String title, | ||
58 | + Transition transition, | ||
59 | + Curve curve, | ||
60 | + Alignment alignment, | ||
61 | + bool maintainState, | ||
62 | + bool opaque, | ||
63 | + Bindings binding, | ||
64 | + List<Bindings> bindings, | ||
65 | + CustomTransition customTransition, | ||
66 | + Duration transitionDuration, | ||
67 | + bool fullscreenDialog, | ||
68 | + RouteSettings settings, | ||
69 | + List<GetPage> children, | ||
70 | + List<GetMiddleware> middlewares, | ||
71 | + }) { | ||
72 | + return GetPage( | ||
73 | + name: name ?? this.name, | ||
74 | + page: page ?? this.page, | ||
75 | + popGesture: popGesture ?? this.popGesture, | ||
76 | + parameter: parameter ?? this.parameter, | ||
77 | + title: title ?? this.title, | ||
78 | + transition: transition ?? this.transition, | ||
79 | + curve: curve ?? this.curve, | ||
80 | + alignment: alignment ?? this.alignment, | ||
81 | + maintainState: maintainState ?? this.maintainState, | ||
82 | + opaque: opaque ?? this.opaque, | ||
83 | + binding: binding ?? this.binding, | ||
84 | + bindings: bindings ?? this.bindings, | ||
85 | + customTransition: customTransition ?? this.customTransition, | ||
86 | + transitionDuration: transitionDuration ?? this.transitionDuration, | ||
87 | + fullscreenDialog: fullscreenDialog ?? this.fullscreenDialog, | ||
88 | + settings: settings ?? this.settings, | ||
89 | + children: children ?? this.children, | ||
90 | + middlewares: middlewares ?? this.middlewares, | ||
91 | + ); | ||
92 | + } | ||
45 | } | 93 | } |
1 | +import 'package:flutter/cupertino.dart'; | ||
2 | +import '../../../get.dart'; | ||
3 | + | ||
4 | +abstract class _RouteMiddleware { | ||
5 | + /// The Order of the Middlewares to run. | ||
6 | + /// | ||
7 | + /// {@tool snippet} | ||
8 | + /// This Middewares will be called in this order. | ||
9 | + /// ```dart | ||
10 | + /// final middlewares = [ | ||
11 | + /// GetMiddleware(priority: 2), | ||
12 | + /// GetMiddleware(priority: 5), | ||
13 | + /// GetMiddleware(priority: 4), | ||
14 | + /// GetMiddleware(priority: -8), | ||
15 | + /// ]; | ||
16 | + /// ``` | ||
17 | + /// -8 => 2 => 4 => 5 | ||
18 | + /// {@end-tool} | ||
19 | + int priority; | ||
20 | + | ||
21 | + /// This function will be called when the page of | ||
22 | + /// the called route is being searched for. | ||
23 | + /// It take RouteSettings as a result an redirect to the new settings or | ||
24 | + /// give it null and there will be no redirecting. | ||
25 | + /// {@tool snippet} | ||
26 | + /// ```dart | ||
27 | + /// GetPage redirect(String route) { | ||
28 | + /// final authService = Get.find<AuthService>(); | ||
29 | + /// return authService.authed.value ? null : RouteSettings(name: '/login'); | ||
30 | + /// } | ||
31 | + /// ``` | ||
32 | + /// {@end-tool} | ||
33 | + RouteSettings redirect(String route); | ||
34 | + | ||
35 | + /// This function will be called when this Page is called | ||
36 | + /// you can use it to change something about the page or give it new page | ||
37 | + /// {@tool snippet} | ||
38 | + /// ```dart | ||
39 | + /// GetPage onPageCalled(GetPage page) { | ||
40 | + /// final authService = Get.find<AuthService>(); | ||
41 | + /// return page.copyWith(title: 'Wellcome ${authService.UserName}'); | ||
42 | + /// } | ||
43 | + /// ``` | ||
44 | + /// {@end-tool} | ||
45 | + GetPage onPageCalled(GetPage page); | ||
46 | + | ||
47 | + /// This function will be called right before the [Bindings] are initialize. | ||
48 | + /// Here you can change [Bindings] for this page | ||
49 | + /// {@tool snippet} | ||
50 | + /// ```dart | ||
51 | + /// List<Bindings> onBindingsStart(List<Bindings> bindings) { | ||
52 | + /// final authService = Get.find<AuthService>(); | ||
53 | + /// if (authService.isAdmin) { | ||
54 | + /// bindings.add(AdminBinding()); | ||
55 | + /// } | ||
56 | + /// return bindings; | ||
57 | + /// } | ||
58 | + /// ``` | ||
59 | + /// {@end-tool} | ||
60 | + List<Bindings> onBindingsStart(List<Bindings> bindings); | ||
61 | + | ||
62 | + /// This function will be called right after the [Bindings] are initialize. | ||
63 | + GetPageBuilder onPageBuildStart(GetPageBuilder page); | ||
64 | + | ||
65 | + /// This function will be called right after the | ||
66 | + /// GetPage.page function is called and will give you the result | ||
67 | + /// of the function. and take the widget that will be showed. | ||
68 | + Widget onPageBuilt(Widget page); | ||
69 | + | ||
70 | + void onPageDispose(); | ||
71 | +} | ||
72 | + | ||
73 | +/// The Page Middlewares. | ||
74 | +/// The Functions will be called in this order | ||
75 | +/// (( [redirect] -> [onPageCalled] -> [onBindingsStart] -> | ||
76 | +/// [onPageBuildStart] -> [onPageBuilt] -> [onPageDispose] )) | ||
77 | +class GetMiddleware implements _RouteMiddleware { | ||
78 | + @override | ||
79 | + int priority = 0; | ||
80 | + | ||
81 | + GetMiddleware({this.priority}); | ||
82 | + | ||
83 | + @override | ||
84 | + RouteSettings redirect(String route) => null; | ||
85 | + | ||
86 | + @override | ||
87 | + GetPage onPageCalled(GetPage page) => page; | ||
88 | + | ||
89 | + @override | ||
90 | + List<Bindings> onBindingsStart(List<Bindings> bindings) => bindings; | ||
91 | + | ||
92 | + @override | ||
93 | + GetPageBuilder onPageBuildStart(GetPageBuilder page) => page; | ||
94 | + | ||
95 | + @override | ||
96 | + Widget onPageBuilt(Widget page) => page; | ||
97 | + | ||
98 | + @override | ||
99 | + void onPageDispose() {} | ||
100 | +} | ||
101 | + | ||
102 | +class MiddlewareRunner { | ||
103 | + MiddlewareRunner(this._middlewares); | ||
104 | + | ||
105 | + final List<GetMiddleware> _middlewares; | ||
106 | + | ||
107 | + List<GetMiddleware> _getMiddlewares() { | ||
108 | + if (_middlewares != null) { | ||
109 | + _middlewares.sort((a, b) => a.priority.compareTo(b.priority)); | ||
110 | + return _middlewares; | ||
111 | + } | ||
112 | + return <GetMiddleware>[]; | ||
113 | + } | ||
114 | + | ||
115 | + GetPage runOnPageCalled(GetPage page) { | ||
116 | + _getMiddlewares().forEach((element) { | ||
117 | + page = element.onPageCalled(page); | ||
118 | + }); | ||
119 | + return page; | ||
120 | + } | ||
121 | + | ||
122 | + RouteSettings runRedirect(String route) { | ||
123 | + RouteSettings to; | ||
124 | + _getMiddlewares().forEach((element) { | ||
125 | + to = element.redirect(route); | ||
126 | + }); | ||
127 | + if (to != null) { | ||
128 | + Get.log('Redirect to $to'); | ||
129 | + } | ||
130 | + return to; | ||
131 | + } | ||
132 | + | ||
133 | + List<Bindings> runOnBindingsStart(List<Bindings> bindings) { | ||
134 | + _getMiddlewares().forEach((element) { | ||
135 | + bindings = element.onBindingsStart(bindings); | ||
136 | + }); | ||
137 | + return bindings; | ||
138 | + } | ||
139 | + | ||
140 | + GetPageBuilder runOnPageBuildStart(GetPageBuilder page) { | ||
141 | + _getMiddlewares().forEach((element) { | ||
142 | + page = element.onPageBuildStart(page); | ||
143 | + }); | ||
144 | + return page; | ||
145 | + } | ||
146 | + | ||
147 | + Widget runOnPageBuilt(Widget page) { | ||
148 | + _getMiddlewares().forEach((element) { | ||
149 | + page = element.onPageBuilt(page); | ||
150 | + }); | ||
151 | + return page; | ||
152 | + } | ||
153 | + | ||
154 | + void runOnPageDispose() => | ||
155 | + _getMiddlewares().forEach((element) => element.onPageDispose()); | ||
156 | +} | ||
157 | + | ||
158 | +class PageRedirect { | ||
159 | + GetPage route; | ||
160 | + GetPage unknownRoute; | ||
161 | + RouteSettings settings; | ||
162 | + bool isUnknown; | ||
163 | + | ||
164 | + PageRedirect(this.settings, this.unknownRoute, | ||
165 | + {this.isUnknown = false, this.route}); | ||
166 | + | ||
167 | + // redirect all pages that needes redirecting | ||
168 | + GetPageRoute page() { | ||
169 | + while (needRecheck()) {} | ||
170 | + return isUnknown | ||
171 | + ? GetPageRoute( | ||
172 | + page: unknownRoute.page, | ||
173 | + parameter: unknownRoute.parameter, | ||
174 | + settings: RouteSettings( | ||
175 | + name: settings.name, arguments: settings.arguments), | ||
176 | + curve: unknownRoute.curve, | ||
177 | + opaque: unknownRoute.opaque, | ||
178 | + customTransition: unknownRoute.customTransition, | ||
179 | + binding: unknownRoute.binding, | ||
180 | + bindings: unknownRoute.bindings, | ||
181 | + transitionDuration: (unknownRoute.transitionDuration ?? | ||
182 | + Get.defaultTransitionDuration), | ||
183 | + transition: unknownRoute.transition, | ||
184 | + popGesture: unknownRoute.popGesture, | ||
185 | + fullscreenDialog: unknownRoute.fullscreenDialog, | ||
186 | + middlewares: unknownRoute.middlewares, | ||
187 | + ) | ||
188 | + : GetPageRoute( | ||
189 | + page: route.page, | ||
190 | + parameter: route.parameter, | ||
191 | + settings: RouteSettings( | ||
192 | + name: settings.name, arguments: settings.arguments), | ||
193 | + curve: route.curve, | ||
194 | + opaque: route.opaque, | ||
195 | + customTransition: route.customTransition, | ||
196 | + binding: route.binding, | ||
197 | + bindings: route.bindings, | ||
198 | + transitionDuration: | ||
199 | + (route.transitionDuration ?? Get.defaultTransitionDuration), | ||
200 | + transition: route.transition, | ||
201 | + popGesture: route.popGesture, | ||
202 | + fullscreenDialog: route.fullscreenDialog, | ||
203 | + middlewares: route.middlewares); | ||
204 | + } | ||
205 | + | ||
206 | + /// check if redirect is needed | ||
207 | + bool needRecheck() { | ||
208 | + final match = Get.routeTree.matchRoute(settings.name); | ||
209 | + Get.parameters = match?.parameters; | ||
210 | + | ||
211 | + // No Match found | ||
212 | + if (match?.route == null) { | ||
213 | + isUnknown = true; | ||
214 | + return false; | ||
215 | + } | ||
216 | + | ||
217 | + final runner = MiddlewareRunner(match.route.middlewares); | ||
218 | + route = runner.runOnPageCalled(match.route); | ||
219 | + | ||
220 | + // No middlewares found return match. | ||
221 | + if (match.route.middlewares == null || match.route.middlewares.isEmpty) { | ||
222 | + return false; | ||
223 | + } | ||
224 | + final newSettings = runner.runRedirect(settings.name); | ||
225 | + if (newSettings == null) { | ||
226 | + return false; | ||
227 | + } | ||
228 | + settings = newSettings; | ||
229 | + return true; | ||
230 | + } | ||
231 | +} |
test/navigation/middleware_test.dart
0 → 100644
1 | +import 'package:flutter/cupertino.dart'; | ||
2 | +import 'package:flutter_test/flutter_test.dart'; | ||
3 | +import 'package:get/get.dart'; | ||
4 | + | ||
5 | +import 'get_main_test.dart'; | ||
6 | + | ||
7 | +class RedirectMiddleware extends GetMiddleware { | ||
8 | + @override | ||
9 | + RouteSettings redirect(String route) => RouteSettings(name: '/second'); | ||
10 | +} | ||
11 | + | ||
12 | +main() { | ||
13 | + testWidgets("Middleware redirect smoke test", (tester) async { | ||
14 | + await tester.pumpWidget( | ||
15 | + GetMaterialApp( | ||
16 | + initialRoute: '/', | ||
17 | + getPages: [ | ||
18 | + GetPage(name: '/', page: () => Container()), | ||
19 | + GetPage( | ||
20 | + name: '/first', | ||
21 | + page: () => FirstScreen(), | ||
22 | + middlewares: [RedirectMiddleware()]), | ||
23 | + GetPage(name: '/second', page: () => SecondScreen()), | ||
24 | + GetPage(name: '/third', page: () => ThirdScreen()), | ||
25 | + ], | ||
26 | + ), | ||
27 | + ); | ||
28 | + | ||
29 | + Get.toNamed('/first'); | ||
30 | + | ||
31 | + await tester.pumpAndSettle(); | ||
32 | + print(Get.routing.current); | ||
33 | + expect(find.byType(SecondScreen), findsOneWidget); | ||
34 | + }); | ||
35 | +} |
test/navigation/parse_route_test.dart
0 → 100644
1 | +import 'package:flutter/cupertino.dart'; | ||
2 | +import 'package:flutter_test/flutter_test.dart'; | ||
3 | +import 'package:get/get.dart'; | ||
4 | +import 'package:get/get_navigation/src/root/parse_route.dart'; | ||
5 | + | ||
6 | +void main() { | ||
7 | + test('Parse Page with children', () { | ||
8 | + final tree = ParseRouteTree(); | ||
9 | + final pageTree = GetPage(name: '/city', page: () => Container(), children: [ | ||
10 | + GetPage(name: '/home', page: () => Container(), children: [ | ||
11 | + GetPage(name: '/bed-room', page: () => Container()), | ||
12 | + GetPage(name: '/living-room', page: () => Container()), | ||
13 | + ]), | ||
14 | + GetPage(name: '/work', page: () => Container(), children: [ | ||
15 | + GetPage(name: '/office', page: () => Container(), children: [ | ||
16 | + GetPage(name: '/pen', page: () => Container()), | ||
17 | + GetPage(name: '/paper', page: () => Container()), | ||
18 | + ]), | ||
19 | + GetPage(name: '/meeting-room', page: () => Container()), | ||
20 | + ]), | ||
21 | + ]); | ||
22 | + | ||
23 | + tree.addRoute(pageTree); | ||
24 | + final searchRoute = '/city/work/office/pen'; | ||
25 | + final match = tree.matchRoute(searchRoute); | ||
26 | + expect(match, isNotNull); | ||
27 | + expect(match.route.name, searchRoute); | ||
28 | + }); | ||
29 | + | ||
30 | + test('Parse Page without children', () { | ||
31 | + final tree = ParseRouteTree(); | ||
32 | + final pageTree = [ | ||
33 | + GetPage(name: '/city', page: () => Container()), | ||
34 | + GetPage(name: '/city/home', page: () => Container()), | ||
35 | + GetPage(name: '/city/home/bed-room', page: () => Container()), | ||
36 | + GetPage(name: '/city/home/living-room', page: () => Container()), | ||
37 | + GetPage(name: '/city/work', page: () => Container()), | ||
38 | + GetPage(name: '/city/work/office', page: () => Container()), | ||
39 | + GetPage(name: '/city/work/office/pen', page: () => Container()), | ||
40 | + GetPage(name: '/city/work/office/paper', page: () => Container()), | ||
41 | + GetPage(name: '/city/work/meeting-room', page: () => Container()), | ||
42 | + ]; | ||
43 | + | ||
44 | + for (var p in pageTree) { | ||
45 | + tree.addRoute(p); | ||
46 | + } | ||
47 | + | ||
48 | + final searchRoute = '/city/work/office/pen'; | ||
49 | + final match = tree.matchRoute(searchRoute); | ||
50 | + expect(match, isNotNull); | ||
51 | + expect(match.route.name, searchRoute); | ||
52 | + }); | ||
53 | +} |
-
Please register or login to post a comment