Showing
8 changed files
with
887 additions
and
550 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, |
| @@ -1054,8 +1060,8 @@ you can only use widgets and widget functions here'''; | @@ -1054,8 +1060,8 @@ you can only use widgets and widget functions here'''; | ||
| 1054 | 1060 | ||
| 1055 | return _key; | 1061 | return _key; |
| 1056 | } | 1062 | } |
| 1057 | - | ||
| 1058 | - /// Casts the stored router delegate to a desired type | 1063 | + |
| 1064 | + /// Casts the stored router delegate to a desired type | ||
| 1059 | TDelegate? delegate<TDelegate extends RouterDelegate<TPage>, TPage>() => | 1065 | TDelegate? delegate<TDelegate extends RouterDelegate<TPage>, TPage>() => |
| 1060 | _routerDelegate as TDelegate?; | 1066 | _routerDelegate as TDelegate?; |
| 1061 | 1067 |
| @@ -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 | 87 | ||
| 423 | @override | 88 | @override |
| 424 | - _CupertinoBackGestureDetectorState<T> createState() => | ||
| 425 | - _CupertinoBackGestureDetectorState<T>(); | ||
| 426 | -} | ||
| 427 | - | ||
| 428 | -class _CupertinoBackGestureDetectorState<T> | ||
| 429 | - extends State<_CupertinoBackGestureDetector<T>> { | ||
| 430 | - _CupertinoBackGestureController<T>? _backGestureController; | 89 | + Widget buildContent(BuildContext context) { |
| 90 | + Get.reference = reference; | ||
| 91 | + final middlewareRunner = MiddlewareRunner(middlewares); | ||
| 92 | + final bindingsToBind = middlewareRunner.runOnBindingsStart(bindings); | ||
| 431 | 93 | ||
| 432 | - late HorizontalDragGestureRecognizer _recognizer; | 94 | + binding?.dependencies(); |
| 95 | + if (bindingsToBind != null) { | ||
| 96 | + for (final binding in bindingsToBind) { | ||
| 97 | + binding.dependencies(); | ||
| 98 | + } | ||
| 99 | + } | ||
| 433 | 100 | ||
| 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; | 101 | + final pageToBuild = middlewareRunner.runOnPageBuildStart(page)!; |
| 102 | + return middlewareRunner.runOnPageBuilt(pageToBuild()); | ||
| 442 | } | 103 | } |
| 443 | 104 | ||
| 444 | @override | 105 | @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 | - } | ||
| 470 | - | ||
| 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; | ||
| 477 | - } | ||
| 478 | - | ||
| 479 | - void _handlePointerDown(PointerDownEvent event) { | ||
| 480 | - if (widget.enabledCallback()) _recognizer.addPointer(event); | ||
| 481 | - } | ||
| 482 | - | ||
| 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 | - } | ||
| 492 | - } | 106 | + final String? title; |
| 493 | 107 | ||
| 494 | @override | 108 | @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 | - } | 109 | + String get debugLabel => '${super.debugLabel}(${settings.name})'; |
| 562 | 110 | ||
| 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 | - } | ||
| 600 | - | ||
| 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