Showing
9 changed files
with
558 additions
and
70 deletions
| @@ -117,5 +117,32 @@ | @@ -117,5 +117,32 @@ | ||
| 117 | ## [1.8.1] | 117 | ## [1.8.1] |
| 118 | -Fix new snackbar features | 118 | -Fix new snackbar features |
| 119 | 119 | ||
| 120 | +## [1.9.0] | ||
| 121 | + -Added: Navigator observer | ||
| 122 | + -Added: Get.args to named routes | ||
| 123 | + -Improve snackbar performance | ||
| 124 | + | ||
| 125 | +## [1.9.1] | ||
| 126 | + -Fix typo on snackbar route | ||
| 127 | + | ||
| 128 | +## [1.9.2] | ||
| 129 | + -Added docs to GetObserver | ||
| 130 | + | ||
| 131 | +## [1.10.0] | ||
| 132 | + -Added backdrop | ||
| 133 | + | ||
| 134 | +## [1.10.1] | ||
| 135 | + -Backdrop improvement | ||
| 136 | + | ||
| 137 | +## [1.10.2] | ||
| 138 | + -Improve snackbar text color | ||
| 139 | + | ||
| 140 | +## [1.10.3] | ||
| 141 | + -Improve default color from dialogs | ||
| 142 | + | ||
| 143 | +## [1.10.4] | ||
| 144 | + -Improve Get.offAll() - predicate now is optional | ||
| 145 | + | ||
| 146 | + | ||
| 120 | 147 | ||
| 121 | 148 |
| @@ -9,13 +9,15 @@ I worked on a pull to fix it in the framework, and seeing how things work I real | @@ -9,13 +9,15 @@ I worked on a pull to fix it in the framework, and seeing how things work I real | ||
| 9 | With that in mind, I created this library that will change the way you work with the Framework and save your life from cliche code, | 9 | With that in mind, I created this library that will change the way you work with the Framework and save your life from cliche code, |
| 10 | increasing your productivity, and eliminating all the bugs present in Flutter's default navigation altogether. | 10 | increasing your productivity, and eliminating all the bugs present in Flutter's default navigation altogether. |
| 11 | 11 | ||
| 12 | +##### If you use MODULAR, you can to use [GET MODULAR](https://pub.dev/packages/get_modular) | ||
| 13 | + | ||
| 12 | ## How to use? | 14 | ## How to use? |
| 13 | 15 | ||
| 14 | Add this to your package's pubspec.yaml file: | 16 | Add this to your package's pubspec.yaml file: |
| 15 | 17 | ||
| 16 | ``` | 18 | ``` |
| 17 | dependencies: | 19 | dependencies: |
| 18 | - get: ^1.9.2 | 20 | + get: ^1.10.4 |
| 19 | ``` | 21 | ``` |
| 20 | 22 | ||
| 21 | And import it: | 23 | And import it: |
| @@ -51,7 +53,7 @@ Get.off(NextScreen()); | @@ -51,7 +53,7 @@ Get.off(NextScreen()); | ||
| 51 | To go to the next screen and cancel all previous routes (useful in shopping carts, polls, and tests) | 53 | To go to the next screen and cancel all previous routes (useful in shopping carts, polls, and tests) |
| 52 | 54 | ||
| 53 | ```dart | 55 | ```dart |
| 54 | -Get.offAll(NextScreen(), (route) => false); | 56 | +Get.offAll(NextScreen()); |
| 55 | ``` | 57 | ``` |
| 56 | 58 | ||
| 57 | To navigate to the next route, and receive or update data as soon as you return from it: | 59 | To navigate to the next route, and receive or update data as soon as you return from it: |
| @@ -195,7 +197,7 @@ Get.offNamed("/NextScreen"); | @@ -195,7 +197,7 @@ Get.offNamed("/NextScreen"); | ||
| 195 | ``` | 197 | ``` |
| 196 | To navigate and remove all previous screens from the tree. | 198 | To navigate and remove all previous screens from the tree. |
| 197 | ```dart | 199 | ```dart |
| 198 | -Get.offAllNamed("/NextScreen", (route) => false); | 200 | +Get.offAllNamed("/NextScreen"); |
| 199 | ``` | 201 | ``` |
| 200 | 202 | ||
| 201 | ## Using with Named Routes and And offering full flutter_web support (REQUIRED FOR NAMED ROUTES): | 203 | ## Using with Named Routes and And offering full flutter_web support (REQUIRED FOR NAMED ROUTES): |
| @@ -213,7 +215,7 @@ void main() { | @@ -213,7 +215,7 @@ void main() { | ||
| 213 | } | 215 | } |
| 214 | ``` | 216 | ``` |
| 215 | #### Middleware | 217 | #### Middleware |
| 216 | -If you want to hear Get events to trigger actions, you can add a GetObserver to your materialApp. This is extremely useful for triggering events whenever a specific Screen is displayed on the screen. Currently on Flutter you would have to put the event on initState and wait for a possible response in a navigator.pop (context); to get that. But with Get, this is extremely simple! | 218 | +If you want listen Get events to trigger actions, you can add a GetObserver to your materialApp. This is extremely useful for triggering events whenever a specific Screen is displayed on the screen. Currently on Flutter you would have to put the event on initState and wait for a possible response in a navigator.pop (context); to get that. But with Get, this is extremely simple! |
| 217 | 219 | ||
| 218 | ##### add GetObserver(); | 220 | ##### add GetObserver(); |
| 219 | ```dart | 221 | ```dart |
| @@ -5,3 +5,4 @@ export 'src/routes.dart'; | @@ -5,3 +5,4 @@ export 'src/routes.dart'; | ||
| 5 | export 'src/snack.dart'; | 5 | export 'src/snack.dart'; |
| 6 | export 'src/bottomsheet.dart'; | 6 | export 'src/bottomsheet.dart'; |
| 7 | export 'src/snack_route.dart'; | 7 | export 'src/snack_route.dart'; |
| 8 | +export 'src/route_observer.dart'; |
lib/src/backdrop_blur.dart
0 → 100644
| 1 | +import 'dart:math' as math; | ||
| 2 | +import 'dart:ui' as ui; | ||
| 3 | + | ||
| 4 | +import 'package:flutter/material.dart'; | ||
| 5 | +import 'package:flutter/scheduler.dart'; | ||
| 6 | + | ||
| 7 | +class RippleBackdropAnimatePage extends StatefulWidget { | ||
| 8 | + const RippleBackdropAnimatePage({ | ||
| 9 | + Key key, | ||
| 10 | + this.child, | ||
| 11 | + this.childFade = false, | ||
| 12 | + this.duration = 300, | ||
| 13 | + this.blurRadius = 15.0, | ||
| 14 | + this.bottomButton, | ||
| 15 | + this.bottomHeight = kBottomNavigationBarHeight, | ||
| 16 | + this.bottomButtonRotate = true, | ||
| 17 | + this.bottomButtonRotateDegree = 45.0, | ||
| 18 | + }) : super(key: key); | ||
| 19 | + | ||
| 20 | + /// Child for page. | ||
| 21 | + final Widget child; | ||
| 22 | + | ||
| 23 | + /// When enabled, [child] will fade in when animation is going and fade out when popping. | ||
| 24 | + /// [false] is by default. | ||
| 25 | + final bool childFade; | ||
| 26 | + | ||
| 27 | + /// Animation's duration, | ||
| 28 | + /// including [Navigator.push], [Navigator.pop]. | ||
| 29 | + final int duration; | ||
| 30 | + | ||
| 31 | + /// Blur radius for [BackdropFilter]. | ||
| 32 | + final double blurRadius; | ||
| 33 | + | ||
| 34 | + /// [Widget] for bottom of the page. | ||
| 35 | + final Widget bottomButton; | ||
| 36 | + | ||
| 37 | + /// The height which [bottomButton] will occupy. | ||
| 38 | + /// [kBottomNavigationBarHeight] is by default. | ||
| 39 | + final double bottomHeight; | ||
| 40 | + | ||
| 41 | + /// When enabled, [bottomButton] will rotate when to animation is going. | ||
| 42 | + /// [true] is by default. | ||
| 43 | + final bool bottomButtonRotate; | ||
| 44 | + | ||
| 45 | + /// The degree which [bottomButton] will rotate. | ||
| 46 | + /// 45.0 is by default. | ||
| 47 | + final double bottomButtonRotateDegree; | ||
| 48 | + | ||
| 49 | + @override | ||
| 50 | + _RippleBackdropAnimatePageState createState() => | ||
| 51 | + _RippleBackdropAnimatePageState(); | ||
| 52 | +} | ||
| 53 | + | ||
| 54 | +class _RippleBackdropAnimatePageState extends State<RippleBackdropAnimatePage> | ||
| 55 | + with TickerProviderStateMixin { | ||
| 56 | + /// Boolean to prevent duplicate pop. | ||
| 57 | + bool _popping = false; | ||
| 58 | + | ||
| 59 | + /// Animation. | ||
| 60 | + int _animateDuration; | ||
| 61 | + double _backdropFilterSize = 0.0; | ||
| 62 | + double _popButtonOpacity = 0.0; | ||
| 63 | + double _popButtonRotateAngle = 0.0; | ||
| 64 | + Animation<double> _backDropFilterAnimation; | ||
| 65 | + AnimationController _backDropFilterController; | ||
| 66 | + Animation<double> _popButtonAnimation; | ||
| 67 | + AnimationController _popButtonController; | ||
| 68 | + Animation<double> _popButtonOpacityAnimation; | ||
| 69 | + AnimationController _popButtonOpacityController; | ||
| 70 | + | ||
| 71 | + @override | ||
| 72 | + void initState() { | ||
| 73 | + _animateDuration = widget.duration; | ||
| 74 | + SchedulerBinding.instance | ||
| 75 | + .addPostFrameCallback((_) => backDropFilterAnimate(context, true)); | ||
| 76 | + super.initState(); | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + @override | ||
| 80 | + void dispose() { | ||
| 81 | + _backDropFilterController?.dispose(); | ||
| 82 | + _popButtonController?.dispose(); | ||
| 83 | + super.dispose(); | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + double pythagoreanTheorem(double short, double long) { | ||
| 87 | + return math.sqrt(math.pow(short, 2) + math.pow(long, 2)); | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + void popButtonAnimate(context, bool forward) { | ||
| 91 | + if (!forward) { | ||
| 92 | + _popButtonController?.stop(); | ||
| 93 | + _popButtonOpacityController?.stop(); | ||
| 94 | + } | ||
| 95 | + final double rotateDegree = | ||
| 96 | + widget.bottomButtonRotateDegree * (math.pi / 180) * 3; | ||
| 97 | + | ||
| 98 | + _popButtonOpacityController = _popButtonController = AnimationController( | ||
| 99 | + duration: Duration(milliseconds: _animateDuration), | ||
| 100 | + vsync: this, | ||
| 101 | + ); | ||
| 102 | + Animation _popButtonCurve = CurvedAnimation( | ||
| 103 | + parent: _popButtonController, | ||
| 104 | + curve: Curves.easeInOut, | ||
| 105 | + ); | ||
| 106 | + _popButtonAnimation = Tween( | ||
| 107 | + begin: forward ? 0.0 : _popButtonRotateAngle, | ||
| 108 | + end: forward ? rotateDegree : 0.0, | ||
| 109 | + ).animate(_popButtonCurve) | ||
| 110 | + ..addListener(() { | ||
| 111 | + setState(() { | ||
| 112 | + _popButtonRotateAngle = _popButtonAnimation.value; | ||
| 113 | + }); | ||
| 114 | + }); | ||
| 115 | + _popButtonOpacityAnimation = Tween( | ||
| 116 | + begin: forward ? 0.0 : _popButtonOpacity, | ||
| 117 | + end: forward ? 1.0 : 0.0, | ||
| 118 | + ).animate(_popButtonCurve) | ||
| 119 | + ..addListener(() { | ||
| 120 | + setState(() { | ||
| 121 | + _popButtonOpacity = _popButtonOpacityAnimation.value; | ||
| 122 | + }); | ||
| 123 | + }); | ||
| 124 | + _popButtonController.forward(); | ||
| 125 | + _popButtonOpacityController.forward(); | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + Future backDropFilterAnimate(BuildContext context, bool forward) async { | ||
| 129 | + final MediaQueryData m = MediaQuery.of(context); | ||
| 130 | + final Size s = m.size; | ||
| 131 | + final double r = | ||
| 132 | + pythagoreanTheorem(s.width, s.height * 2 + m.padding.top) / 2; | ||
| 133 | + if (!forward) _backDropFilterController?.stop(); | ||
| 134 | + popButtonAnimate(context, forward); | ||
| 135 | + | ||
| 136 | + _backDropFilterController = AnimationController( | ||
| 137 | + duration: Duration(milliseconds: _animateDuration), | ||
| 138 | + vsync: this, | ||
| 139 | + ); | ||
| 140 | + Animation _backDropFilterCurve = CurvedAnimation( | ||
| 141 | + parent: _backDropFilterController, | ||
| 142 | + curve: forward ? Curves.easeInOut : Curves.easeIn, | ||
| 143 | + ); | ||
| 144 | + _backDropFilterAnimation = Tween( | ||
| 145 | + begin: forward ? 0.0 : _backdropFilterSize, | ||
| 146 | + end: forward ? r * 2 : 0.0, | ||
| 147 | + ).animate(_backDropFilterCurve) | ||
| 148 | + ..addListener(() { | ||
| 149 | + setState(() { | ||
| 150 | + _backdropFilterSize = _backDropFilterAnimation.value; | ||
| 151 | + }); | ||
| 152 | + }); | ||
| 153 | + await _backDropFilterController.forward(); | ||
| 154 | + } | ||
| 155 | + | ||
| 156 | + Widget popButton() { | ||
| 157 | + Widget button = widget.bottomButton ?? Icon(Icons.add, color: Colors.grey); | ||
| 158 | + if (widget.bottomButtonRotate) { | ||
| 159 | + button = Transform.rotate( | ||
| 160 | + angle: _popButtonRotateAngle, | ||
| 161 | + child: button, | ||
| 162 | + ); | ||
| 163 | + } | ||
| 164 | + button = Opacity( | ||
| 165 | + opacity: _popButtonOpacity, | ||
| 166 | + child: SizedBox( | ||
| 167 | + width: widget.bottomHeight, | ||
| 168 | + height: widget.bottomHeight, | ||
| 169 | + child: Center( | ||
| 170 | + child: GestureDetector( | ||
| 171 | + behavior: HitTestBehavior.opaque, | ||
| 172 | + child: button, | ||
| 173 | + onTap: willPop, | ||
| 174 | + ), | ||
| 175 | + ), | ||
| 176 | + ), | ||
| 177 | + ); | ||
| 178 | + | ||
| 179 | + return button; | ||
| 180 | + } | ||
| 181 | + | ||
| 182 | + Widget wrapper(context, {Widget child}) { | ||
| 183 | + final MediaQueryData m = MediaQuery.of(context); | ||
| 184 | + final Size s = m.size; | ||
| 185 | + final double r = | ||
| 186 | + pythagoreanTheorem(s.width, s.height * 2 + m.padding.top) / 2; | ||
| 187 | + final double topOverflow = r - s.height; | ||
| 188 | + final double horizontalOverflow = r - s.width; | ||
| 189 | + | ||
| 190 | + return Stack( | ||
| 191 | + overflow: Overflow.visible, | ||
| 192 | + children: <Widget>[ | ||
| 193 | + Positioned( | ||
| 194 | + left: -horizontalOverflow, | ||
| 195 | + right: -horizontalOverflow, | ||
| 196 | + top: -topOverflow, | ||
| 197 | + bottom: -r, | ||
| 198 | + child: GestureDetector( | ||
| 199 | + behavior: HitTestBehavior.opaque, | ||
| 200 | + onTap: willPop, | ||
| 201 | + child: Center( | ||
| 202 | + child: SizedBox( | ||
| 203 | + width: _backdropFilterSize, | ||
| 204 | + height: _backdropFilterSize, | ||
| 205 | + child: ClipRRect( | ||
| 206 | + borderRadius: BorderRadius.circular(r * 2), | ||
| 207 | + child: BackdropFilter( | ||
| 208 | + filter: ui.ImageFilter.blur( | ||
| 209 | + sigmaX: widget.blurRadius, | ||
| 210 | + sigmaY: widget.blurRadius, | ||
| 211 | + ), | ||
| 212 | + child: Text(" "), | ||
| 213 | + ), | ||
| 214 | + ), | ||
| 215 | + ), | ||
| 216 | + ), | ||
| 217 | + ), | ||
| 218 | + ), | ||
| 219 | + Align( | ||
| 220 | + alignment: Alignment.topCenter, | ||
| 221 | + child: Container( | ||
| 222 | + margin: EdgeInsets.only(top: topOverflow + 10), | ||
| 223 | + width: s.width, | ||
| 224 | + height: s.height, | ||
| 225 | + constraints: BoxConstraints( | ||
| 226 | + maxWidth: s.width, | ||
| 227 | + maxHeight: s.height, | ||
| 228 | + ), | ||
| 229 | + child: Column( | ||
| 230 | + mainAxisAlignment: MainAxisAlignment.end, | ||
| 231 | + children: <Widget>[ | ||
| 232 | + Expanded( | ||
| 233 | + child: Opacity( | ||
| 234 | + opacity: widget.childFade ? _popButtonOpacity : 1.0, | ||
| 235 | + child: child, | ||
| 236 | + ), | ||
| 237 | + ), | ||
| 238 | + popButton(), | ||
| 239 | + ], | ||
| 240 | + ), | ||
| 241 | + ), | ||
| 242 | + ), | ||
| 243 | + ], | ||
| 244 | + ); | ||
| 245 | + } | ||
| 246 | + | ||
| 247 | + Future<bool> willPop() async { | ||
| 248 | + await backDropFilterAnimate(context, false); | ||
| 249 | + if (!_popping) { | ||
| 250 | + _popping = true; | ||
| 251 | + await Future.delayed(Duration(milliseconds: _animateDuration), () { | ||
| 252 | + Navigator.of(context).pop(); | ||
| 253 | + }); | ||
| 254 | + } | ||
| 255 | + return null; | ||
| 256 | + } | ||
| 257 | + | ||
| 258 | + @override | ||
| 259 | + Widget build(BuildContext context) { | ||
| 260 | + return Scaffold( | ||
| 261 | + backgroundColor: Colors.transparent, | ||
| 262 | + body: WillPopScope( | ||
| 263 | + onWillPop: willPop, | ||
| 264 | + child: wrapper( | ||
| 265 | + context, | ||
| 266 | + child: widget.child, | ||
| 267 | + ), | ||
| 268 | + ), | ||
| 269 | + ); | ||
| 270 | + } | ||
| 271 | +} |
| @@ -43,6 +43,7 @@ Future<T> getShowGeneralDialog<T>({ | @@ -43,6 +43,7 @@ Future<T> getShowGeneralDialog<T>({ | ||
| 43 | assert(!barrierDismissible || barrierLabel != null); | 43 | assert(!barrierDismissible || barrierLabel != null); |
| 44 | return Get.key.currentState.push<T>(_DialogRoute<T>( | 44 | return Get.key.currentState.push<T>(_DialogRoute<T>( |
| 45 | pageBuilder: pageBuilder, | 45 | pageBuilder: pageBuilder, |
| 46 | + settings: RouteSettings(name: "dialog"), // REMOVE THIS IF ERROR | ||
| 46 | barrierDismissible: barrierDismissible, | 47 | barrierDismissible: barrierDismissible, |
| 47 | barrierLabel: barrierLabel, | 48 | barrierLabel: barrierLabel, |
| 48 | barrierColor: barrierColor, | 49 | barrierColor: barrierColor, |
lib/src/route_observer.dart
0 → 100644
| 1 | +import 'package:flutter/widgets.dart'; | ||
| 2 | + | ||
| 3 | +class Routing { | ||
| 4 | + final current; | ||
| 5 | + final previous; | ||
| 6 | + final args; | ||
| 7 | + final previousArgs; | ||
| 8 | + final removed; | ||
| 9 | + final bool isBack; | ||
| 10 | + final bool isSnackbar; | ||
| 11 | + final bool isBottomSheet; | ||
| 12 | + final bool isDialog; | ||
| 13 | + Routing({ | ||
| 14 | + this.current, | ||
| 15 | + this.previous, | ||
| 16 | + this.args, | ||
| 17 | + this.previousArgs, | ||
| 18 | + this.removed, | ||
| 19 | + this.isBack, | ||
| 20 | + this.isSnackbar, | ||
| 21 | + this.isBottomSheet, | ||
| 22 | + this.isDialog, | ||
| 23 | + }); | ||
| 24 | +} | ||
| 25 | + | ||
| 26 | +class GetObserver extends NavigatorObserver { | ||
| 27 | + final Function(Routing) routing; | ||
| 28 | + GetObserver(this.routing); | ||
| 29 | + @override | ||
| 30 | + void didPush(Route<dynamic> route, Route<dynamic> previousRoute) { | ||
| 31 | + if ('${route?.settings?.name}' == 'snackbar') { | ||
| 32 | + print("[OPEN SNACKBAR] ${route?.settings?.name}"); | ||
| 33 | + } else if ('${route?.settings?.name}' == 'bottomsheet') { | ||
| 34 | + print("[OPEN BOTTOMSHEET] ${route?.settings?.name}"); | ||
| 35 | + } else if ('${route?.settings?.name}' == 'dialog') { | ||
| 36 | + print("[OPEN DIALOG] ${route?.settings?.name}"); | ||
| 37 | + } else { | ||
| 38 | + print("[GOING TO ROUTE] ${route?.settings?.name}"); | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + routing(Routing( | ||
| 42 | + removed: null, | ||
| 43 | + isBack: false, | ||
| 44 | + current: '${route?.settings?.name}', | ||
| 45 | + previous: '${previousRoute?.settings?.name}', | ||
| 46 | + args: route?.settings?.arguments, | ||
| 47 | + previousArgs: previousRoute?.settings?.arguments, | ||
| 48 | + isSnackbar: '${route?.settings?.name}' == 'snackbar')); | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + @override | ||
| 52 | + void didPop(Route route, Route previousRoute) { | ||
| 53 | + super.didPop(route, previousRoute); | ||
| 54 | + | ||
| 55 | + if ('${route?.settings?.name}' == 'snackbar') { | ||
| 56 | + print("[CLOSE SNACKBAR] ${route?.settings?.name}"); | ||
| 57 | + } else if ('${route?.settings?.name}' == 'bottomsheet') { | ||
| 58 | + print("[CLOSE BOTTOMSHEET] ${route?.settings?.name}"); | ||
| 59 | + } else if ('${route?.settings?.name}' == 'dialog') { | ||
| 60 | + print("[CLOSE DIALOG] ${route?.settings?.name}"); | ||
| 61 | + } else if ('${route?.settings?.name}' == 'snackbar') { | ||
| 62 | + print("[CLOSE SNACKBAR] ${route?.settings?.name}"); | ||
| 63 | + } else { | ||
| 64 | + print("[BACK ROUTE] ${route?.settings?.name}"); | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + routing(Routing( | ||
| 68 | + removed: null, | ||
| 69 | + isBack: true, | ||
| 70 | + current: '${previousRoute?.settings?.name}', | ||
| 71 | + previous: '${route?.settings?.name}', | ||
| 72 | + args: previousRoute?.settings?.arguments, | ||
| 73 | + previousArgs: route?.settings?.arguments, | ||
| 74 | + isSnackbar: '${route?.settings?.name}' == 'snackbar')); | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + @override | ||
| 78 | + void didReplace({Route newRoute, Route oldRoute}) { | ||
| 79 | + super.didReplace(newRoute: newRoute, oldRoute: oldRoute); | ||
| 80 | + print("[REPLACE ROUTE] ${oldRoute?.settings?.name}"); | ||
| 81 | + | ||
| 82 | + routing(Routing( | ||
| 83 | + removed: null, // add '${oldRoute?.settings?.name}' or remain null ??? | ||
| 84 | + isBack: false, | ||
| 85 | + current: '${newRoute?.settings?.name}', | ||
| 86 | + previous: '${oldRoute?.settings?.name}', | ||
| 87 | + args: newRoute?.settings?.arguments, | ||
| 88 | + isSnackbar: null, | ||
| 89 | + previousArgs: null)); | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + @override | ||
| 93 | + void didRemove(Route route, Route previousRoute) { | ||
| 94 | + super.didRemove(route, previousRoute); | ||
| 95 | + print("[REMOVING ROUTE] ${route?.settings?.name}"); | ||
| 96 | + | ||
| 97 | + routing(Routing( | ||
| 98 | + isBack: false, | ||
| 99 | + current: '${previousRoute?.settings?.name}', | ||
| 100 | + removed: '${route?.settings?.name}', | ||
| 101 | + previous: null, | ||
| 102 | + isSnackbar: null, | ||
| 103 | + args: previousRoute?.settings?.arguments, | ||
| 104 | + previousArgs: route?.settings?.arguments)); | ||
| 105 | + } | ||
| 106 | +} |
| 1 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
| 2 | +import 'package:flutter/scheduler.dart'; | ||
| 3 | +import 'backdrop_blur.dart'; | ||
| 2 | import 'bottomsheet.dart'; | 4 | import 'bottomsheet.dart'; |
| 3 | import 'dialog.dart'; | 5 | import 'dialog.dart'; |
| 4 | import 'snack.dart'; | 6 | import 'snack.dart'; |
| 5 | import 'getroute.dart'; | 7 | import 'getroute.dart'; |
| 8 | +import 'transparent_route.dart'; | ||
| 6 | 9 | ||
| 7 | class Get { | 10 | class Get { |
| 8 | static Get _get; | 11 | static Get _get; |
| @@ -31,11 +34,16 @@ class Get { | @@ -31,11 +34,16 @@ class Get { | ||
| 31 | /// routes rebuild bug present in Flutter. If for some strange reason you want the default behavior | 34 | /// routes rebuild bug present in Flutter. If for some strange reason you want the default behavior |
| 32 | /// of rebuilding every app after a route, use rebuildRoutes = true as the parameter. | 35 | /// of rebuilding every app after a route, use rebuildRoutes = true as the parameter. |
| 33 | static to(Widget page, | 36 | static to(Widget page, |
| 34 | - {bool rebuildRoutes = false, Transition transition = Transition.fade}) { | 37 | + {bool rebuildRoutes = false, |
| 38 | + Transition transition = Transition.fade, | ||
| 39 | + Duration duration = const Duration(milliseconds: 400)}) { | ||
| 35 | // if (key.currentState.mounted) // add this if appear problems on future with route navigate | 40 | // if (key.currentState.mounted) // add this if appear problems on future with route navigate |
| 36 | // when widget don't mounted | 41 | // when widget don't mounted |
| 37 | - return key.currentState.push( | ||
| 38 | - GetRoute(opaque: rebuildRoutes, page: page, transition: transition)); | 42 | + return key.currentState.push(GetRoute( |
| 43 | + opaque: rebuildRoutes, | ||
| 44 | + page: page, | ||
| 45 | + transition: transition, | ||
| 46 | + duration: duration)); | ||
| 39 | } | 47 | } |
| 40 | 48 | ||
| 41 | /// It replaces Navigator.pushNamed, but needs no context, and it doesn't have the Navigator.pushNamed | 49 | /// It replaces Navigator.pushNamed, but needs no context, and it doesn't have the Navigator.pushNamed |
| @@ -82,16 +90,18 @@ class Get { | @@ -82,16 +90,18 @@ class Get { | ||
| 82 | 90 | ||
| 83 | /// It replaces Navigator.pushNamedAndRemoveUntil, but needs no context. | 91 | /// It replaces Navigator.pushNamedAndRemoveUntil, but needs no context. |
| 84 | static offAllNamed( | 92 | static offAllNamed( |
| 85 | - String newRouteName, | ||
| 86 | - RoutePredicate predicate, { | 93 | + String newRouteName, { |
| 94 | + RoutePredicate predicate, | ||
| 87 | arguments, | 95 | arguments, |
| 88 | }) { | 96 | }) { |
| 89 | - return key.currentState | ||
| 90 | - .pushNamedAndRemoveUntil(newRouteName, predicate, arguments: arguments); | 97 | + var route = (Route<dynamic> rota) => false; |
| 98 | + return key.currentState.pushNamedAndRemoveUntil( | ||
| 99 | + newRouteName, predicate ?? route, | ||
| 100 | + arguments: arguments); | ||
| 91 | } | 101 | } |
| 92 | 102 | ||
| 93 | /// It replaces Navigator.pop, but needs no context. | 103 | /// It replaces Navigator.pop, but needs no context. |
| 94 | - static back({result}) { | 104 | + static back({dynamic result}) { |
| 95 | return key.currentState.pop(result); | 105 | return key.currentState.pop(result); |
| 96 | } | 106 | } |
| 97 | 107 | ||
| @@ -112,18 +122,24 @@ class Get { | @@ -112,18 +122,24 @@ class Get { | ||
| 112 | /// of rebuilding every app after a route, use rebuildRoutes = true as the parameter. | 122 | /// of rebuilding every app after a route, use rebuildRoutes = true as the parameter. |
| 113 | static off(Widget page, | 123 | static off(Widget page, |
| 114 | {bool rebuildRoutes = false, | 124 | {bool rebuildRoutes = false, |
| 115 | - Transition transition = Transition.rightToLeft}) { | ||
| 116 | - return key.currentState.pushReplacement( | ||
| 117 | - GetRoute(opaque: rebuildRoutes, page: page, transition: transition)); | 125 | + Transition transition = Transition.rightToLeft, |
| 126 | + Duration duration = const Duration(milliseconds: 400)}) { | ||
| 127 | + return key.currentState.pushReplacement(GetRoute( | ||
| 128 | + opaque: rebuildRoutes, | ||
| 129 | + page: page, | ||
| 130 | + transition: transition, | ||
| 131 | + duration: duration)); | ||
| 118 | } | 132 | } |
| 119 | 133 | ||
| 120 | /// It replaces Navigator.pushAndRemoveUntil, but needs no context | 134 | /// It replaces Navigator.pushAndRemoveUntil, but needs no context |
| 121 | - static offAll(Widget page, RoutePredicate predicate, | ||
| 122 | - {bool rebuildRoutes = false, | 135 | + static offAll(Widget page, |
| 136 | + {RoutePredicate predicate, | ||
| 137 | + bool rebuildRoutes = false, | ||
| 123 | Transition transition = Transition.rightToLeft}) { | 138 | Transition transition = Transition.rightToLeft}) { |
| 139 | + var route = (Route<dynamic> rota) => false; | ||
| 124 | return key.currentState.pushAndRemoveUntil( | 140 | return key.currentState.pushAndRemoveUntil( |
| 125 | GetRoute(opaque: rebuildRoutes, page: page, transition: transition), | 141 | GetRoute(opaque: rebuildRoutes, page: page, transition: transition), |
| 126 | - predicate); | 142 | + predicate ?? route); |
| 127 | } | 143 | } |
| 128 | 144 | ||
| 129 | /// Show a dialog. You can choose color and opacity of background | 145 | /// Show a dialog. You can choose color and opacity of background |
| @@ -137,6 +153,7 @@ class Get { | @@ -137,6 +153,7 @@ class Get { | ||
| 137 | assert(useRootNavigator != null); | 153 | assert(useRootNavigator != null); |
| 138 | final ThemeData theme = | 154 | final ThemeData theme = |
| 139 | Theme.of(Get.key.currentContext, shadowThemeOnly: true); | 155 | Theme.of(Get.key.currentContext, shadowThemeOnly: true); |
| 156 | + | ||
| 140 | return getShowGeneralDialog( | 157 | return getShowGeneralDialog( |
| 141 | pageBuilder: (BuildContext buildContext, Animation<double> animation, | 158 | pageBuilder: (BuildContext buildContext, Animation<double> animation, |
| 142 | Animation<double> secondaryAnimation) { | 159 | Animation<double> secondaryAnimation) { |
| @@ -208,10 +225,40 @@ class Get { | @@ -208,10 +225,40 @@ class Get { | ||
| 208 | clipBehavior: clipBehavior, | 225 | clipBehavior: clipBehavior, |
| 209 | isDismissible: isDismissible, | 226 | isDismissible: isDismissible, |
| 210 | modalBarrierColor: barrierColor, | 227 | modalBarrierColor: barrierColor, |
| 228 | + settings: RouteSettings(name: "bottomsheet"), | ||
| 211 | enableDrag: enableDrag, | 229 | enableDrag: enableDrag, |
| 212 | )); | 230 | )); |
| 213 | } | 231 | } |
| 214 | 232 | ||
| 233 | + /// get arguments from current screen. You need of context | ||
| 234 | + static args(context) { | ||
| 235 | + return ModalRoute.of(context).settings.arguments; | ||
| 236 | + } | ||
| 237 | + | ||
| 238 | + static backdrop(Widget child, | ||
| 239 | + {double radius = 20.0, | ||
| 240 | + double blurRadius: 20.0, | ||
| 241 | + int duration = 300, | ||
| 242 | + Transition transition = Transition.fade, | ||
| 243 | + Widget bottomButton = const Icon(Icons.visibility), | ||
| 244 | + double bottomHeight = 60.0, | ||
| 245 | + bool bottomButtonRotate = false}) { | ||
| 246 | + final page = RippleBackdropAnimatePage( | ||
| 247 | + child: child, | ||
| 248 | + childFade: true, | ||
| 249 | + duration: duration, | ||
| 250 | + blurRadius: blurRadius, | ||
| 251 | + bottomButton: bottomButton, | ||
| 252 | + bottomHeight: bottomHeight, | ||
| 253 | + bottomButtonRotate: bottomButtonRotate, | ||
| 254 | + ); | ||
| 255 | + | ||
| 256 | + return key.currentState | ||
| 257 | + .push(TransparentRoute(builder: (BuildContext context) { | ||
| 258 | + return page; | ||
| 259 | + })); | ||
| 260 | + } | ||
| 261 | + | ||
| 215 | static snackbar(title, message, | 262 | static snackbar(title, message, |
| 216 | {Color colorText, | 263 | {Color colorText, |
| 217 | Duration duration, | 264 | Duration duration, |
| @@ -246,56 +293,56 @@ class Get { | @@ -246,56 +293,56 @@ class Get { | ||
| 246 | double overlayBlur, | 293 | double overlayBlur, |
| 247 | Color overlayColor, | 294 | Color overlayColor, |
| 248 | Form userInputForm}) { | 295 | Form userInputForm}) { |
| 249 | - // if (key.currentState.mounted) | ||
| 250 | - return GetBar( | ||
| 251 | - titleText: titleText ?? | ||
| 252 | - Text( | ||
| 253 | - title, | ||
| 254 | - style: TextStyle( | ||
| 255 | - color: | ||
| 256 | - colorText ?? Theme.of(Get.key.currentContext).accentColor, | ||
| 257 | - fontWeight: FontWeight.w800, | ||
| 258 | - fontSize: 16), | ||
| 259 | - ), | ||
| 260 | - messageText: messageText ?? | ||
| 261 | - Text( | ||
| 262 | - message, | ||
| 263 | - style: TextStyle( | ||
| 264 | - color: | ||
| 265 | - colorText ?? Theme.of(Get.key.currentContext).accentColor, | ||
| 266 | - fontWeight: FontWeight.w300, | ||
| 267 | - fontSize: 14), | ||
| 268 | - ), | ||
| 269 | - snackPosition: snackPosition ?? SnackPosition.TOP, | ||
| 270 | - borderRadius: borderRadius ?? 15, | ||
| 271 | - margin: margin ?? EdgeInsets.symmetric(horizontal: 10), | ||
| 272 | - duration: duration ?? Duration(seconds: 3), | ||
| 273 | - barBlur: barBlur ?? 7.0, | ||
| 274 | - backgroundColor: backgroundColor ?? Colors.grey.withOpacity(0.2), | ||
| 275 | - icon: icon, | ||
| 276 | - shouldIconPulse: shouldIconPulse ?? true, | ||
| 277 | - maxWidth: maxWidth, | ||
| 278 | - padding: padding ?? EdgeInsets.all(16), | ||
| 279 | - borderColor: borderColor, | ||
| 280 | - borderWidth: borderWidth, | ||
| 281 | - leftBarIndicatorColor: leftBarIndicatorColor, | ||
| 282 | - boxShadows: boxShadows, | ||
| 283 | - backgroundGradient: backgroundGradient, | ||
| 284 | - mainButton: mainButton, | ||
| 285 | - onTap: onTap, | ||
| 286 | - isDismissible: isDismissible ?? true, | ||
| 287 | - dismissDirection: dismissDirection ?? SnackDismissDirection.VERTICAL, | ||
| 288 | - showProgressIndicator: showProgressIndicator ?? false, | ||
| 289 | - progressIndicatorController: progressIndicatorController, | ||
| 290 | - progressIndicatorBackgroundColor: progressIndicatorBackgroundColor, | ||
| 291 | - progressIndicatorValueColor: progressIndicatorValueColor, | ||
| 292 | - snackStyle: snackStyle ?? SnackStyle.FLOATING, | ||
| 293 | - forwardAnimationCurve: forwardAnimationCurve ?? Curves.easeOutCirc, | ||
| 294 | - reverseAnimationCurve: reverseAnimationCurve ?? Curves.easeOutCirc, | ||
| 295 | - animationDuration: animationDuration ?? Duration(seconds: 1), | ||
| 296 | - overlayBlur: overlayBlur ?? 0.0, | ||
| 297 | - overlayColor: overlayColor ?? Colors.transparent, | ||
| 298 | - userInputForm: userInputForm) | ||
| 299 | - ..show(); | 296 | + SchedulerBinding.instance.addPostFrameCallback((_) { |
| 297 | + final Color defaultColor = IconTheme.of(Get.key.currentContext).color; | ||
| 298 | + return GetBar( | ||
| 299 | + titleText: titleText ?? | ||
| 300 | + Text( | ||
| 301 | + title, | ||
| 302 | + style: TextStyle( | ||
| 303 | + color: colorText ?? defaultColor, | ||
| 304 | + fontWeight: FontWeight.w800, | ||
| 305 | + fontSize: 16), | ||
| 306 | + ), | ||
| 307 | + messageText: messageText ?? | ||
| 308 | + Text( | ||
| 309 | + message, | ||
| 310 | + style: TextStyle( | ||
| 311 | + color: colorText ?? defaultColor, | ||
| 312 | + fontWeight: FontWeight.w300, | ||
| 313 | + fontSize: 14), | ||
| 314 | + ), | ||
| 315 | + snackPosition: snackPosition ?? SnackPosition.TOP, | ||
| 316 | + borderRadius: borderRadius ?? 15, | ||
| 317 | + margin: margin ?? EdgeInsets.symmetric(horizontal: 10), | ||
| 318 | + duration: duration ?? Duration(seconds: 3), | ||
| 319 | + barBlur: barBlur ?? 7.0, | ||
| 320 | + backgroundColor: backgroundColor ?? Colors.grey.withOpacity(0.2), | ||
| 321 | + icon: icon, | ||
| 322 | + shouldIconPulse: shouldIconPulse ?? true, | ||
| 323 | + maxWidth: maxWidth, | ||
| 324 | + padding: padding ?? EdgeInsets.all(16), | ||
| 325 | + borderColor: borderColor, | ||
| 326 | + borderWidth: borderWidth, | ||
| 327 | + leftBarIndicatorColor: leftBarIndicatorColor, | ||
| 328 | + boxShadows: boxShadows, | ||
| 329 | + backgroundGradient: backgroundGradient, | ||
| 330 | + mainButton: mainButton, | ||
| 331 | + onTap: onTap, | ||
| 332 | + isDismissible: isDismissible ?? true, | ||
| 333 | + dismissDirection: dismissDirection ?? SnackDismissDirection.VERTICAL, | ||
| 334 | + showProgressIndicator: showProgressIndicator ?? false, | ||
| 335 | + progressIndicatorController: progressIndicatorController, | ||
| 336 | + progressIndicatorBackgroundColor: progressIndicatorBackgroundColor, | ||
| 337 | + progressIndicatorValueColor: progressIndicatorValueColor, | ||
| 338 | + snackStyle: snackStyle ?? SnackStyle.FLOATING, | ||
| 339 | + forwardAnimationCurve: forwardAnimationCurve ?? Curves.easeOutCirc, | ||
| 340 | + reverseAnimationCurve: reverseAnimationCurve ?? Curves.easeOutCirc, | ||
| 341 | + animationDuration: animationDuration ?? Duration(seconds: 1), | ||
| 342 | + overlayBlur: overlayBlur ?? 0.0, | ||
| 343 | + overlayColor: overlayColor ?? Colors.transparent, | ||
| 344 | + userInputForm: userInputForm) | ||
| 345 | + ..show(); | ||
| 346 | + }); | ||
| 300 | } | 347 | } |
| 301 | } | 348 | } |
lib/src/transparent_route.dart
0 → 100644
| 1 | +import 'package:flutter/material.dart'; | ||
| 2 | + | ||
| 3 | +class TransparentRoute extends PageRoute<void> { | ||
| 4 | + TransparentRoute({ | ||
| 5 | + @required this.builder, | ||
| 6 | + RouteSettings settings, | ||
| 7 | + }) : assert(builder != null), | ||
| 8 | + super(settings: settings, fullscreenDialog: false); | ||
| 9 | + | ||
| 10 | + final WidgetBuilder builder; | ||
| 11 | + | ||
| 12 | + @override | ||
| 13 | + bool get opaque => false; | ||
| 14 | + @override | ||
| 15 | + Color get barrierColor => null; | ||
| 16 | + @override | ||
| 17 | + String get barrierLabel => null; | ||
| 18 | + @override | ||
| 19 | + bool get maintainState => true; | ||
| 20 | + @override | ||
| 21 | + Duration get transitionDuration => Duration.zero; | ||
| 22 | + | ||
| 23 | + @override | ||
| 24 | + Widget buildPage(BuildContext context, Animation<double> animation, | ||
| 25 | + Animation<double> secondaryAnimation) { | ||
| 26 | + final result = builder(context); | ||
| 27 | + return Semantics( | ||
| 28 | + scopesRoute: true, | ||
| 29 | + explicitChildNodes: true, | ||
| 30 | + child: result, | ||
| 31 | + ); | ||
| 32 | + } | ||
| 33 | +} |
| 1 | name: get | 1 | name: get |
| 2 | description: A consistent navigation library that lets you navigate between screens, open dialogs, and display snackbars easily with no context. | 2 | description: A consistent navigation library that lets you navigate between screens, open dialogs, and display snackbars easily with no context. |
| 3 | -version: 1.8.1 | 3 | +version: 1.10.4 |
| 4 | homepage: https://github.com/jonataslaw/get | 4 | homepage: https://github.com/jonataslaw/get |
| 5 | 5 | ||
| 6 | environment: | 6 | environment: |
-
Please register or login to post a comment