Showing
8 changed files
with
884 additions
and
547 deletions
@@ -494,6 +494,7 @@ extension GetNavigation on GetInterface { | @@ -494,6 +494,7 @@ extension GetNavigation on GetInterface { | ||
494 | Bindings? binding, | 494 | Bindings? binding, |
495 | bool preventDuplicates = true, | 495 | bool preventDuplicates = true, |
496 | bool? popGesture, | 496 | bool? popGesture, |
497 | + double gestureWidth = 20, | ||
497 | }) { | 498 | }) { |
498 | var routeName = "/${page.runtimeType.toString()}"; | 499 | var routeName = "/${page.runtimeType.toString()}"; |
499 | if (preventDuplicates && routeName == currentRoute) { | 500 | if (preventDuplicates && routeName == currentRoute) { |
@@ -504,6 +505,7 @@ extension GetNavigation on GetInterface { | @@ -504,6 +505,7 @@ extension GetNavigation on GetInterface { | ||
504 | opaque: opaque ?? true, | 505 | opaque: opaque ?? true, |
505 | page: _resolve(page, 'to'), | 506 | page: _resolve(page, 'to'), |
506 | routeName: routeName, | 507 | routeName: routeName, |
508 | + gestureWidth: gestureWidth, | ||
507 | settings: RouteSettings( | 509 | settings: RouteSettings( |
508 | // name: forceRouteName ? '${a.runtimeType}' : '', | 510 | // name: forceRouteName ? '${a.runtimeType}' : '', |
509 | arguments: arguments, | 511 | arguments: arguments, |
@@ -862,6 +864,7 @@ you can only use widgets and widget functions here'''; | @@ -862,6 +864,7 @@ you can only use widgets and widget functions here'''; | ||
862 | bool fullscreenDialog = false, | 864 | bool fullscreenDialog = false, |
863 | bool preventDuplicates = true, | 865 | bool preventDuplicates = true, |
864 | Duration? duration, | 866 | Duration? duration, |
867 | + double gestureWidth = 20, | ||
865 | }) { | 868 | }) { |
866 | var routeName = "/${page.runtimeType.toString()}"; | 869 | var routeName = "/${page.runtimeType.toString()}"; |
867 | if (preventDuplicates && routeName == currentRoute) { | 870 | if (preventDuplicates && routeName == currentRoute) { |
@@ -869,6 +872,7 @@ you can only use widgets and widget functions here'''; | @@ -869,6 +872,7 @@ you can only use widgets and widget functions here'''; | ||
869 | } | 872 | } |
870 | return global(id).currentState?.pushReplacement(GetPageRoute( | 873 | return global(id).currentState?.pushReplacement(GetPageRoute( |
871 | opaque: opaque, | 874 | opaque: opaque, |
875 | + gestureWidth: gestureWidth, | ||
872 | page: _resolve(page, 'off'), | 876 | page: _resolve(page, 'off'), |
873 | binding: binding, | 877 | binding: binding, |
874 | settings: RouteSettings(arguments: arguments), | 878 | settings: RouteSettings(arguments: arguments), |
@@ -923,6 +927,7 @@ you can only use widgets and widget functions here'''; | @@ -923,6 +927,7 @@ you can only use widgets and widget functions here'''; | ||
923 | Transition? transition, | 927 | Transition? transition, |
924 | Curve? curve, | 928 | Curve? curve, |
925 | Duration? duration, | 929 | Duration? duration, |
930 | + double gestureWidth = 20, | ||
926 | }) { | 931 | }) { |
927 | var routeName = "/${page.runtimeType.toString()}"; | 932 | var routeName = "/${page.runtimeType.toString()}"; |
928 | 933 | ||
@@ -932,6 +937,7 @@ you can only use widgets and widget functions here'''; | @@ -932,6 +937,7 @@ you can only use widgets and widget functions here'''; | ||
932 | popGesture: popGesture ?? defaultPopGesture, | 937 | popGesture: popGesture ?? defaultPopGesture, |
933 | page: _resolve(page, 'offAll'), | 938 | page: _resolve(page, 'offAll'), |
934 | binding: binding, | 939 | binding: binding, |
940 | + gestureWidth: gestureWidth, | ||
935 | settings: RouteSettings(arguments: arguments), | 941 | settings: RouteSettings(arguments: arguments), |
936 | fullscreenDialog: fullscreenDialog, | 942 | fullscreenDialog: fullscreenDialog, |
937 | routeName: routeName, | 943 | routeName: routeName, |
@@ -174,11 +174,17 @@ class GetCupertinoApp extends StatelessWidget { | @@ -174,11 +174,17 @@ class GetCupertinoApp extends StatelessWidget { | ||
174 | super(key: key); | 174 | super(key: key); |
175 | 175 | ||
176 | Route<dynamic> generator(RouteSettings settings) { | 176 | Route<dynamic> generator(RouteSettings settings) { |
177 | - return PageRedirect(settings, unknownRoute).page(); | 177 | + return PageRedirect(settings: settings, unknownRoute: unknownRoute).page(); |
178 | } | 178 | } |
179 | 179 | ||
180 | - List<Route<dynamic>> initialRoutesGenerate(String name) => | ||
181 | - [PageRedirect(RouteSettings(name: name), unknownRoute).page()]; | 180 | + List<Route<dynamic>> initialRoutesGenerate(String name) { |
181 | + return [ | ||
182 | + PageRedirect( | ||
183 | + settings: RouteSettings(name: name), | ||
184 | + unknownRoute: unknownRoute, | ||
185 | + ).page() | ||
186 | + ]; | ||
187 | + } | ||
182 | 188 | ||
183 | @override | 189 | @override |
184 | Widget build(BuildContext context) => GetBuilder<GetMaterialController>( | 190 | Widget build(BuildContext context) => GetBuilder<GetMaterialController>( |
@@ -183,11 +183,18 @@ class GetMaterialApp extends StatelessWidget { | @@ -183,11 +183,18 @@ class GetMaterialApp extends StatelessWidget { | ||
183 | initialRoute = null, | 183 | initialRoute = null, |
184 | super(key: key); | 184 | super(key: key); |
185 | 185 | ||
186 | - Route<dynamic> generator(RouteSettings settings) => | ||
187 | - PageRedirect(settings, unknownRoute).page(); | 186 | + Route<dynamic> generator(RouteSettings settings) { |
187 | + return PageRedirect(settings: settings, unknownRoute: unknownRoute).page(); | ||
188 | + } | ||
188 | 189 | ||
189 | - List<Route<dynamic>> initialRoutesGenerate(String name) => | ||
190 | - [PageRedirect(RouteSettings(name: name), unknownRoute).page()]; | 190 | + List<Route<dynamic>> initialRoutesGenerate(String name) { |
191 | + return [ | ||
192 | + PageRedirect( | ||
193 | + settings: RouteSettings(name: name), | ||
194 | + unknownRoute: unknownRoute, | ||
195 | + ).page() | ||
196 | + ]; | ||
197 | + } | ||
191 | 198 | ||
192 | @override | 199 | @override |
193 | Widget build(BuildContext context) => GetBuilder<GetMaterialController>( | 200 | Widget build(BuildContext context) => GetBuilder<GetMaterialController>( |
1 | -import 'dart:math'; | ||
2 | -import 'dart:ui' show lerpDouble; | ||
3 | -import 'package:flutter/cupertino.dart'; | ||
4 | -import 'package:flutter/gestures.dart'; | ||
5 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
6 | -import '../../../get_core/get_core.dart'; | ||
7 | -import '../../../get_instance/get_instance.dart'; | ||
8 | -import '../../get_navigation.dart'; | 2 | + |
3 | +import '../../../get.dart'; | ||
9 | import 'custom_transition.dart'; | 4 | import 'custom_transition.dart'; |
10 | -import 'default_transitions.dart'; | 5 | +import 'get_transition_mixin.dart'; |
6 | +import 'route_middleware.dart'; | ||
11 | import 'transitions_type.dart'; | 7 | import 'transitions_type.dart'; |
12 | 8 | ||
13 | -class GetPageRoute<T> extends PageRoute<T> { | 9 | +class GetPageRoute<T> extends PageRoute<T> with GetPageRouteTransitionMixin<T> { |
10 | + /// Creates a page route for use in an iOS designed app. | ||
11 | + /// | ||
12 | + /// The [builder], [maintainState], and [fullscreenDialog] arguments must not | ||
13 | + /// be null. | ||
14 | GetPageRoute({ | 14 | GetPageRoute({ |
15 | RouteSettings? settings, | 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, |
19 | + this.gestureWidth = 20.0, | ||
19 | this.curve, | 20 | this.curve, |
20 | this.alignment, | 21 | this.alignment, |
21 | this.transition, | 22 | this.transition, |
@@ -27,6 +28,7 @@ class GetPageRoute<T> extends PageRoute<T> { | @@ -27,6 +28,7 @@ class GetPageRoute<T> extends PageRoute<T> { | ||
27 | this.bindings, | 28 | this.bindings, |
28 | this.routeName, | 29 | this.routeName, |
29 | this.page, | 30 | this.page, |
31 | + this.title, | ||
30 | this.barrierLabel, | 32 | this.barrierLabel, |
31 | this.maintainState = true, | 33 | this.maintainState = true, |
32 | bool fullscreenDialog = false, | 34 | bool fullscreenDialog = false, |
@@ -36,35 +38,23 @@ class GetPageRoute<T> extends PageRoute<T> { | @@ -36,35 +38,23 @@ class GetPageRoute<T> extends PageRoute<T> { | ||
36 | 38 | ||
37 | @override | 39 | @override |
38 | final Duration transitionDuration; | 40 | final Duration transitionDuration; |
39 | - | ||
40 | final GetPageBuilder? page; | 41 | final GetPageBuilder? page; |
41 | - | ||
42 | final String? routeName; | 42 | final String? routeName; |
43 | - | ||
44 | final String reference; | 43 | final String reference; |
45 | - | ||
46 | final CustomTransition? customTransition; | 44 | final CustomTransition? customTransition; |
47 | - | ||
48 | final Bindings? binding; | 45 | final Bindings? binding; |
49 | - | ||
50 | final Map<String, String>? parameter; | 46 | final Map<String, String>? parameter; |
51 | - | ||
52 | final List<Bindings>? bindings; | 47 | final List<Bindings>? bindings; |
53 | 48 | ||
54 | @override | 49 | @override |
55 | final bool opaque; | 50 | final bool opaque; |
56 | - | ||
57 | final bool? popGesture; | 51 | final bool? popGesture; |
58 | 52 | ||
59 | @override | 53 | @override |
60 | final bool barrierDismissible; | 54 | final bool barrierDismissible; |
61 | - | ||
62 | final Transition? transition; | 55 | final Transition? transition; |
63 | - | ||
64 | final Curve? curve; | 56 | final Curve? curve; |
65 | - | ||
66 | final Alignment? alignment; | 57 | final Alignment? alignment; |
67 | - | ||
68 | final List<GetMiddleware>? middlewares; | 58 | final List<GetMiddleware>? middlewares; |
69 | 59 | ||
70 | @override | 60 | @override |
@@ -77,308 +67,6 @@ class GetPageRoute<T> extends PageRoute<T> { | @@ -77,308 +67,6 @@ class GetPageRoute<T> extends PageRoute<T> { | ||
77 | final bool maintainState; | 67 | final bool maintainState; |
78 | 68 | ||
79 | @override | 69 | @override |
80 | - bool canTransitionTo(TransitionRoute<dynamic> nextRoute) { | ||
81 | - // Don't perform outgoing animation if the next route is a | ||
82 | - // fullscreen dialog. | ||
83 | - return nextRoute is PageRoute && !nextRoute.fullscreenDialog; | ||
84 | - } | ||
85 | - | ||
86 | - static bool _isPopGestureEnabled<T>(PageRoute<T> route) { | ||
87 | - // ignore: lines_longer_than_80_chars | ||
88 | - if (route.isFirst || | ||
89 | - route.willHandlePopInternally || | ||
90 | - route.hasScopedWillPopCallback || | ||
91 | - route.fullscreenDialog || | ||
92 | - route.animation!.status != AnimationStatus.completed || | ||
93 | - route.secondaryAnimation!.status != AnimationStatus.dismissed || | ||
94 | - isPopGestureInProgress(route)) return false; | ||
95 | - | ||
96 | - return true; | ||
97 | - } | ||
98 | - | ||
99 | - static _CupertinoBackGestureController<T> _startPopGesture<T>( | ||
100 | - PageRoute<T> route) { | ||
101 | - assert(_isPopGestureEnabled(route)); | ||
102 | - | ||
103 | - return _CupertinoBackGestureController<T>( | ||
104 | - navigator: route.navigator!, | ||
105 | - controller: route.controller!, | ||
106 | - ); | ||
107 | - } | ||
108 | - | ||
109 | - @override | ||
110 | - Widget buildPage( | ||
111 | - BuildContext? context, | ||
112 | - Animation<double>? animation, | ||
113 | - Animation<double>? secondaryAnimation, | ||
114 | - ) { | ||
115 | - // Get.reference = settings.name ?? routeName; | ||
116 | - Get.reference = reference; | ||
117 | - | ||
118 | - final middlewareRunner = MiddlewareRunner(middlewares); | ||
119 | - final bindingsToBind = middlewareRunner.runOnBindingsStart(bindings); | ||
120 | - | ||
121 | - binding?.dependencies(); | ||
122 | - if (bindingsToBind != null) { | ||
123 | - for (final binding in bindingsToBind) { | ||
124 | - binding.dependencies(); | ||
125 | - } | ||
126 | - } | ||
127 | - | ||
128 | - final pageToBuild = middlewareRunner.runOnPageBuildStart(page)!; | ||
129 | - return middlewareRunner.runOnPageBuilt(pageToBuild()); | ||
130 | - } | ||
131 | - | ||
132 | - static bool isPopGestureInProgress(PageRoute<dynamic> route) { | ||
133 | - return route.navigator!.userGestureInProgress; | ||
134 | - } | ||
135 | - | ||
136 | - bool get popGestureInProgress => isPopGestureInProgress(this); | ||
137 | - | ||
138 | - @override | ||
139 | - Widget buildTransitions(BuildContext context, Animation<double> animation, | ||
140 | - Animation<double> secondaryAnimation, Widget child) { | ||
141 | - final finalCurve = curve ?? Get.defaultTransitionCurve; | ||
142 | - final hasCurve = curve != null; | ||
143 | - if (fullscreenDialog && transition == null) { | ||
144 | - /// by default, if no curve is defined, use Cupertino transition in the | ||
145 | - /// default way (no linearTransition)... otherwise take the curve passed. | ||
146 | - return CupertinoFullscreenDialogTransition( | ||
147 | - primaryRouteAnimation: hasCurve | ||
148 | - ? CurvedAnimation(parent: animation, curve: finalCurve) | ||
149 | - : animation, | ||
150 | - secondaryRouteAnimation: secondaryAnimation, | ||
151 | - child: child, | ||
152 | - linearTransition: hasCurve); | ||
153 | - } | ||
154 | - if (customTransition != null) { | ||
155 | - return customTransition!.buildTransition( | ||
156 | - context, | ||
157 | - finalCurve, | ||
158 | - alignment, | ||
159 | - animation, | ||
160 | - secondaryAnimation, | ||
161 | - popGesture ?? Get.defaultPopGesture | ||
162 | - ? _CupertinoBackGestureDetector<T>( | ||
163 | - enabledCallback: () => _isPopGestureEnabled<T>(this), | ||
164 | - onStartPopGesture: () => _startPopGesture<T>(this), | ||
165 | - child: child) | ||
166 | - : child, | ||
167 | - ); | ||
168 | - } | ||
169 | - | ||
170 | - /// Apply the curve by default... | ||
171 | - final iosAnimation = animation; | ||
172 | - animation = CurvedAnimation(parent: animation, curve: finalCurve); | ||
173 | - | ||
174 | - switch (transition ?? Get.defaultTransition) { | ||
175 | - case Transition.leftToRight: | ||
176 | - return SlideLeftTransition().buildTransitions( | ||
177 | - context, | ||
178 | - curve, | ||
179 | - alignment, | ||
180 | - animation, | ||
181 | - secondaryAnimation, | ||
182 | - popGesture ?? Get.defaultPopGesture | ||
183 | - ? _CupertinoBackGestureDetector<T>( | ||
184 | - enabledCallback: () => _isPopGestureEnabled<T>(this), | ||
185 | - onStartPopGesture: () => _startPopGesture<T>(this), | ||
186 | - child: child) | ||
187 | - : child); | ||
188 | - | ||
189 | - case Transition.downToUp: | ||
190 | - return SlideDownTransition().buildTransitions( | ||
191 | - context, | ||
192 | - curve, | ||
193 | - alignment, | ||
194 | - animation, | ||
195 | - secondaryAnimation, | ||
196 | - popGesture ?? Get.defaultPopGesture | ||
197 | - ? _CupertinoBackGestureDetector<T>( | ||
198 | - enabledCallback: () => _isPopGestureEnabled<T>(this), | ||
199 | - onStartPopGesture: () => _startPopGesture<T>(this), | ||
200 | - child: child) | ||
201 | - : child); | ||
202 | - | ||
203 | - case Transition.upToDown: | ||
204 | - return SlideTopTransition().buildTransitions( | ||
205 | - context, | ||
206 | - curve, | ||
207 | - alignment, | ||
208 | - animation, | ||
209 | - secondaryAnimation, | ||
210 | - popGesture ?? Get.defaultPopGesture | ||
211 | - ? _CupertinoBackGestureDetector<T>( | ||
212 | - enabledCallback: () => _isPopGestureEnabled<T>(this), | ||
213 | - onStartPopGesture: () => _startPopGesture<T>(this), | ||
214 | - child: child) | ||
215 | - : child); | ||
216 | - | ||
217 | - case Transition.noTransition: | ||
218 | - return popGesture ?? Get.defaultPopGesture | ||
219 | - ? _CupertinoBackGestureDetector<T>( | ||
220 | - enabledCallback: () => _isPopGestureEnabled<T>(this), | ||
221 | - onStartPopGesture: () => _startPopGesture<T>(this), | ||
222 | - child: child) | ||
223 | - : child; | ||
224 | - | ||
225 | - case Transition.rightToLeft: | ||
226 | - return SlideRightTransition().buildTransitions( | ||
227 | - context, | ||
228 | - curve, | ||
229 | - alignment, | ||
230 | - animation, | ||
231 | - secondaryAnimation, | ||
232 | - popGesture ?? Get.defaultPopGesture | ||
233 | - ? _CupertinoBackGestureDetector<T>( | ||
234 | - enabledCallback: () => _isPopGestureEnabled<T>(this), | ||
235 | - onStartPopGesture: () => _startPopGesture<T>(this), | ||
236 | - child: child) | ||
237 | - : child); | ||
238 | - | ||
239 | - case Transition.zoom: | ||
240 | - return ZoomInTransition().buildTransitions( | ||
241 | - context, | ||
242 | - curve, | ||
243 | - alignment, | ||
244 | - animation, | ||
245 | - secondaryAnimation, | ||
246 | - popGesture ?? Get.defaultPopGesture | ||
247 | - ? _CupertinoBackGestureDetector<T>( | ||
248 | - enabledCallback: () => _isPopGestureEnabled<T>(this), | ||
249 | - onStartPopGesture: () => _startPopGesture<T>(this), | ||
250 | - child: child) | ||
251 | - : child); | ||
252 | - | ||
253 | - case Transition.fadeIn: | ||
254 | - return FadeInTransition().buildTransitions( | ||
255 | - context, | ||
256 | - curve, | ||
257 | - alignment, | ||
258 | - animation, | ||
259 | - secondaryAnimation, | ||
260 | - popGesture ?? Get.defaultPopGesture | ||
261 | - ? _CupertinoBackGestureDetector<T>( | ||
262 | - enabledCallback: () => _isPopGestureEnabled<T>(this), | ||
263 | - onStartPopGesture: () => _startPopGesture<T>(this), | ||
264 | - child: child) | ||
265 | - : child); | ||
266 | - | ||
267 | - case Transition.rightToLeftWithFade: | ||
268 | - return RightToLeftFadeTransition().buildTransitions( | ||
269 | - context, | ||
270 | - curve, | ||
271 | - alignment, | ||
272 | - animation, | ||
273 | - secondaryAnimation, | ||
274 | - popGesture ?? Get.defaultPopGesture | ||
275 | - ? _CupertinoBackGestureDetector<T>( | ||
276 | - enabledCallback: () => _isPopGestureEnabled<T>(this), | ||
277 | - onStartPopGesture: () => _startPopGesture<T>(this), | ||
278 | - child: child) | ||
279 | - : child); | ||
280 | - | ||
281 | - case Transition.leftToRightWithFade: | ||
282 | - return LeftToRightFadeTransition().buildTransitions( | ||
283 | - context, | ||
284 | - curve, | ||
285 | - alignment, | ||
286 | - animation, | ||
287 | - secondaryAnimation, | ||
288 | - popGesture ?? Get.defaultPopGesture | ||
289 | - ? _CupertinoBackGestureDetector<T>( | ||
290 | - enabledCallback: () => _isPopGestureEnabled<T>(this), | ||
291 | - onStartPopGesture: () => _startPopGesture<T>(this), | ||
292 | - child: child) | ||
293 | - : child); | ||
294 | - | ||
295 | - case Transition.cupertino: | ||
296 | - return CupertinoPageTransitionsBuilder().buildTransitions( | ||
297 | - this, | ||
298 | - context, | ||
299 | - iosAnimation, | ||
300 | - secondaryAnimation, | ||
301 | - popGesture ?? Get.defaultPopGesture | ||
302 | - ? _CupertinoBackGestureDetector<T>( | ||
303 | - enabledCallback: () => _isPopGestureEnabled<T>(this), | ||
304 | - onStartPopGesture: () => _startPopGesture<T>(this), | ||
305 | - child: child) | ||
306 | - : child); | ||
307 | - | ||
308 | - case Transition.size: | ||
309 | - return SizeTransitions().buildTransitions( | ||
310 | - context, | ||
311 | - curve!, | ||
312 | - alignment, | ||
313 | - animation, | ||
314 | - secondaryAnimation, | ||
315 | - popGesture ?? Get.defaultPopGesture | ||
316 | - ? _CupertinoBackGestureDetector<T>( | ||
317 | - enabledCallback: () => _isPopGestureEnabled<T>(this), | ||
318 | - onStartPopGesture: () => _startPopGesture<T>(this), | ||
319 | - child: child) | ||
320 | - : child); | ||
321 | - | ||
322 | - case Transition.fade: | ||
323 | - return FadeUpwardsPageTransitionsBuilder().buildTransitions( | ||
324 | - this, | ||
325 | - context, | ||
326 | - animation, | ||
327 | - secondaryAnimation, | ||
328 | - popGesture ?? Get.defaultPopGesture | ||
329 | - ? _CupertinoBackGestureDetector<T>( | ||
330 | - enabledCallback: () => _isPopGestureEnabled<T>(this), | ||
331 | - onStartPopGesture: () => _startPopGesture<T>(this), | ||
332 | - child: child) | ||
333 | - : child); | ||
334 | - | ||
335 | - case Transition.topLevel: | ||
336 | - return ZoomPageTransitionsBuilder().buildTransitions( | ||
337 | - this, | ||
338 | - context, | ||
339 | - animation, | ||
340 | - secondaryAnimation, | ||
341 | - popGesture ?? Get.defaultPopGesture | ||
342 | - ? _CupertinoBackGestureDetector<T>( | ||
343 | - enabledCallback: () => _isPopGestureEnabled<T>(this), | ||
344 | - onStartPopGesture: () => _startPopGesture<T>(this), | ||
345 | - child: child) | ||
346 | - : child); | ||
347 | - | ||
348 | - case Transition.native: | ||
349 | - return PageTransitionsTheme().buildTransitions( | ||
350 | - this, | ||
351 | - context, | ||
352 | - iosAnimation, | ||
353 | - secondaryAnimation, | ||
354 | - popGesture ?? Get.defaultPopGesture | ||
355 | - ? _CupertinoBackGestureDetector<T>( | ||
356 | - enabledCallback: () => _isPopGestureEnabled<T>(this), | ||
357 | - onStartPopGesture: () => _startPopGesture<T>(this), | ||
358 | - child: child) | ||
359 | - : child); | ||
360 | - | ||
361 | - default: | ||
362 | - if (Get.customTransition != null) { | ||
363 | - return Get.customTransition!.buildTransition( | ||
364 | - context, curve, alignment, animation, secondaryAnimation, child); | ||
365 | - } | ||
366 | - | ||
367 | - return PageTransitionsTheme().buildTransitions( | ||
368 | - this, | ||
369 | - context, | ||
370 | - iosAnimation, | ||
371 | - secondaryAnimation, | ||
372 | - popGesture ?? Get.defaultPopGesture | ||
373 | - ? _CupertinoBackGestureDetector<T>( | ||
374 | - enabledCallback: () => _isPopGestureEnabled<T>(this), | ||
375 | - onStartPopGesture: () => _startPopGesture<T>(this), | ||
376 | - child: child) | ||
377 | - : child); | ||
378 | - } | ||
379 | - } | ||
380 | - | ||
381 | - @override | ||
382 | void dispose() { | 70 | void dispose() { |
383 | super.dispose(); | 71 | super.dispose(); |
384 | if (Get.smartManagement != SmartManagement.onlyBuilder) { | 72 | if (Get.smartManagement != SmartManagement.onlyBuilder) { |
@@ -396,220 +84,30 @@ class GetPageRoute<T> extends PageRoute<T> { | @@ -396,220 +84,30 @@ class GetPageRoute<T> extends PageRoute<T> { | ||
396 | final middlewareRunner = MiddlewareRunner(middlewares); | 84 | final middlewareRunner = MiddlewareRunner(middlewares); |
397 | middlewareRunner.runOnPageDispose(); | 85 | middlewareRunner.runOnPageDispose(); |
398 | } | 86 | } |
399 | -} | ||
400 | - | ||
401 | -const double _kBackGestureWidth = 20.0; | ||
402 | -const double _kMinFlingVelocity = 1.0; | ||
403 | -const int _kMaxDroppedSwipePageForwardAnimationTime = 800; // Milliseconds. | ||
404 | - | ||
405 | -// The maximum time for a page to get reset to it's original position if the | ||
406 | -// user releases a page mid swipe. | ||
407 | -const int _kMaxPageBackAnimationTime = 300; | ||
408 | - | ||
409 | -class _CupertinoBackGestureDetector<T> extends StatefulWidget { | ||
410 | - const _CupertinoBackGestureDetector({ | ||
411 | - Key? key, | ||
412 | - required this.enabledCallback, | ||
413 | - required this.onStartPopGesture, | ||
414 | - required this.child, | ||
415 | - }) : super(key: key); | ||
416 | - | ||
417 | - final Widget child; | ||
418 | - | ||
419 | - final ValueGetter<bool> enabledCallback; | ||
420 | - | ||
421 | - final ValueGetter<_CupertinoBackGestureController<T>> onStartPopGesture; | ||
422 | - | ||
423 | - @override | ||
424 | - _CupertinoBackGestureDetectorState<T> createState() => | ||
425 | - _CupertinoBackGestureDetectorState<T>(); | ||
426 | -} | ||
427 | - | ||
428 | -class _CupertinoBackGestureDetectorState<T> | ||
429 | - extends State<_CupertinoBackGestureDetector<T>> { | ||
430 | - _CupertinoBackGestureController<T>? _backGestureController; | ||
431 | - | ||
432 | - late HorizontalDragGestureRecognizer _recognizer; | ||
433 | - | ||
434 | - @override | ||
435 | - void initState() { | ||
436 | - super.initState(); | ||
437 | - _recognizer = HorizontalDragGestureRecognizer(debugOwner: this) | ||
438 | - ..onStart = _handleDragStart | ||
439 | - ..onUpdate = _handleDragUpdate | ||
440 | - ..onEnd = _handleDragEnd | ||
441 | - ..onCancel = _handleDragCancel; | ||
442 | - } | ||
443 | 87 | ||
444 | @override | 88 | @override |
445 | - void dispose() { | ||
446 | - _recognizer.dispose(); | ||
447 | - super.dispose(); | ||
448 | - } | ||
449 | - | ||
450 | - void _handleDragStart(DragStartDetails details) { | ||
451 | - assert(mounted); | ||
452 | - assert(_backGestureController == null); | ||
453 | - _backGestureController = widget.onStartPopGesture(); | ||
454 | - } | ||
455 | - | ||
456 | - void _handleDragUpdate(DragUpdateDetails details) { | ||
457 | - assert(mounted); | ||
458 | - assert(_backGestureController != null); | ||
459 | - _backGestureController!.dragUpdate( | ||
460 | - _convertToLogical(details.primaryDelta! / context.size!.width)!); | ||
461 | - } | ||
462 | - | ||
463 | - void _handleDragEnd(DragEndDetails details) { | ||
464 | - assert(mounted); | ||
465 | - assert(_backGestureController != null); | ||
466 | - _backGestureController!.dragEnd(_convertToLogical( | ||
467 | - details.velocity.pixelsPerSecond.dx / context.size!.width)!); | ||
468 | - _backGestureController = null; | ||
469 | - } | 89 | + Widget buildContent(BuildContext context) { |
90 | + Get.reference = reference; | ||
91 | + final middlewareRunner = MiddlewareRunner(middlewares); | ||
92 | + final bindingsToBind = middlewareRunner.runOnBindingsStart(bindings); | ||
470 | 93 | ||
471 | - void _handleDragCancel() { | ||
472 | - assert(mounted); | ||
473 | - // This can be called even if start is not called, paired with | ||
474 | - // the "down" event that we don't consider here. | ||
475 | - _backGestureController?.dragEnd(0.0); | ||
476 | - _backGestureController = null; | 94 | + binding?.dependencies(); |
95 | + if (bindingsToBind != null) { | ||
96 | + for (final binding in bindingsToBind) { | ||
97 | + binding.dependencies(); | ||
477 | } | 98 | } |
478 | - | ||
479 | - void _handlePointerDown(PointerDownEvent event) { | ||
480 | - if (widget.enabledCallback()) _recognizer.addPointer(event); | ||
481 | } | 99 | } |
482 | 100 | ||
483 | - double? _convertToLogical(double value) { | ||
484 | - switch (Directionality.of(context)) { | ||
485 | - case TextDirection.rtl: | ||
486 | - return -value; | ||
487 | - case TextDirection.ltr: | ||
488 | - return value; | ||
489 | - default: | ||
490 | - return value; | ||
491 | - } | 101 | + final pageToBuild = middlewareRunner.runOnPageBuildStart(page)!; |
102 | + return middlewareRunner.runOnPageBuilt(pageToBuild()); | ||
492 | } | 103 | } |
493 | 104 | ||
494 | @override | 105 | @override |
495 | - Widget build(BuildContext context) { | ||
496 | - assert(debugCheckHasDirectionality(context)); | ||
497 | - // For devices with notches, the drag area needs to be larger on the side | ||
498 | - // that has the notch. | ||
499 | - var dragAreaWidth = Directionality.of(context) == TextDirection.ltr | ||
500 | - ? MediaQuery.of(context).padding.left | ||
501 | - : MediaQuery.of(context).padding.right; | ||
502 | - dragAreaWidth = max(dragAreaWidth, _kBackGestureWidth); | ||
503 | - return Stack( | ||
504 | - fit: StackFit.passthrough, | ||
505 | - children: <Widget>[ | ||
506 | - widget.child, | ||
507 | - PositionedDirectional( | ||
508 | - start: 0.0, | ||
509 | - width: dragAreaWidth, | ||
510 | - top: 0.0, | ||
511 | - bottom: 0.0, | ||
512 | - child: Listener( | ||
513 | - onPointerDown: _handlePointerDown, | ||
514 | - behavior: HitTestBehavior.translucent, | ||
515 | - ), | ||
516 | - ), | ||
517 | - ], | ||
518 | - ); | ||
519 | - } | ||
520 | -} | ||
521 | - | ||
522 | -class _CupertinoBackGestureController<T> { | ||
523 | - /// Creates a controller for an iOS-style back gesture. | ||
524 | - /// | ||
525 | - /// The [navigator] and [controller] arguments must not be null. | ||
526 | - _CupertinoBackGestureController({ | ||
527 | - required this.navigator, | ||
528 | - required this.controller, | ||
529 | - }) { | ||
530 | - navigator.didStartUserGesture(); | ||
531 | - } | ||
532 | - | ||
533 | - final AnimationController controller; | ||
534 | - final NavigatorState navigator; | ||
535 | - | ||
536 | - /// The drag gesture has changed by [fractionalDelta]. The total range of the | ||
537 | - /// drag should be 0.0 to 1.0. | ||
538 | - void dragUpdate(double delta) { | ||
539 | - controller.value -= delta; | ||
540 | - } | ||
541 | - | ||
542 | - /// The drag gesture has ended with a horizontal motion of | ||
543 | - /// [fractionalVelocity] as a fraction of screen width per second. | ||
544 | - void dragEnd(double velocity) { | ||
545 | - // Fling in the appropriate direction. | ||
546 | - // AnimationController.fling is guaranteed to | ||
547 | - // take at least one frame. | ||
548 | - // | ||
549 | - // This curve has been determined through rigorously eyeballing native iOS | ||
550 | - // animations. | ||
551 | - const Curve animationCurve = Curves.fastLinearToSlowEaseIn; | ||
552 | - bool animateForward; | ||
553 | - | ||
554 | - // If the user releases the page before mid screen with sufficient velocity, | ||
555 | - // or after mid screen, we should animate the page out. Otherwise, the page | ||
556 | - // should be animated back in. | ||
557 | - if (velocity.abs() >= _kMinFlingVelocity) { | ||
558 | - animateForward = velocity <= 0; | ||
559 | - } else { | ||
560 | - animateForward = controller.value > 0.5; | ||
561 | - } | 106 | + final String? title; |
562 | 107 | ||
563 | - if (animateForward) { | ||
564 | - // The closer the panel is to dismissing, the shorter the animation is. | ||
565 | - // We want to cap the animation time, but we want to use a linear curve | ||
566 | - // to determine it. | ||
567 | - final droppedPageForwardAnimationTime = min( | ||
568 | - lerpDouble( | ||
569 | - _kMaxDroppedSwipePageForwardAnimationTime, | ||
570 | - 0, | ||
571 | - controller.value, | ||
572 | - )! | ||
573 | - .floor(), | ||
574 | - _kMaxPageBackAnimationTime, | ||
575 | - ); | ||
576 | - controller.animateTo(1.0, | ||
577 | - duration: Duration(milliseconds: droppedPageForwardAnimationTime), | ||
578 | - curve: animationCurve); | ||
579 | - } else { | ||
580 | - // This route is destined to pop at this point. Reuse navigator's pop. | ||
581 | - navigator.pop(); | ||
582 | - | ||
583 | - // The popping may have finished inline if already at the target | ||
584 | - // destination. | ||
585 | - if (controller.isAnimating) { | ||
586 | - // Otherwise, use a custom popping animation duration and curve. | ||
587 | - final droppedPageBackAnimationTime = lerpDouble( | ||
588 | - 0, | ||
589 | - _kMaxDroppedSwipePageForwardAnimationTime, | ||
590 | - controller.value, | ||
591 | - )! | ||
592 | - .floor(); | ||
593 | - controller.animateBack( | ||
594 | - 0.0, | ||
595 | - duration: Duration(milliseconds: droppedPageBackAnimationTime), | ||
596 | - curve: animationCurve, | ||
597 | - ); | ||
598 | - } | ||
599 | - } | 108 | + @override |
109 | + String get debugLabel => '${super.debugLabel}(${settings.name})'; | ||
600 | 110 | ||
601 | - if (controller.isAnimating) { | ||
602 | - // Keep the userGestureInProgress in true state so we don't change the | ||
603 | - // curve of the page transition mid-flight since CupertinoPageTransition | ||
604 | - // depends on userGestureInProgress. | ||
605 | - late AnimationStatusListener animationStatusCallback; | ||
606 | - animationStatusCallback = (status) { | ||
607 | - navigator.didStopUserGesture(); | ||
608 | - controller.removeStatusListener(animationStatusCallback); | ||
609 | - }; | ||
610 | - controller.addStatusListener(animationStatusCallback); | ||
611 | - } else { | ||
612 | - navigator.didStopUserGesture(); | ||
613 | - } | ||
614 | - } | 111 | + @override |
112 | + final double gestureWidth; | ||
615 | } | 113 | } |
1 | +// import 'package:flutter/material.dart'; | ||
2 | + | ||
3 | +// import '../../../get.dart'; | ||
4 | +// import 'custom_transition.dart'; | ||
5 | +// import 'get_transition_mixin.dart'; | ||
6 | +// import 'route_middleware.dart'; | ||
7 | +// import 'transitions_type.dart'; | ||
8 | + | ||
9 | +// class GetPageRoute<T> extends PageRoute<T> | ||
10 | +// with GetPageRouteTransitionMixin<T> { | ||
11 | +// /// Creates a page route for use in an iOS designed app. | ||
12 | +// /// | ||
13 | +// /// The [builder], [maintainState], and [fullscreenDialog] arguments must not | ||
14 | +// /// be null. | ||
15 | +// GetPageRoute({ | ||
16 | +// RouteSettings? settings, | ||
17 | +// this.transitionDuration = const Duration(milliseconds: 300), | ||
18 | +// this.opaque = true, | ||
19 | +// this.parameter, | ||
20 | +// this.curve, | ||
21 | +// this.alignment, | ||
22 | +// this.transition, | ||
23 | +// this.popGesture, | ||
24 | +// this.customTransition, | ||
25 | +// this.barrierDismissible = false, | ||
26 | +// this.barrierColor, | ||
27 | +// this.binding, | ||
28 | +// this.bindings, | ||
29 | +// this.routeName, | ||
30 | +// this.page, | ||
31 | +// this.title, | ||
32 | +// this.barrierLabel, | ||
33 | +// this.maintainState = true, | ||
34 | +// bool fullscreenDialog = false, | ||
35 | +// this.middlewares, | ||
36 | +// }) : reference = "$routeName: ${settings?.hashCode ?? page.hashCode}", | ||
37 | +// super(settings: settings, fullscreenDialog: fullscreenDialog); | ||
38 | + | ||
39 | +// @override | ||
40 | +// final Duration transitionDuration; | ||
41 | +// final GetPageBuilder? page; | ||
42 | +// final String? routeName; | ||
43 | +// final String reference; | ||
44 | +// final CustomTransition? customTransition; | ||
45 | +// final Bindings? binding; | ||
46 | +// final Map<String, String>? parameter; | ||
47 | +// final List<Bindings>? bindings; | ||
48 | + | ||
49 | +// @override | ||
50 | +// final bool opaque; | ||
51 | +// final bool? popGesture; | ||
52 | + | ||
53 | +// @override | ||
54 | +// final bool barrierDismissible; | ||
55 | +// final Transition? transition; | ||
56 | +// final Curve? curve; | ||
57 | +// final Alignment? alignment; | ||
58 | +// final List<GetMiddleware>? middlewares; | ||
59 | + | ||
60 | +// @override | ||
61 | +// final Color? barrierColor; | ||
62 | + | ||
63 | +// @override | ||
64 | +// final String? barrierLabel; | ||
65 | + | ||
66 | +// @override | ||
67 | +// final bool maintainState; | ||
68 | + | ||
69 | +// @override | ||
70 | +// void dispose() { | ||
71 | +// super.dispose(); | ||
72 | +// if (Get.smartManagement != SmartManagement.onlyBuilder) { | ||
73 | +// WidgetsBinding.instance!.addPostFrameCallback((_) { | ||
74 | +// if (Get.reference != reference) { | ||
75 | +// GetInstance().removeDependencyByRoute("$reference"); | ||
76 | +// } | ||
77 | +// }); | ||
78 | +// } | ||
79 | + | ||
80 | +// // if (Get.smartManagement != SmartManagement.onlyBuilder) { | ||
81 | +// // GetInstance().removeDependencyByRoute("$reference"); | ||
82 | +// // } | ||
83 | + | ||
84 | +// final middlewareRunner = MiddlewareRunner(middlewares); | ||
85 | +// middlewareRunner.runOnPageDispose(); | ||
86 | +// } | ||
87 | + | ||
88 | +// @override | ||
89 | +// Widget buildContent(BuildContext context) { | ||
90 | +// Get.reference = reference; | ||
91 | +// final middlewareRunner = MiddlewareRunner(middlewares); | ||
92 | +// final bindingsToBind = middlewareRunner.runOnBindingsStart(bindings); | ||
93 | + | ||
94 | +// binding?.dependencies(); | ||
95 | +// if (bindingsToBind != null) { | ||
96 | +// for (final binding in bindingsToBind) { | ||
97 | +// binding.dependencies(); | ||
98 | +// } | ||
99 | +// } | ||
100 | + | ||
101 | +// final pageToBuild = middlewareRunner.runOnPageBuildStart(page)!; | ||
102 | +// return middlewareRunner.runOnPageBuilt(pageToBuild()); | ||
103 | +// } | ||
104 | + | ||
105 | +// @override | ||
106 | +// final String? title; | ||
107 | + | ||
108 | +// @override | ||
109 | +// String get debugLabel => '${super.debugLabel}(${settings.name})'; | ||
110 | +// } |
1 | +import 'package:flutter/cupertino.dart'; | ||
1 | import 'package:flutter/foundation.dart'; | 2 | import 'package:flutter/foundation.dart'; |
2 | import 'package:flutter/material.dart'; | 3 | import 'package:flutter/material.dart'; |
3 | import 'package:flutter/widgets.dart'; | 4 | import 'package:flutter/widgets.dart'; |
@@ -36,6 +37,7 @@ class GetPage<T> extends Page<T> { | @@ -36,6 +37,7 @@ class GetPage<T> extends Page<T> { | ||
36 | final Alignment? alignment; | 37 | final Alignment? alignment; |
37 | final bool maintainState; | 38 | final bool maintainState; |
38 | final bool opaque; | 39 | final bool opaque; |
40 | + final double gestureWidth; | ||
39 | final Bindings? binding; | 41 | final Bindings? binding; |
40 | final List<Bindings> bindings; | 42 | final List<Bindings> bindings; |
41 | final CustomTransition? customTransition; | 43 | final CustomTransition? customTransition; |
@@ -63,6 +65,7 @@ class GetPage<T> extends Page<T> { | @@ -63,6 +65,7 @@ class GetPage<T> extends Page<T> { | ||
63 | required this.name, | 65 | required this.name, |
64 | required this.page, | 66 | required this.page, |
65 | this.title, | 67 | this.title, |
68 | + this.gestureWidth = 20, | ||
66 | // RouteSettings settings, | 69 | // RouteSettings settings, |
67 | this.maintainState = true, | 70 | this.maintainState = true, |
68 | this.curve = Curves.linear, | 71 | this.curve = Curves.linear, |
@@ -109,7 +112,7 @@ class GetPage<T> extends Page<T> { | @@ -109,7 +112,7 @@ class GetPage<T> extends Page<T> { | ||
109 | return PathDecoded(RegExp('^$stringPath\$'), keys); | 112 | return PathDecoded(RegExp('^$stringPath\$'), keys); |
110 | } | 113 | } |
111 | 114 | ||
112 | - GetPage copy({ | 115 | + GetPage<T> copy({ |
113 | String? name, | 116 | String? name, |
114 | GetPageBuilder? page, | 117 | GetPageBuilder? page, |
115 | bool? popGesture, | 118 | bool? popGesture, |
@@ -130,6 +133,7 @@ class GetPage<T> extends Page<T> { | @@ -130,6 +133,7 @@ class GetPage<T> extends Page<T> { | ||
130 | GetPage? unknownRoute, | 133 | GetPage? unknownRoute, |
131 | List<GetMiddleware>? middlewares, | 134 | List<GetMiddleware>? middlewares, |
132 | bool? preventDuplicates, | 135 | bool? preventDuplicates, |
136 | + double? gestureWidth, | ||
133 | }) { | 137 | }) { |
134 | return GetPage( | 138 | return GetPage( |
135 | preventDuplicates: preventDuplicates ?? this.preventDuplicates, | 139 | preventDuplicates: preventDuplicates ?? this.preventDuplicates, |
@@ -151,14 +155,17 @@ class GetPage<T> extends Page<T> { | @@ -151,14 +155,17 @@ class GetPage<T> extends Page<T> { | ||
151 | children: children ?? this.children, | 155 | children: children ?? this.children, |
152 | unknownRoute: unknownRoute ?? this.unknownRoute, | 156 | unknownRoute: unknownRoute ?? this.unknownRoute, |
153 | middlewares: middlewares ?? this.middlewares, | 157 | middlewares: middlewares ?? this.middlewares, |
158 | + gestureWidth: gestureWidth ?? this.gestureWidth, | ||
154 | ); | 159 | ); |
155 | } | 160 | } |
156 | 161 | ||
157 | @override | 162 | @override |
158 | Route<T> createRoute(BuildContext context) { | 163 | Route<T> createRoute(BuildContext context) { |
164 | + // return GetPageRoute<T>(settings: this, page: page); | ||
159 | return PageRedirect( | 165 | return PageRedirect( |
160 | - this, | ||
161 | - unknownRoute, | ||
162 | - ).page<T>(); | 166 | + route: this, |
167 | + settings: this, | ||
168 | + unknownRoute: unknownRoute, | ||
169 | + ).getPageToRoute<T>(this, unknownRoute); | ||
163 | } | 170 | } |
164 | } | 171 | } |
1 | +import 'dart:math'; | ||
2 | +import 'dart:ui'; | ||
3 | + | ||
4 | +import 'package:flutter/cupertino.dart'; | ||
5 | +import 'package:flutter/foundation.dart'; | ||
6 | +import 'package:flutter/gestures.dart'; | ||
7 | +import 'package:flutter/material.dart'; | ||
8 | +import '../../../get.dart'; | ||
9 | + | ||
10 | +import 'default_transitions.dart'; | ||
11 | +import 'transitions_type.dart'; | ||
12 | + | ||
13 | +//const double _kBackGestureWidth = 20.0; | ||
14 | +const double _kMinFlingVelocity = 1.0; // Screen widths per second. | ||
15 | + | ||
16 | +// An eyeballed value for the maximum time it takes | ||
17 | +//for a page to animate forward | ||
18 | +// if the user releases a page mid swipe. | ||
19 | +const int _kMaxDroppedSwipePageForwardAnimationTime = 800; // Milliseconds. | ||
20 | + | ||
21 | +// The maximum time for a page to get reset to it's original position if the | ||
22 | +// user releases a page mid swipe. | ||
23 | +const int _kMaxPageBackAnimationTime = 300; // Milliseconds. | ||
24 | + | ||
25 | +mixin GetPageRouteTransitionMixin<T> on PageRoute<T> { | ||
26 | + /// Builds the primary contents of the route. | ||
27 | + @protected | ||
28 | + Widget buildContent(BuildContext context); | ||
29 | + | ||
30 | + /// {@template flutter.cupertino.CupertinoRouteTransitionMixin.title} | ||
31 | + /// A title string for this route. | ||
32 | + /// | ||
33 | + /// Used to auto-populate [CupertinoNavigationBar] and | ||
34 | + /// [CupertinoSliverNavigationBar]'s `middle`/`largeTitle` widgets when | ||
35 | + /// one is not manually supplied. | ||
36 | + /// {@endtemplate} | ||
37 | + String? get title; | ||
38 | + | ||
39 | + double get gestureWidth; | ||
40 | + | ||
41 | + ValueNotifier<String?>? _previousTitle; | ||
42 | + | ||
43 | + /// The title string of the previous [CupertinoPageRoute]. | ||
44 | + /// | ||
45 | + /// The [ValueListenable]'s value is readable after the route is installed | ||
46 | + /// onto a [Navigator]. The [ValueListenable] will also notify its listeners | ||
47 | + /// if the value changes (such as by replacing the previous route). | ||
48 | + /// | ||
49 | + /// The [ValueListenable] itself will be null before the route is installed. | ||
50 | + /// Its content value will be null if the previous route has no title or | ||
51 | + /// is not a [CupertinoPageRoute]. | ||
52 | + /// | ||
53 | + /// See also: | ||
54 | + /// | ||
55 | + /// * [ValueListenableBuilder], which can be used to listen and rebuild | ||
56 | + /// widgets based on a ValueListenable. | ||
57 | + ValueListenable<String?> get previousTitle { | ||
58 | + assert( | ||
59 | + _previousTitle != null, | ||
60 | + ''' | ||
61 | +Cannot read the previousTitle for a route that has not yet been installed''', | ||
62 | + ); | ||
63 | + return _previousTitle!; | ||
64 | + } | ||
65 | + | ||
66 | + @override | ||
67 | + void didChangePrevious(Route<dynamic>? previousRoute) { | ||
68 | + final previousTitleString = previousRoute is CupertinoRouteTransitionMixin | ||
69 | + ? previousRoute.title | ||
70 | + : null; | ||
71 | + if (_previousTitle == null) { | ||
72 | + _previousTitle = ValueNotifier<String?>(previousTitleString); | ||
73 | + } else { | ||
74 | + _previousTitle!.value = previousTitleString; | ||
75 | + } | ||
76 | + super.didChangePrevious(previousRoute); | ||
77 | + } | ||
78 | + | ||
79 | + @override | ||
80 | + // A relatively rigorous eyeball estimation. | ||
81 | + Duration get transitionDuration => const Duration(milliseconds: 400); | ||
82 | + | ||
83 | + @override | ||
84 | + Color? get barrierColor => null; | ||
85 | + | ||
86 | + @override | ||
87 | + String? get barrierLabel => null; | ||
88 | + | ||
89 | + @override | ||
90 | + bool canTransitionTo(TransitionRoute<dynamic> nextRoute) { | ||
91 | + // Don't perform outgoing animation if the next route is a | ||
92 | + // fullscreen dialog. | ||
93 | + return nextRoute is CupertinoRouteTransitionMixin && | ||
94 | + !nextRoute.fullscreenDialog; | ||
95 | + } | ||
96 | + | ||
97 | + /// True if an iOS-style back swipe pop gesture is currently | ||
98 | + /// underway for [route]. | ||
99 | + /// | ||
100 | + /// This just check the route's [NavigatorState.userGestureInProgress]. | ||
101 | + /// | ||
102 | + /// See also: | ||
103 | + /// | ||
104 | + /// * [popGestureEnabled], which returns true if a user-triggered pop gesture | ||
105 | + /// would be allowed. | ||
106 | + static bool isPopGestureInProgress(PageRoute<dynamic> route) { | ||
107 | + return route.navigator!.userGestureInProgress; | ||
108 | + } | ||
109 | + | ||
110 | + /// True if an iOS-style back swipe pop gesture is currently | ||
111 | + /// underway for this route. | ||
112 | + /// | ||
113 | + /// See also: | ||
114 | + /// | ||
115 | + /// * [isPopGestureInProgress], which returns true if a Cupertino pop gesture | ||
116 | + /// is currently underway for specific route. | ||
117 | + /// * [popGestureEnabled], which returns true if a user-triggered pop gesture | ||
118 | + /// would be allowed. | ||
119 | + bool get popGestureInProgress => isPopGestureInProgress(this); | ||
120 | + | ||
121 | + /// Whether a pop gesture can be started by the user. | ||
122 | + /// | ||
123 | + /// Returns true if the user can edge-swipe to a previous route. | ||
124 | + /// | ||
125 | + /// Returns false once [isPopGestureInProgress] is true, but | ||
126 | + /// [isPopGestureInProgress] can only become true if [popGestureEnabled] was | ||
127 | + /// true first. | ||
128 | + /// | ||
129 | + /// This should only be used between frames, not during build. | ||
130 | + bool get popGestureEnabled => _isPopGestureEnabled(this); | ||
131 | + | ||
132 | + static bool _isPopGestureEnabled<T>(PageRoute<T> route) { | ||
133 | + // If there's nothing to go back to, then obviously we don't support | ||
134 | + // the back gesture. | ||
135 | + if (route.isFirst) return false; | ||
136 | + // If the route wouldn't actually pop if we popped it, then the gesture | ||
137 | + // would be really confusing (or would skip internal routes), | ||
138 | + //so disallow it. | ||
139 | + if (route.willHandlePopInternally) return false; | ||
140 | + // If attempts to dismiss this route might be vetoed such as in a page | ||
141 | + // with forms, then do not allow the user to dismiss the route with a swipe. | ||
142 | + if (route.hasScopedWillPopCallback) return false; | ||
143 | + // Fullscreen dialogs aren't dismissible by back swipe. | ||
144 | + if (route.fullscreenDialog) return false; | ||
145 | + // If we're in an animation already, we cannot be manually swiped. | ||
146 | + if (route.animation!.status != AnimationStatus.completed) return false; | ||
147 | + // If we're being popped into, we also cannot be swiped until the pop above | ||
148 | + // it completes. This translates to our secondary animation being | ||
149 | + // dismissed. | ||
150 | + if (route.secondaryAnimation!.status != AnimationStatus.dismissed) { | ||
151 | + return false; | ||
152 | + } | ||
153 | + // If we're in a gesture already, we cannot start another. | ||
154 | + if (isPopGestureInProgress(route)) return false; | ||
155 | + | ||
156 | + // Looks like a back gesture would be welcome! | ||
157 | + return true; | ||
158 | + } | ||
159 | + | ||
160 | + @override | ||
161 | + Widget buildPage(BuildContext context, Animation<double> animation, | ||
162 | + Animation<double> secondaryAnimation) { | ||
163 | + final child = buildContent(context); | ||
164 | + final Widget result = Semantics( | ||
165 | + scopesRoute: true, | ||
166 | + explicitChildNodes: true, | ||
167 | + child: child, | ||
168 | + ); | ||
169 | + return result; | ||
170 | + } | ||
171 | + | ||
172 | + // Called by CupertinoBackGestureDetector when a pop ("back") drag start | ||
173 | + // gesture is detected. The returned controller handles all of the subsequent | ||
174 | + // drag events. | ||
175 | + static CupertinoBackGestureController<T> _startPopGesture<T>( | ||
176 | + PageRoute<T> route) { | ||
177 | + assert(_isPopGestureEnabled(route)); | ||
178 | + | ||
179 | + return CupertinoBackGestureController<T>( | ||
180 | + navigator: route.navigator!, | ||
181 | + controller: route.controller!, // protected access | ||
182 | + ); | ||
183 | + } | ||
184 | + | ||
185 | + /// Returns a [CupertinoFullscreenDialogTransition] if [route] is a full | ||
186 | + /// screen dialog, otherwise a [CupertinoPageTransition] is returned. | ||
187 | + /// | ||
188 | + /// Used by [CupertinoPageRoute.buildTransitions]. | ||
189 | + /// | ||
190 | + /// This method can be applied to any [PageRoute], not just | ||
191 | + /// [CupertinoPageRoute]. It's typically used to provide a Cupertino style | ||
192 | + /// horizontal transition for material widgets when the target platform | ||
193 | + /// is [TargetPlatform.iOS]. | ||
194 | + /// | ||
195 | + /// See also: | ||
196 | + /// | ||
197 | + /// * [CupertinoPageTransitionsBuilder], which uses this method to define a | ||
198 | + /// [PageTransitionsBuilder] for the [PageTransitionsTheme]. | ||
199 | + static Widget buildPageTransitions<T>( | ||
200 | + PageRoute<T> rawRoute, | ||
201 | + BuildContext context, | ||
202 | + Animation<double> animation, | ||
203 | + Animation<double> secondaryAnimation, | ||
204 | + Widget child, | ||
205 | + ) { | ||
206 | + // Check if the route has an animation that's currently participating | ||
207 | + // in a back swipe gesture. | ||
208 | + // | ||
209 | + // In the middle of a back gesture drag, let the transition be linear to | ||
210 | + // match finger motions. | ||
211 | + final route = rawRoute as GetPageRoute<T>; | ||
212 | + final linearTransition = isPopGestureInProgress(route); | ||
213 | + final finalCurve = route.curve ?? Get.defaultTransitionCurve; | ||
214 | + final hasCurve = route.curve != null; | ||
215 | + if (route.fullscreenDialog && route.transition == null) { | ||
216 | + return CupertinoFullscreenDialogTransition( | ||
217 | + primaryRouteAnimation: hasCurve | ||
218 | + ? CurvedAnimation(parent: animation, curve: finalCurve) | ||
219 | + : animation, | ||
220 | + secondaryRouteAnimation: secondaryAnimation, | ||
221 | + child: child, | ||
222 | + linearTransition: linearTransition, | ||
223 | + ); | ||
224 | + } else { | ||
225 | + if (route.customTransition != null) { | ||
226 | + return route.customTransition!.buildTransition( | ||
227 | + context, | ||
228 | + finalCurve, | ||
229 | + route.alignment, | ||
230 | + animation, | ||
231 | + secondaryAnimation, | ||
232 | + route.popGesture ?? Get.defaultPopGesture | ||
233 | + ? CupertinoBackGestureDetector<T>( | ||
234 | + gestureWidth: route.gestureWidth, | ||
235 | + enabledCallback: () => _isPopGestureEnabled<T>(route), | ||
236 | + onStartPopGesture: () => _startPopGesture<T>(route), | ||
237 | + child: child) | ||
238 | + : child, | ||
239 | + ); | ||
240 | + } | ||
241 | + | ||
242 | + /// Apply the curve by default... | ||
243 | + final iosAnimation = animation; | ||
244 | + animation = CurvedAnimation(parent: animation, curve: finalCurve); | ||
245 | + | ||
246 | + switch (route.transition ?? Get.defaultTransition) { | ||
247 | + case Transition.leftToRight: | ||
248 | + return SlideLeftTransition().buildTransitions( | ||
249 | + context, | ||
250 | + route.curve, | ||
251 | + route.alignment, | ||
252 | + animation, | ||
253 | + secondaryAnimation, | ||
254 | + route.popGesture ?? Get.defaultPopGesture | ||
255 | + ? CupertinoBackGestureDetector<T>( | ||
256 | + gestureWidth: route.gestureWidth, | ||
257 | + enabledCallback: () => _isPopGestureEnabled<T>(route), | ||
258 | + onStartPopGesture: () => _startPopGesture<T>(route), | ||
259 | + child: child) | ||
260 | + : child); | ||
261 | + | ||
262 | + case Transition.downToUp: | ||
263 | + return SlideDownTransition().buildTransitions( | ||
264 | + context, | ||
265 | + route.curve, | ||
266 | + route.alignment, | ||
267 | + animation, | ||
268 | + secondaryAnimation, | ||
269 | + route.popGesture ?? Get.defaultPopGesture | ||
270 | + ? CupertinoBackGestureDetector<T>( | ||
271 | + gestureWidth: route.gestureWidth, | ||
272 | + enabledCallback: () => _isPopGestureEnabled<T>(route), | ||
273 | + onStartPopGesture: () => _startPopGesture<T>(route), | ||
274 | + child: child) | ||
275 | + : child); | ||
276 | + | ||
277 | + case Transition.upToDown: | ||
278 | + return SlideTopTransition().buildTransitions( | ||
279 | + context, | ||
280 | + route.curve, | ||
281 | + route.alignment, | ||
282 | + animation, | ||
283 | + secondaryAnimation, | ||
284 | + route.popGesture ?? Get.defaultPopGesture | ||
285 | + ? CupertinoBackGestureDetector<T>( | ||
286 | + gestureWidth: route.gestureWidth, | ||
287 | + enabledCallback: () => _isPopGestureEnabled<T>(route), | ||
288 | + onStartPopGesture: () => _startPopGesture<T>(route), | ||
289 | + child: child) | ||
290 | + : child); | ||
291 | + | ||
292 | + case Transition.noTransition: | ||
293 | + return route.popGesture ?? Get.defaultPopGesture | ||
294 | + ? CupertinoBackGestureDetector<T>( | ||
295 | + gestureWidth: route.gestureWidth, | ||
296 | + enabledCallback: () => _isPopGestureEnabled<T>(route), | ||
297 | + onStartPopGesture: () => _startPopGesture<T>(route), | ||
298 | + child: child) | ||
299 | + : child; | ||
300 | + | ||
301 | + case Transition.rightToLeft: | ||
302 | + return SlideRightTransition().buildTransitions( | ||
303 | + context, | ||
304 | + route.curve, | ||
305 | + route.alignment, | ||
306 | + animation, | ||
307 | + secondaryAnimation, | ||
308 | + route.popGesture ?? Get.defaultPopGesture | ||
309 | + ? CupertinoBackGestureDetector<T>( | ||
310 | + gestureWidth: route.gestureWidth, | ||
311 | + enabledCallback: () => _isPopGestureEnabled<T>(route), | ||
312 | + onStartPopGesture: () => _startPopGesture<T>(route), | ||
313 | + child: child) | ||
314 | + : child); | ||
315 | + | ||
316 | + case Transition.zoom: | ||
317 | + return ZoomInTransition().buildTransitions( | ||
318 | + context, | ||
319 | + route.curve, | ||
320 | + route.alignment, | ||
321 | + animation, | ||
322 | + secondaryAnimation, | ||
323 | + route.popGesture ?? Get.defaultPopGesture | ||
324 | + ? CupertinoBackGestureDetector<T>( | ||
325 | + gestureWidth: route.gestureWidth, | ||
326 | + enabledCallback: () => _isPopGestureEnabled<T>(route), | ||
327 | + onStartPopGesture: () => _startPopGesture<T>(route), | ||
328 | + child: child) | ||
329 | + : child); | ||
330 | + | ||
331 | + case Transition.fadeIn: | ||
332 | + return FadeInTransition().buildTransitions( | ||
333 | + context, | ||
334 | + route.curve, | ||
335 | + route.alignment, | ||
336 | + animation, | ||
337 | + secondaryAnimation, | ||
338 | + route.popGesture ?? Get.defaultPopGesture | ||
339 | + ? CupertinoBackGestureDetector<T>( | ||
340 | + gestureWidth: route.gestureWidth, | ||
341 | + enabledCallback: () => _isPopGestureEnabled<T>(route), | ||
342 | + onStartPopGesture: () => _startPopGesture<T>(route), | ||
343 | + child: child) | ||
344 | + : child); | ||
345 | + | ||
346 | + case Transition.rightToLeftWithFade: | ||
347 | + return RightToLeftFadeTransition().buildTransitions( | ||
348 | + context, | ||
349 | + route.curve, | ||
350 | + route.alignment, | ||
351 | + animation, | ||
352 | + secondaryAnimation, | ||
353 | + route.popGesture ?? Get.defaultPopGesture | ||
354 | + ? CupertinoBackGestureDetector<T>( | ||
355 | + gestureWidth: route.gestureWidth, | ||
356 | + enabledCallback: () => _isPopGestureEnabled<T>(route), | ||
357 | + onStartPopGesture: () => _startPopGesture<T>(route), | ||
358 | + child: child) | ||
359 | + : child); | ||
360 | + | ||
361 | + case Transition.leftToRightWithFade: | ||
362 | + return LeftToRightFadeTransition().buildTransitions( | ||
363 | + context, | ||
364 | + route.curve, | ||
365 | + route.alignment, | ||
366 | + animation, | ||
367 | + secondaryAnimation, | ||
368 | + route.popGesture ?? Get.defaultPopGesture | ||
369 | + ? CupertinoBackGestureDetector<T>( | ||
370 | + gestureWidth: route.gestureWidth, | ||
371 | + enabledCallback: () => _isPopGestureEnabled<T>(route), | ||
372 | + onStartPopGesture: () => _startPopGesture<T>(route), | ||
373 | + child: child) | ||
374 | + : child); | ||
375 | + | ||
376 | + case Transition.cupertino: | ||
377 | + return CupertinoPageTransition( | ||
378 | + primaryRouteAnimation: animation, | ||
379 | + secondaryRouteAnimation: secondaryAnimation, | ||
380 | + linearTransition: linearTransition, | ||
381 | + child: CupertinoBackGestureDetector<T>( | ||
382 | + gestureWidth: route.gestureWidth, | ||
383 | + enabledCallback: () => _isPopGestureEnabled<T>(route), | ||
384 | + onStartPopGesture: () => _startPopGesture<T>(route), | ||
385 | + child: child, | ||
386 | + ), | ||
387 | + ); | ||
388 | + | ||
389 | + case Transition.size: | ||
390 | + return SizeTransitions().buildTransitions( | ||
391 | + context, | ||
392 | + route.curve!, | ||
393 | + route.alignment, | ||
394 | + animation, | ||
395 | + secondaryAnimation, | ||
396 | + route.popGesture ?? Get.defaultPopGesture | ||
397 | + ? CupertinoBackGestureDetector<T>( | ||
398 | + gestureWidth: route.gestureWidth, | ||
399 | + enabledCallback: () => _isPopGestureEnabled<T>(route), | ||
400 | + onStartPopGesture: () => _startPopGesture<T>(route), | ||
401 | + child: child) | ||
402 | + : child); | ||
403 | + | ||
404 | + case Transition.fade: | ||
405 | + return FadeUpwardsPageTransitionsBuilder().buildTransitions( | ||
406 | + route, | ||
407 | + context, | ||
408 | + animation, | ||
409 | + secondaryAnimation, | ||
410 | + route.popGesture ?? Get.defaultPopGesture | ||
411 | + ? CupertinoBackGestureDetector<T>( | ||
412 | + gestureWidth: route.gestureWidth, | ||
413 | + enabledCallback: () => _isPopGestureEnabled<T>(route), | ||
414 | + onStartPopGesture: () => _startPopGesture<T>(route), | ||
415 | + child: child) | ||
416 | + : child); | ||
417 | + | ||
418 | + case Transition.topLevel: | ||
419 | + return ZoomPageTransitionsBuilder().buildTransitions( | ||
420 | + route, | ||
421 | + context, | ||
422 | + animation, | ||
423 | + secondaryAnimation, | ||
424 | + route.popGesture ?? Get.defaultPopGesture | ||
425 | + ? CupertinoBackGestureDetector<T>( | ||
426 | + gestureWidth: route.gestureWidth, | ||
427 | + enabledCallback: () => _isPopGestureEnabled<T>(route), | ||
428 | + onStartPopGesture: () => _startPopGesture<T>(route), | ||
429 | + child: child) | ||
430 | + : child); | ||
431 | + | ||
432 | + case Transition.native: | ||
433 | + return PageTransitionsTheme().buildTransitions( | ||
434 | + route, | ||
435 | + context, | ||
436 | + iosAnimation, | ||
437 | + secondaryAnimation, | ||
438 | + route.popGesture ?? Get.defaultPopGesture | ||
439 | + ? CupertinoBackGestureDetector<T>( | ||
440 | + gestureWidth: route.gestureWidth, | ||
441 | + enabledCallback: () => _isPopGestureEnabled<T>(route), | ||
442 | + onStartPopGesture: () => _startPopGesture<T>(route), | ||
443 | + child: child) | ||
444 | + : child); | ||
445 | + | ||
446 | + default: | ||
447 | + if (Get.customTransition != null) { | ||
448 | + return Get.customTransition!.buildTransition(context, route.curve, | ||
449 | + route.alignment, animation, secondaryAnimation, child); | ||
450 | + } | ||
451 | + | ||
452 | + return PageTransitionsTheme().buildTransitions( | ||
453 | + route, | ||
454 | + context, | ||
455 | + iosAnimation, | ||
456 | + secondaryAnimation, | ||
457 | + route.popGesture ?? Get.defaultPopGesture | ||
458 | + ? CupertinoBackGestureDetector<T>( | ||
459 | + gestureWidth: route.gestureWidth, | ||
460 | + enabledCallback: () => _isPopGestureEnabled<T>(route), | ||
461 | + onStartPopGesture: () => _startPopGesture<T>(route), | ||
462 | + child: child) | ||
463 | + : child); | ||
464 | + } | ||
465 | + } | ||
466 | + } | ||
467 | + | ||
468 | + @override | ||
469 | + Widget buildTransitions(BuildContext context, Animation<double> animation, | ||
470 | + Animation<double> secondaryAnimation, Widget child) { | ||
471 | + return buildPageTransitions<T>( | ||
472 | + this, context, animation, secondaryAnimation, child); | ||
473 | + } | ||
474 | +} | ||
475 | + | ||
476 | +class CupertinoBackGestureDetector<T> extends StatefulWidget { | ||
477 | + const CupertinoBackGestureDetector({ | ||
478 | + Key? key, | ||
479 | + required this.enabledCallback, | ||
480 | + required this.onStartPopGesture, | ||
481 | + required this.child, | ||
482 | + required this.gestureWidth, | ||
483 | + }) : super(key: key); | ||
484 | + | ||
485 | + final Widget child; | ||
486 | + final double gestureWidth; | ||
487 | + | ||
488 | + final ValueGetter<bool> enabledCallback; | ||
489 | + | ||
490 | + final ValueGetter<CupertinoBackGestureController<T>> onStartPopGesture; | ||
491 | + | ||
492 | + @override | ||
493 | + CupertinoBackGestureDetectorState<T> createState() => | ||
494 | + CupertinoBackGestureDetectorState<T>(); | ||
495 | +} | ||
496 | + | ||
497 | +class CupertinoBackGestureDetectorState<T> | ||
498 | + extends State<CupertinoBackGestureDetector<T>> { | ||
499 | + CupertinoBackGestureController<T>? _backGestureController; | ||
500 | + | ||
501 | + late HorizontalDragGestureRecognizer _recognizer; | ||
502 | + | ||
503 | + @override | ||
504 | + void initState() { | ||
505 | + super.initState(); | ||
506 | + _recognizer = HorizontalDragGestureRecognizer(debugOwner: this) | ||
507 | + ..onStart = _handleDragStart | ||
508 | + ..onUpdate = _handleDragUpdate | ||
509 | + ..onEnd = _handleDragEnd | ||
510 | + ..onCancel = _handleDragCancel; | ||
511 | + } | ||
512 | + | ||
513 | + @override | ||
514 | + void dispose() { | ||
515 | + _recognizer.dispose(); | ||
516 | + super.dispose(); | ||
517 | + } | ||
518 | + | ||
519 | + void _handleDragStart(DragStartDetails details) { | ||
520 | + assert(mounted); | ||
521 | + assert(_backGestureController == null); | ||
522 | + _backGestureController = widget.onStartPopGesture(); | ||
523 | + } | ||
524 | + | ||
525 | + void _handleDragUpdate(DragUpdateDetails details) { | ||
526 | + assert(mounted); | ||
527 | + assert(_backGestureController != null); | ||
528 | + _backGestureController!.dragUpdate( | ||
529 | + _convertToLogical(details.primaryDelta! / context.size!.width)); | ||
530 | + } | ||
531 | + | ||
532 | + void _handleDragEnd(DragEndDetails details) { | ||
533 | + assert(mounted); | ||
534 | + assert(_backGestureController != null); | ||
535 | + _backGestureController!.dragEnd(_convertToLogical( | ||
536 | + details.velocity.pixelsPerSecond.dx / context.size!.width)); | ||
537 | + _backGestureController = null; | ||
538 | + } | ||
539 | + | ||
540 | + void _handleDragCancel() { | ||
541 | + assert(mounted); | ||
542 | + // This can be called even if start is not called, paired with | ||
543 | + // the "down" event | ||
544 | + // that we don't consider here. | ||
545 | + _backGestureController?.dragEnd(0.0); | ||
546 | + _backGestureController = null; | ||
547 | + } | ||
548 | + | ||
549 | + void _handlePointerDown(PointerDownEvent event) { | ||
550 | + if (widget.enabledCallback()) _recognizer.addPointer(event); | ||
551 | + } | ||
552 | + | ||
553 | + double _convertToLogical(double value) { | ||
554 | + switch (Directionality.of(context)) { | ||
555 | + case TextDirection.rtl: | ||
556 | + return -value; | ||
557 | + case TextDirection.ltr: | ||
558 | + return value; | ||
559 | + } | ||
560 | + } | ||
561 | + | ||
562 | + @override | ||
563 | + Widget build(BuildContext context) { | ||
564 | + assert(debugCheckHasDirectionality(context)); | ||
565 | + // For devices with notches, the drag area needs to be larger on the side | ||
566 | + // that has the notch. | ||
567 | + var dragAreaWidth = Directionality.of(context) == TextDirection.ltr | ||
568 | + ? MediaQuery.of(context).padding.left | ||
569 | + : MediaQuery.of(context).padding.right; | ||
570 | + dragAreaWidth = max(dragAreaWidth, widget.gestureWidth); | ||
571 | + return Stack( | ||
572 | + fit: StackFit.passthrough, | ||
573 | + children: <Widget>[ | ||
574 | + widget.child, | ||
575 | + PositionedDirectional( | ||
576 | + start: 0.0, | ||
577 | + width: dragAreaWidth, | ||
578 | + top: 0.0, | ||
579 | + bottom: 0.0, | ||
580 | + child: Listener( | ||
581 | + onPointerDown: _handlePointerDown, | ||
582 | + behavior: HitTestBehavior.translucent, | ||
583 | + ), | ||
584 | + ), | ||
585 | + ], | ||
586 | + ); | ||
587 | + } | ||
588 | +} | ||
589 | + | ||
590 | +class CupertinoBackGestureController<T> { | ||
591 | + /// Creates a controller for an iOS-style back gesture. | ||
592 | + /// | ||
593 | + /// The [navigator] and [controller] arguments must not be null. | ||
594 | + CupertinoBackGestureController({ | ||
595 | + required this.navigator, | ||
596 | + required this.controller, | ||
597 | + }) { | ||
598 | + navigator.didStartUserGesture(); | ||
599 | + } | ||
600 | + | ||
601 | + final AnimationController controller; | ||
602 | + final NavigatorState navigator; | ||
603 | + | ||
604 | + /// The drag gesture has changed by [fractionalDelta]. The total range of the | ||
605 | + /// drag should be 0.0 to 1.0. | ||
606 | + void dragUpdate(double delta) { | ||
607 | + controller.value -= delta; | ||
608 | + } | ||
609 | + | ||
610 | + /// The drag gesture has ended with a horizontal motion of | ||
611 | + /// [fractionalVelocity] as a fraction of screen width per second. | ||
612 | + void dragEnd(double velocity) { | ||
613 | + // Fling in the appropriate direction. | ||
614 | + // AnimationController.fling is guaranteed to | ||
615 | + // take at least one frame. | ||
616 | + // | ||
617 | + // This curve has been determined through rigorously eyeballing native iOS | ||
618 | + // animations. | ||
619 | + const Curve animationCurve = Curves.fastLinearToSlowEaseIn; | ||
620 | + final bool animateForward; | ||
621 | + | ||
622 | + // If the user releases the page before mid screen with sufficient velocity, | ||
623 | + // or after mid screen, we should animate the page out. Otherwise, the page | ||
624 | + // should be animated back in. | ||
625 | + if (velocity.abs() >= _kMinFlingVelocity) { | ||
626 | + animateForward = velocity <= 0; | ||
627 | + } else { | ||
628 | + animateForward = controller.value > 0.5; | ||
629 | + } | ||
630 | + | ||
631 | + if (animateForward) { | ||
632 | + // The closer the panel is to dismissing, the shorter the animation is. | ||
633 | + // We want to cap the animation time, but we want to use a linear curve | ||
634 | + // to determine it. | ||
635 | + final droppedPageForwardAnimationTime = min( | ||
636 | + lerpDouble( | ||
637 | + _kMaxDroppedSwipePageForwardAnimationTime, 0, controller.value)! | ||
638 | + .floor(), | ||
639 | + _kMaxPageBackAnimationTime, | ||
640 | + ); | ||
641 | + controller.animateTo(1.0, | ||
642 | + duration: Duration(milliseconds: droppedPageForwardAnimationTime), | ||
643 | + curve: animationCurve); | ||
644 | + } else { | ||
645 | + // This route is destined to pop at this point. Reuse navigator's pop. | ||
646 | + navigator.pop(); | ||
647 | + | ||
648 | + // The popping may have finished inline if already at the | ||
649 | + // target destination. | ||
650 | + if (controller.isAnimating) { | ||
651 | + // Otherwise, use a custom popping animation duration and curve. | ||
652 | + final droppedPageBackAnimationTime = lerpDouble( | ||
653 | + 0, _kMaxDroppedSwipePageForwardAnimationTime, controller.value)! | ||
654 | + .floor(); | ||
655 | + controller.animateBack(0.0, | ||
656 | + duration: Duration(milliseconds: droppedPageBackAnimationTime), | ||
657 | + curve: animationCurve); | ||
658 | + } | ||
659 | + } | ||
660 | + | ||
661 | + if (controller.isAnimating) { | ||
662 | + // Keep the userGestureInProgress in true state so we don't change the | ||
663 | + // curve of the page transition mid-flight since CupertinoPageTransition | ||
664 | + // depends on userGestureInProgress. | ||
665 | + late AnimationStatusListener animationStatusCallback; | ||
666 | + animationStatusCallback = (status) { | ||
667 | + navigator.didStopUserGesture(); | ||
668 | + controller.removeStatusListener(animationStatusCallback); | ||
669 | + }; | ||
670 | + controller.addStatusListener(animationStatusCallback); | ||
671 | + } else { | ||
672 | + navigator.didStopUserGesture(); | ||
673 | + } | ||
674 | + } | ||
675 | +} |
@@ -158,14 +158,14 @@ class MiddlewareRunner { | @@ -158,14 +158,14 @@ class MiddlewareRunner { | ||
158 | class PageRedirect { | 158 | class PageRedirect { |
159 | GetPage? route; | 159 | GetPage? route; |
160 | GetPage? unknownRoute; | 160 | GetPage? unknownRoute; |
161 | - RouteSettings settings; | 161 | + RouteSettings? settings; |
162 | bool isUnknown; | 162 | bool isUnknown; |
163 | 163 | ||
164 | - PageRedirect( | ||
165 | - this.settings, | ||
166 | - this.unknownRoute, { | ||
167 | - this.isUnknown = false, | 164 | + PageRedirect({ |
168 | this.route, | 165 | this.route, |
166 | + this.unknownRoute, | ||
167 | + this.isUnknown = false, | ||
168 | + this.settings, | ||
169 | }); | 169 | }); |
170 | 170 | ||
171 | // redirect all pages that needes redirecting | 171 | // redirect all pages that needes redirecting |
@@ -178,11 +178,36 @@ class PageRedirect { | @@ -178,11 +178,36 @@ class PageRedirect { | ||
178 | settings: isUnknown | 178 | settings: isUnknown |
179 | ? RouteSettings( | 179 | ? RouteSettings( |
180 | name: _r.name, | 180 | name: _r.name, |
181 | - arguments: settings.arguments, | 181 | + arguments: settings!.arguments, |
182 | ) | 182 | ) |
183 | : settings, | 183 | : settings, |
184 | curve: _r.curve, | 184 | curve: _r.curve, |
185 | opaque: _r.opaque, | 185 | opaque: _r.opaque, |
186 | + gestureWidth: _r.gestureWidth, | ||
187 | + customTransition: _r.customTransition, | ||
188 | + binding: _r.binding, | ||
189 | + bindings: _r.bindings, | ||
190 | + transitionDuration: | ||
191 | + _r.transitionDuration ?? Get.defaultTransitionDuration, | ||
192 | + transition: _r.transition, | ||
193 | + popGesture: _r.popGesture, | ||
194 | + fullscreenDialog: _r.fullscreenDialog, | ||
195 | + middlewares: _r.middlewares, | ||
196 | + ); | ||
197 | + } | ||
198 | + | ||
199 | + // redirect all pages that needes redirecting | ||
200 | + GetPageRoute<T> getPageToRoute<T>(GetPage rou, GetPage? unk) { | ||
201 | + while (needRecheck()) {} | ||
202 | + final _r = (isUnknown ? unk : rou)!; | ||
203 | + | ||
204 | + return GetPageRoute<T>( | ||
205 | + page: _r.page, | ||
206 | + parameter: _r.parameter, | ||
207 | + settings: _r, | ||
208 | + curve: _r.curve, | ||
209 | + gestureWidth: _r.gestureWidth, | ||
210 | + opaque: _r.opaque, | ||
186 | customTransition: _r.customTransition, | 211 | customTransition: _r.customTransition, |
187 | binding: _r.binding, | 212 | binding: _r.binding, |
188 | bindings: _r.bindings, | 213 | bindings: _r.bindings, |
@@ -197,7 +222,10 @@ class PageRedirect { | @@ -197,7 +222,10 @@ class PageRedirect { | ||
197 | 222 | ||
198 | /// check if redirect is needed | 223 | /// check if redirect is needed |
199 | bool needRecheck() { | 224 | bool needRecheck() { |
200 | - final match = Get.routeTree.matchRoute(settings.name!); | 225 | + if (settings == null && route != null) { |
226 | + settings = route; | ||
227 | + } | ||
228 | + final match = Get.routeTree.matchRoute(settings!.name!); | ||
201 | Get.parameters = match.parameters; | 229 | Get.parameters = match.parameters; |
202 | 230 | ||
203 | // No Match found | 231 | // No Match found |
@@ -214,7 +242,7 @@ class PageRedirect { | @@ -214,7 +242,7 @@ class PageRedirect { | ||
214 | if (match.route!.middlewares == null || match.route!.middlewares!.isEmpty) { | 242 | if (match.route!.middlewares == null || match.route!.middlewares!.isEmpty) { |
215 | return false; | 243 | return false; |
216 | } | 244 | } |
217 | - final newSettings = runner.runRedirect(settings.name); | 245 | + final newSettings = runner.runRedirect(settings!.name); |
218 | if (newSettings == null) { | 246 | if (newSettings == null) { |
219 | return false; | 247 | return false; |
220 | } | 248 | } |
-
Please register or login to post a comment