Jonny Borges
Committed by GitHub

Merge pull request #2008 from jonataslaw/snackbar2.0

prepare snackbar api to getx 5
@@ -17,4 +17,4 @@ export 'src/routes/observers/route_observer.dart'; @@ -17,4 +17,4 @@ export 'src/routes/observers/route_observer.dart';
17 export 'src/routes/route_middleware.dart'; 17 export 'src/routes/route_middleware.dart';
18 export 'src/routes/transitions_type.dart'; 18 export 'src/routes/transitions_type.dart';
19 export 'src/snackbar/snack.dart'; 19 export 'src/snackbar/snack.dart';
20 -export 'src/snackbar/snack_route.dart'; 20 +export 'src/snackbar/snackbar_controller.dart';
@@ -11,243 +11,56 @@ import 'dialog/dialog_route.dart'; @@ -11,243 +11,56 @@ import 'dialog/dialog_route.dart';
11 import 'root/parse_route.dart'; 11 import 'root/parse_route.dart';
12 import 'root/root_controller.dart'; 12 import 'root/root_controller.dart';
13 import 'routes/transitions_type.dart'; 13 import 'routes/transitions_type.dart';
  14 +import 'snackbar/snackbar_controller.dart';
14 15
15 -extension ExtensionSnackbar on GetInterface {  
16 - void rawSnackbar({  
17 - String? title,  
18 - String? message,  
19 - Widget? titleText,  
20 - Widget? messageText,  
21 - Widget? icon,  
22 - bool instantInit = true,  
23 - bool shouldIconPulse = true,  
24 - double? maxWidth,  
25 - EdgeInsets margin = const EdgeInsets.all(0.0),  
26 - EdgeInsets padding = const EdgeInsets.all(16),  
27 - double borderRadius = 0.0,  
28 - Color? borderColor,  
29 - double borderWidth = 1.0,  
30 - Color backgroundColor = const Color(0xFF303030),  
31 - Color? leftBarIndicatorColor,  
32 - List<BoxShadow>? boxShadows,  
33 - Gradient? backgroundGradient,  
34 - Widget? mainButton,  
35 - OnTap? onTap,  
36 - Duration duration = const Duration(seconds: 3),  
37 - bool isDismissible = true,  
38 - SnackDismissDirection dismissDirection = SnackDismissDirection.VERTICAL,  
39 - bool showProgressIndicator = false,  
40 - AnimationController? progressIndicatorController,  
41 - Color? progressIndicatorBackgroundColor,  
42 - Animation<Color>? progressIndicatorValueColor,  
43 - SnackPosition snackPosition = SnackPosition.BOTTOM,  
44 - SnackStyle snackStyle = SnackStyle.FLOATING,  
45 - Curve forwardAnimationCurve = Curves.easeOutCirc,  
46 - Curve reverseAnimationCurve = Curves.easeOutCirc,  
47 - Duration animationDuration = const Duration(seconds: 1),  
48 - SnackbarStatusCallback? snackbarStatus,  
49 - double? barBlur = 0.0,  
50 - double overlayBlur = 0.0,  
51 - Color? overlayColor,  
52 - Form? userInputForm,  
53 - }) async {  
54 - final getBar = GetBar(  
55 - snackbarStatus: snackbarStatus,  
56 - title: title,  
57 - message: message,  
58 - titleText: titleText,  
59 - messageText: messageText,  
60 - snackPosition: snackPosition,  
61 - borderRadius: borderRadius,  
62 - margin: margin,  
63 - duration: duration,  
64 - barBlur: barBlur,  
65 - backgroundColor: backgroundColor,  
66 - icon: icon,  
67 - shouldIconPulse: shouldIconPulse,  
68 - maxWidth: maxWidth,  
69 - padding: padding,  
70 - borderColor: borderColor,  
71 - borderWidth: borderWidth,  
72 - leftBarIndicatorColor: leftBarIndicatorColor,  
73 - boxShadows: boxShadows,  
74 - backgroundGradient: backgroundGradient,  
75 - mainButton: mainButton,  
76 - onTap: onTap,  
77 - isDismissible: isDismissible,  
78 - dismissDirection: dismissDirection,  
79 - showProgressIndicator: showProgressIndicator,  
80 - progressIndicatorController: progressIndicatorController,  
81 - progressIndicatorBackgroundColor: progressIndicatorBackgroundColor,  
82 - progressIndicatorValueColor: progressIndicatorValueColor,  
83 - snackStyle: snackStyle,  
84 - forwardAnimationCurve: forwardAnimationCurve,  
85 - reverseAnimationCurve: reverseAnimationCurve,  
86 - animationDuration: animationDuration,  
87 - overlayBlur: overlayBlur,  
88 - overlayColor: overlayColor,  
89 - userInputForm: userInputForm,  
90 - );  
91 -  
92 - if (instantInit) {  
93 - getBar.show();  
94 - } else {  
95 - SchedulerBinding.instance!.addPostFrameCallback((_) {  
96 - getBar.show();  
97 - });  
98 - }  
99 - }  
100 -  
101 - Future<T?>? showSnackbar<T>(GetBar snackbar) {  
102 - return key.currentState?.push(SnackRoute<T>(snack: snackbar));  
103 - }  
104 -  
105 - void snackbar<T>(  
106 - String title,  
107 - String message, {  
108 - Color? colorText,  
109 - Duration? duration, 16 +/// It replaces the Flutter Navigator, but needs no context.
  17 +/// You can to use navigator.push(YourRoute()) rather
  18 +/// Navigator.push(context, YourRoute());
  19 +NavigatorState? get navigator => GetNavigation(Get).key.currentState;
110 20
111 - /// with instantInit = false you can put snackbar on initState  
112 - bool instantInit = true,  
113 - SnackPosition? snackPosition,  
114 - Widget? titleText,  
115 - Widget? messageText,  
116 - Widget? icon,  
117 - bool? shouldIconPulse,  
118 - double? maxWidth,  
119 - EdgeInsets? margin,  
120 - EdgeInsets? padding,  
121 - double? borderRadius,  
122 - Color? borderColor,  
123 - double? borderWidth, 21 +extension ExtensionBottomSheet on GetInterface {
  22 + Future<T?> bottomSheet<T>(
  23 + Widget bottomsheet, {
124 Color? backgroundColor, 24 Color? backgroundColor,
125 - Color? leftBarIndicatorColor,  
126 - List<BoxShadow>? boxShadows,  
127 - Gradient? backgroundGradient,  
128 - TextButton? mainButton,  
129 - OnTap? onTap,  
130 - bool? isDismissible,  
131 - bool? showProgressIndicator,  
132 - SnackDismissDirection? dismissDirection,  
133 - AnimationController? progressIndicatorController,  
134 - Color? progressIndicatorBackgroundColor,  
135 - Animation<Color>? progressIndicatorValueColor,  
136 - SnackStyle? snackStyle,  
137 - Curve? forwardAnimationCurve,  
138 - Curve? reverseAnimationCurve,  
139 - Duration? animationDuration,  
140 - double? barBlur,  
141 - double? overlayBlur,  
142 - SnackbarStatusCallback? snackbarStatus,  
143 - Color? overlayColor,  
144 - Form? userInputForm,  
145 - }) async {  
146 - final getBar = GetBar(  
147 - snackbarStatus: snackbarStatus,  
148 - titleText: titleText ??  
149 - Text(  
150 - title,  
151 - style: TextStyle(  
152 - color: colorText ?? iconColor ?? Colors.black,  
153 - fontWeight: FontWeight.w800,  
154 - fontSize: 16,  
155 - ),  
156 - ),  
157 - messageText: messageText ??  
158 - Text(  
159 - message,  
160 - style: TextStyle(  
161 - color: colorText ?? iconColor ?? Colors.black,  
162 - fontWeight: FontWeight.w300,  
163 - fontSize: 14,  
164 - ),  
165 - ),  
166 - snackPosition: snackPosition ?? SnackPosition.TOP,  
167 - borderRadius: borderRadius ?? 15,  
168 - margin: margin ?? EdgeInsets.symmetric(horizontal: 10),  
169 - duration: duration ?? Duration(seconds: 3),  
170 - barBlur: barBlur ?? 7.0,  
171 - backgroundColor: backgroundColor ?? Colors.grey.withOpacity(0.2),  
172 - icon: icon,  
173 - shouldIconPulse: shouldIconPulse ?? true,  
174 - maxWidth: maxWidth,  
175 - padding: padding ?? EdgeInsets.all(16),  
176 - borderColor: borderColor,  
177 - borderWidth: borderWidth,  
178 - leftBarIndicatorColor: leftBarIndicatorColor,  
179 - boxShadows: boxShadows,  
180 - backgroundGradient: backgroundGradient,  
181 - mainButton: mainButton,  
182 - onTap: onTap,  
183 - isDismissible: isDismissible ?? true,  
184 - dismissDirection: dismissDirection ?? SnackDismissDirection.VERTICAL,  
185 - showProgressIndicator: showProgressIndicator ?? false,  
186 - progressIndicatorController: progressIndicatorController,  
187 - progressIndicatorBackgroundColor: progressIndicatorBackgroundColor,  
188 - progressIndicatorValueColor: progressIndicatorValueColor,  
189 - snackStyle: snackStyle ?? SnackStyle.FLOATING,  
190 - forwardAnimationCurve: forwardAnimationCurve ?? Curves.easeOutCirc,  
191 - reverseAnimationCurve: reverseAnimationCurve ?? Curves.easeOutCirc,  
192 - animationDuration: animationDuration ?? Duration(seconds: 1),  
193 - overlayBlur: overlayBlur ?? 0.0,  
194 - overlayColor: overlayColor ?? Colors.transparent,  
195 - userInputForm: userInputForm);  
196 -  
197 - if (instantInit) {  
198 - showSnackbar<T>(getBar);  
199 - } else {  
200 - routing.isSnackbar = true;  
201 - SchedulerBinding.instance!.addPostFrameCallback((_) {  
202 - showSnackbar<T>(getBar);  
203 - });  
204 - }  
205 - }  
206 -}  
207 -  
208 -extension OverlayExt on GetInterface {  
209 - Future<T> showOverlay<T>({  
210 - required Future<T> Function() asyncFunction,  
211 - Color opacityColor = Colors.black,  
212 - Widget? loadingWidget,  
213 - double opacity = .5,  
214 - }) async {  
215 - final navigatorState =  
216 - Navigator.of(Get.overlayContext!, rootNavigator: false);  
217 - final overlayState = navigatorState.overlay!;  
218 -  
219 - final overlayEntryOpacity = OverlayEntry(builder: (context) {  
220 - return Opacity(  
221 - opacity: opacity,  
222 - child: Container(  
223 - color: opacityColor,  
224 - ));  
225 - });  
226 - final overlayEntryLoader = OverlayEntry(builder: (context) {  
227 - return loadingWidget ??  
228 - Center(  
229 - child: Container(  
230 - height: 90,  
231 - width: 90,  
232 - child: Text('Loading...'),  
233 - ));  
234 - });  
235 - overlayState.insert(overlayEntryOpacity);  
236 - overlayState.insert(overlayEntryLoader);  
237 -  
238 - T data; 25 + double? elevation,
  26 + bool persistent = true,
  27 + ShapeBorder? shape,
  28 + Clip? clipBehavior,
  29 + Color? barrierColor,
  30 + bool? ignoreSafeArea,
  31 + bool isScrollControlled = false,
  32 + bool useRootNavigator = false,
  33 + bool isDismissible = true,
  34 + bool enableDrag = true,
  35 + RouteSettings? settings,
  36 + Duration? enterBottomSheetDuration,
  37 + Duration? exitBottomSheetDuration,
  38 + }) {
  39 + return Navigator.of(overlayContext!, rootNavigator: useRootNavigator)
  40 + .push(GetModalBottomSheetRoute<T>(
  41 + builder: (_) => bottomsheet,
  42 + isPersistent: persistent,
  43 + // theme: Theme.of(key.currentContext, shadowThemeOnly: true),
  44 + theme: Theme.of(key.currentContext!),
  45 + isScrollControlled: isScrollControlled,
239 46
240 - try {  
241 - data = await asyncFunction();  
242 - } on Exception catch (_) {  
243 - overlayEntryLoader.remove();  
244 - overlayEntryOpacity.remove();  
245 - rethrow;  
246 - } 47 + barrierLabel: MaterialLocalizations.of(key.currentContext!)
  48 + .modalBarrierDismissLabel,
247 49
248 - overlayEntryLoader.remove();  
249 - overlayEntryOpacity.remove();  
250 - return data; 50 + backgroundColor: backgroundColor ?? Colors.transparent,
  51 + elevation: elevation,
  52 + shape: shape,
  53 + removeTop: ignoreSafeArea ?? true,
  54 + clipBehavior: clipBehavior,
  55 + isDismissible: isDismissible,
  56 + modalBarrierColor: barrierColor,
  57 + settings: settings,
  58 + enableDrag: enableDrag,
  59 + enterBottomSheetDuration:
  60 + enterBottomSheetDuration ?? const Duration(milliseconds: 250),
  61 + exitBottomSheetDuration:
  62 + exitBottomSheetDuration ?? const Duration(milliseconds: 200),
  63 + ));
251 } 64 }
252 } 65 }
253 66
@@ -378,7 +191,7 @@ extension ExtensionDialog on GetInterface { @@ -378,7 +191,7 @@ extension ExtensionDialog on GetInterface {
378 padding: EdgeInsets.symmetric(horizontal: 10, vertical: 8), 191 padding: EdgeInsets.symmetric(horizontal: 10, vertical: 8),
379 shape: RoundedRectangleBorder( 192 shape: RoundedRectangleBorder(
380 side: BorderSide( 193 side: BorderSide(
381 - color: buttonColor ?? theme.accentColor, 194 + color: buttonColor ?? theme.colorScheme.secondary,
382 width: 2, 195 width: 2,
383 style: BorderStyle.solid), 196 style: BorderStyle.solid),
384 borderRadius: BorderRadius.circular(100)), 197 borderRadius: BorderRadius.circular(100)),
@@ -389,7 +202,8 @@ extension ExtensionDialog on GetInterface { @@ -389,7 +202,8 @@ extension ExtensionDialog on GetInterface {
389 }, 202 },
390 child: Text( 203 child: Text(
391 textCancel ?? "Cancel", 204 textCancel ?? "Cancel",
392 - style: TextStyle(color: cancelTextColor ?? theme.accentColor), 205 + style: TextStyle(
  206 + color: cancelTextColor ?? theme.colorScheme.secondary),
393 ), 207 ),
394 )); 208 ));
395 } 209 }
@@ -397,113 +211,265 @@ extension ExtensionDialog on GetInterface { @@ -397,113 +211,265 @@ extension ExtensionDialog on GetInterface {
397 if (confirm != null) { 211 if (confirm != null) {
398 actions.add(confirm); 212 actions.add(confirm);
399 } else { 213 } else {
400 - if (leanConfirm) {  
401 - actions.add(TextButton(  
402 - style: TextButton.styleFrom(  
403 - tapTargetSize: MaterialTapTargetSize.shrinkWrap,  
404 - backgroundColor: buttonColor ?? theme.accentColor,  
405 - shape: RoundedRectangleBorder(  
406 - borderRadius: BorderRadius.circular(100)),  
407 - ),  
408 - child: Text(  
409 - textConfirm ?? "Ok",  
410 - style:  
411 - TextStyle(color: confirmTextColor ?? theme.backgroundColor),  
412 - ),  
413 - onPressed: () {  
414 - onConfirm?.call();  
415 - }));  
416 - } 214 + if (leanConfirm) {
  215 + actions.add(TextButton(
  216 + style: TextButton.styleFrom(
  217 + tapTargetSize: MaterialTapTargetSize.shrinkWrap,
  218 + backgroundColor: buttonColor ?? theme.colorScheme.secondary,
  219 + shape: RoundedRectangleBorder(
  220 + borderRadius: BorderRadius.circular(100)),
  221 + ),
  222 + child: Text(
  223 + textConfirm ?? "Ok",
  224 + style:
  225 + TextStyle(color: confirmTextColor ?? theme.backgroundColor),
  226 + ),
  227 + onPressed: () {
  228 + onConfirm?.call();
  229 + }));
  230 + }
  231 + }
  232 +
  233 + Widget baseAlertDialog = AlertDialog(
  234 + titlePadding: titlePadding ?? EdgeInsets.all(8),
  235 + contentPadding: contentPadding ?? EdgeInsets.all(8),
  236 +
  237 + backgroundColor: backgroundColor ?? theme.dialogBackgroundColor,
  238 + shape: RoundedRectangleBorder(
  239 + borderRadius: BorderRadius.all(Radius.circular(radius))),
  240 + title: Text(title, textAlign: TextAlign.center, style: titleStyle),
  241 + content: Column(
  242 + crossAxisAlignment: CrossAxisAlignment.center,
  243 + mainAxisSize: MainAxisSize.min,
  244 + children: [
  245 + content ??
  246 + Text(middleText,
  247 + textAlign: TextAlign.center, style: middleTextStyle),
  248 + SizedBox(height: 16),
  249 + ButtonTheme(
  250 + minWidth: 78.0,
  251 + height: 34.0,
  252 + child: Wrap(
  253 + alignment: WrapAlignment.center,
  254 + spacing: 8,
  255 + runSpacing: 8,
  256 + children: actions,
  257 + ),
  258 + )
  259 + ],
  260 + ),
  261 + // actions: actions, // ?? <Widget>[cancelButton, confirmButton],
  262 + buttonPadding: EdgeInsets.zero,
  263 + );
  264 +
  265 + return dialog<T>(
  266 + onWillPop != null
  267 + ? WillPopScope(
  268 + onWillPop: onWillPop,
  269 + child: baseAlertDialog,
  270 + )
  271 + : baseAlertDialog,
  272 + barrierDismissible: barrierDismissible,
  273 + navigatorKey: navigatorKey,
  274 + );
  275 + }
  276 +}
  277 +
  278 +extension ExtensionSnackbar on GetInterface {
  279 + void rawSnackbar({
  280 + String? title,
  281 + String? message,
  282 + Widget? titleText,
  283 + Widget? messageText,
  284 + Widget? icon,
  285 + bool instantInit = true,
  286 + bool shouldIconPulse = true,
  287 + double? maxWidth,
  288 + EdgeInsets margin = const EdgeInsets.all(0.0),
  289 + EdgeInsets padding = const EdgeInsets.all(16),
  290 + double borderRadius = 0.0,
  291 + Color? borderColor,
  292 + double borderWidth = 1.0,
  293 + Color backgroundColor = const Color(0xFF303030),
  294 + Color? leftBarIndicatorColor,
  295 + List<BoxShadow>? boxShadows,
  296 + Gradient? backgroundGradient,
  297 + Widget? mainButton,
  298 + OnTap? onTap,
  299 + Duration duration = const Duration(seconds: 3),
  300 + bool isDismissible = true,
  301 + DismissDirection? dismissDirection,
  302 + bool showProgressIndicator = false,
  303 + AnimationController? progressIndicatorController,
  304 + Color? progressIndicatorBackgroundColor,
  305 + Animation<Color>? progressIndicatorValueColor,
  306 + SnackPosition snackPosition = SnackPosition.BOTTOM,
  307 + SnackStyle snackStyle = SnackStyle.FLOATING,
  308 + Curve forwardAnimationCurve = Curves.easeOutCirc,
  309 + Curve reverseAnimationCurve = Curves.easeOutCirc,
  310 + Duration animationDuration = const Duration(seconds: 1),
  311 + SnackbarStatusCallback? snackbarStatus,
  312 + double? barBlur = 0.0,
  313 + double overlayBlur = 0.0,
  314 + Color? overlayColor,
  315 + Form? userInputForm,
  316 + }) async {
  317 + final getBar = GetSnackBar(
  318 + snackbarStatus: snackbarStatus,
  319 + title: title,
  320 + message: message,
  321 + titleText: titleText,
  322 + messageText: messageText,
  323 + snackPosition: snackPosition,
  324 + borderRadius: borderRadius,
  325 + margin: margin,
  326 + duration: duration,
  327 + barBlur: barBlur,
  328 + backgroundColor: backgroundColor,
  329 + icon: icon,
  330 + shouldIconPulse: shouldIconPulse,
  331 + maxWidth: maxWidth,
  332 + padding: padding,
  333 + borderColor: borderColor,
  334 + borderWidth: borderWidth,
  335 + leftBarIndicatorColor: leftBarIndicatorColor,
  336 + boxShadows: boxShadows,
  337 + backgroundGradient: backgroundGradient,
  338 + mainButton: mainButton,
  339 + onTap: onTap,
  340 + isDismissible: isDismissible,
  341 + dismissDirection: dismissDirection,
  342 + showProgressIndicator: showProgressIndicator,
  343 + progressIndicatorController: progressIndicatorController,
  344 + progressIndicatorBackgroundColor: progressIndicatorBackgroundColor,
  345 + progressIndicatorValueColor: progressIndicatorValueColor,
  346 + snackStyle: snackStyle,
  347 + forwardAnimationCurve: forwardAnimationCurve,
  348 + reverseAnimationCurve: reverseAnimationCurve,
  349 + animationDuration: animationDuration,
  350 + overlayBlur: overlayBlur,
  351 + overlayColor: overlayColor,
  352 + userInputForm: userInputForm,
  353 + );
  354 +
  355 + if (instantInit) {
  356 + getBar.show();
  357 + } else {
  358 + SchedulerBinding.instance!.addPostFrameCallback((_) {
  359 + getBar.show();
  360 + });
417 } 361 }
  362 + }
418 363
419 - Widget baseAlertDialog = AlertDialog(  
420 - titlePadding: titlePadding ?? EdgeInsets.all(8),  
421 - contentPadding: contentPadding ?? EdgeInsets.all(8),  
422 -  
423 - backgroundColor: backgroundColor ?? theme.dialogBackgroundColor,  
424 - shape: RoundedRectangleBorder(  
425 - borderRadius: BorderRadius.all(Radius.circular(radius))),  
426 - title: Text(title, textAlign: TextAlign.center, style: titleStyle),  
427 - content: Column(  
428 - crossAxisAlignment: CrossAxisAlignment.center,  
429 - mainAxisSize: MainAxisSize.min,  
430 - children: [  
431 - content ??  
432 - Text(middleText,  
433 - textAlign: TextAlign.center, style: middleTextStyle),  
434 - SizedBox(height: 16),  
435 - ButtonTheme(  
436 - minWidth: 78.0,  
437 - height: 34.0,  
438 - child: Wrap(  
439 - alignment: WrapAlignment.center,  
440 - spacing: 8,  
441 - runSpacing: 8,  
442 - children: actions,  
443 - ),  
444 - )  
445 - ],  
446 - ),  
447 - // actions: actions, // ?? <Widget>[cancelButton, confirmButton],  
448 - buttonPadding: EdgeInsets.zero,  
449 - );  
450 -  
451 - return dialog<T>(  
452 - onWillPop != null  
453 - ? WillPopScope(  
454 - onWillPop: onWillPop,  
455 - child: baseAlertDialog,  
456 - )  
457 - : baseAlertDialog,  
458 - barrierDismissible: barrierDismissible,  
459 - navigatorKey: navigatorKey,  
460 - ); 364 + SnackbarController showSnackbar(GetSnackBar snackbar) {
  365 + final controller = SnackbarController(snackbar);
  366 + controller.show();
  367 + return controller;
461 } 368 }
462 -}  
463 369
464 -extension ExtensionBottomSheet on GetInterface {  
465 - Future<T?> bottomSheet<T>(  
466 - Widget bottomsheet, { 370 + SnackbarController snackbar(
  371 + String title,
  372 + String message, {
  373 + Color? colorText,
  374 + Duration? duration,
  375 +
  376 + /// with instantInit = false you can put snackbar on initState
  377 + bool instantInit = true,
  378 + SnackPosition? snackPosition,
  379 + Widget? titleText,
  380 + Widget? messageText,
  381 + Widget? icon,
  382 + bool? shouldIconPulse,
  383 + double? maxWidth,
  384 + EdgeInsets? margin,
  385 + EdgeInsets? padding,
  386 + double? borderRadius,
  387 + Color? borderColor,
  388 + double? borderWidth,
467 Color? backgroundColor, 389 Color? backgroundColor,
468 - double? elevation,  
469 - bool persistent = true,  
470 - ShapeBorder? shape,  
471 - Clip? clipBehavior,  
472 - Color? barrierColor,  
473 - bool? ignoreSafeArea,  
474 - bool isScrollControlled = false,  
475 - bool useRootNavigator = false,  
476 - bool isDismissible = true,  
477 - bool enableDrag = true,  
478 - RouteSettings? settings,  
479 - Duration? enterBottomSheetDuration,  
480 - Duration? exitBottomSheetDuration, 390 + Color? leftBarIndicatorColor,
  391 + List<BoxShadow>? boxShadows,
  392 + Gradient? backgroundGradient,
  393 + TextButton? mainButton,
  394 + OnTap? onTap,
  395 + bool? isDismissible,
  396 + bool? showProgressIndicator,
  397 + DismissDirection? dismissDirection,
  398 + AnimationController? progressIndicatorController,
  399 + Color? progressIndicatorBackgroundColor,
  400 + Animation<Color>? progressIndicatorValueColor,
  401 + SnackStyle? snackStyle,
  402 + Curve? forwardAnimationCurve,
  403 + Curve? reverseAnimationCurve,
  404 + Duration? animationDuration,
  405 + double? barBlur,
  406 + double? overlayBlur,
  407 + SnackbarStatusCallback? snackbarStatus,
  408 + Color? overlayColor,
  409 + Form? userInputForm,
481 }) { 410 }) {
482 - return Navigator.of(overlayContext!, rootNavigator: useRootNavigator)  
483 - .push(GetModalBottomSheetRoute<T>(  
484 - builder: (_) => bottomsheet,  
485 - isPersistent: persistent,  
486 - // theme: Theme.of(key.currentContext, shadowThemeOnly: true),  
487 - theme: Theme.of(key.currentContext!),  
488 - isScrollControlled: isScrollControlled, 411 + final getSnackBar = GetSnackBar(
  412 + snackbarStatus: snackbarStatus,
  413 + titleText: titleText ??
  414 + Text(
  415 + title,
  416 + style: TextStyle(
  417 + color: colorText ?? iconColor ?? Colors.black,
  418 + fontWeight: FontWeight.w800,
  419 + fontSize: 16,
  420 + ),
  421 + ),
  422 + messageText: messageText ??
  423 + Text(
  424 + message,
  425 + style: TextStyle(
  426 + color: colorText ?? iconColor ?? Colors.black,
  427 + fontWeight: FontWeight.w300,
  428 + fontSize: 14,
  429 + ),
  430 + ),
  431 + snackPosition: snackPosition ?? SnackPosition.TOP,
  432 + borderRadius: borderRadius ?? 15,
  433 + margin: margin ?? EdgeInsets.symmetric(horizontal: 10),
  434 + duration: duration ?? Duration(seconds: 3),
  435 + barBlur: barBlur ?? 7.0,
  436 + backgroundColor: backgroundColor ?? Colors.grey.withOpacity(0.2),
  437 + icon: icon,
  438 + shouldIconPulse: shouldIconPulse ?? true,
  439 + maxWidth: maxWidth,
  440 + padding: padding ?? EdgeInsets.all(16),
  441 + borderColor: borderColor,
  442 + borderWidth: borderWidth,
  443 + leftBarIndicatorColor: leftBarIndicatorColor,
  444 + boxShadows: boxShadows,
  445 + backgroundGradient: backgroundGradient,
  446 + mainButton: mainButton,
  447 + onTap: onTap,
  448 + isDismissible: isDismissible ?? true,
  449 + dismissDirection: dismissDirection,
  450 + showProgressIndicator: showProgressIndicator ?? false,
  451 + progressIndicatorController: progressIndicatorController,
  452 + progressIndicatorBackgroundColor: progressIndicatorBackgroundColor,
  453 + progressIndicatorValueColor: progressIndicatorValueColor,
  454 + snackStyle: snackStyle ?? SnackStyle.FLOATING,
  455 + forwardAnimationCurve: forwardAnimationCurve ?? Curves.easeOutCirc,
  456 + reverseAnimationCurve: reverseAnimationCurve ?? Curves.easeOutCirc,
  457 + animationDuration: animationDuration ?? Duration(seconds: 1),
  458 + overlayBlur: overlayBlur ?? 0.0,
  459 + overlayColor: overlayColor ?? Colors.transparent,
  460 + userInputForm: userInputForm);
489 461
490 - barrierLabel: MaterialLocalizations.of(key.currentContext!)  
491 - .modalBarrierDismissLabel, 462 + final controller = SnackbarController(getSnackBar);
492 463
493 - backgroundColor: backgroundColor ?? Colors.transparent,  
494 - elevation: elevation,  
495 - shape: shape,  
496 - removeTop: ignoreSafeArea ?? true,  
497 - clipBehavior: clipBehavior,  
498 - isDismissible: isDismissible,  
499 - modalBarrierColor: barrierColor,  
500 - settings: settings,  
501 - enableDrag: enableDrag,  
502 - enterBottomSheetDuration:  
503 - enterBottomSheetDuration ?? const Duration(milliseconds: 250),  
504 - exitBottomSheetDuration:  
505 - exitBottomSheetDuration ?? const Duration(milliseconds: 200),  
506 - )); 464 + if (instantInit) {
  465 + controller.show();
  466 + } else {
  467 + //routing.isSnackbar = true;
  468 + SchedulerBinding.instance!.addPostFrameCallback((_) {
  469 + controller.show();
  470 + });
  471 + }
  472 + return controller;
507 } 473 }
508 } 474 }
509 475
@@ -826,11 +792,11 @@ you can only use widgets and widget functions here'''; @@ -826,11 +792,11 @@ you can only use widgets and widget functions here''';
826 792
827 /// Returns true if a Snackbar, Dialog or BottomSheet is currently OPEN 793 /// Returns true if a Snackbar, Dialog or BottomSheet is currently OPEN
828 bool get isOverlaysOpen => 794 bool get isOverlaysOpen =>
829 - (isSnackbarOpen! || isDialogOpen! || isBottomSheetOpen!); 795 + (isSnackbarOpen || isDialogOpen! || isBottomSheetOpen!);
830 796
831 /// Returns true if there is no Snackbar, Dialog or BottomSheet open 797 /// Returns true if there is no Snackbar, Dialog or BottomSheet open
832 bool get isOverlaysClosed => 798 bool get isOverlaysClosed =>
833 - (!isSnackbarOpen! && !isDialogOpen! && !isBottomSheetOpen!); 799 + (!isSnackbarOpen && !isDialogOpen! && !isBottomSheetOpen!);
834 800
835 /// **Navigation.popUntil()** shortcut.<br><br> 801 /// **Navigation.popUntil()** shortcut.<br><br>
836 /// 802 ///
@@ -851,8 +817,11 @@ you can only use widgets and widget functions here'''; @@ -851,8 +817,11 @@ you can only use widgets and widget functions here''';
851 int? id, 817 int? id,
852 }) { 818 }) {
853 if (closeOverlays && isOverlaysOpen) { 819 if (closeOverlays && isOverlaysOpen) {
  820 + if (isSnackbarOpen) {
  821 + closeAllSnackbars();
  822 + }
854 navigator?.popUntil((route) { 823 navigator?.popUntil((route) {
855 - return (isOverlaysClosed); 824 + return (!isDialogOpen! && !isBottomSheetOpen!);
856 }); 825 });
857 } 826 }
858 if (canPop) { 827 if (canPop) {
@@ -1135,7 +1104,16 @@ you can only use widgets and widget functions here'''; @@ -1135,7 +1104,16 @@ you can only use widgets and widget functions here''';
1135 String get previousRoute => routing.previous; 1104 String get previousRoute => routing.previous;
1136 1105
1137 /// check if snackbar is open 1106 /// check if snackbar is open
1138 - bool? get isSnackbarOpen => routing.isSnackbar; 1107 + bool get isSnackbarOpen =>
  1108 + SnackbarController.isSnackbarBeingShown; //routing.isSnackbar;
  1109 +
  1110 + void closeAllSnackbars() {
  1111 + SnackbarController.cancelAllSnackbars();
  1112 + }
  1113 +
  1114 + void closeCurrentSnackbar() {
  1115 + SnackbarController.closeCurrentSnackbar();
  1116 + }
1139 1117
1140 /// check if dialog is open 1118 /// check if dialog is open
1141 bool? get isDialogOpen => routing.isDialog; 1119 bool? get isDialogOpen => routing.isDialog;
@@ -1341,7 +1319,48 @@ extension NavTwoExt on GetInterface { @@ -1341,7 +1319,48 @@ extension NavTwoExt on GetInterface {
1341 } 1319 }
1342 } 1320 }
1343 1321
1344 -/// It replaces the Flutter Navigator, but needs no context.  
1345 -/// You can to use navigator.push(YourRoute()) rather  
1346 -/// Navigator.push(context, YourRoute());  
1347 -NavigatorState? get navigator => GetNavigation(Get).key.currentState; 1322 +extension OverlayExt on GetInterface {
  1323 + Future<T> showOverlay<T>({
  1324 + required Future<T> Function() asyncFunction,
  1325 + Color opacityColor = Colors.black,
  1326 + Widget? loadingWidget,
  1327 + double opacity = .5,
  1328 + }) async {
  1329 + final navigatorState =
  1330 + Navigator.of(Get.overlayContext!, rootNavigator: false);
  1331 + final overlayState = navigatorState.overlay!;
  1332 +
  1333 + final overlayEntryOpacity = OverlayEntry(builder: (context) {
  1334 + return Opacity(
  1335 + opacity: opacity,
  1336 + child: Container(
  1337 + color: opacityColor,
  1338 + ));
  1339 + });
  1340 + final overlayEntryLoader = OverlayEntry(builder: (context) {
  1341 + return loadingWidget ??
  1342 + Center(
  1343 + child: Container(
  1344 + height: 90,
  1345 + width: 90,
  1346 + child: Text('Loading...'),
  1347 + ));
  1348 + });
  1349 + overlayState.insert(overlayEntryOpacity);
  1350 + overlayState.insert(overlayEntryLoader);
  1351 +
  1352 + T data;
  1353 +
  1354 + try {
  1355 + data = await asyncFunction();
  1356 + } on Exception catch (_) {
  1357 + overlayEntryLoader.remove();
  1358 + overlayEntryOpacity.remove();
  1359 + rethrow;
  1360 + }
  1361 +
  1362 + overlayEntryLoader.remove();
  1363 + overlayEntryOpacity.remove();
  1364 + return data;
  1365 + }
  1366 +}
@@ -10,6 +10,63 @@ import '../../get_navigation.dart'; @@ -10,6 +10,63 @@ import '../../get_navigation.dart';
10 import 'root_controller.dart'; 10 import 'root_controller.dart';
11 11
12 class GetMaterialApp extends StatelessWidget { 12 class GetMaterialApp extends StatelessWidget {
  13 + final GlobalKey<NavigatorState>? navigatorKey;
  14 +
  15 + final GlobalKey<ScaffoldMessengerState>? scaffoldMessengerKey;
  16 + final Widget? home;
  17 + final Map<String, WidgetBuilder>? routes;
  18 + final String? initialRoute;
  19 + final RouteFactory? onGenerateRoute;
  20 + final InitialRouteListFactory? onGenerateInitialRoutes;
  21 + final RouteFactory? onUnknownRoute;
  22 + final List<NavigatorObserver>? navigatorObservers;
  23 + final TransitionBuilder? builder;
  24 + final String title;
  25 + final GenerateAppTitle? onGenerateTitle;
  26 + final ThemeData? theme;
  27 + final ThemeData? darkTheme;
  28 + final ThemeMode themeMode;
  29 + final CustomTransition? customTransition;
  30 + final Color? color;
  31 + final Map<String, Map<String, String>>? translationsKeys;
  32 + final Translations? translations;
  33 + final TextDirection? textDirection;
  34 + final Locale? locale;
  35 + final Locale? fallbackLocale;
  36 + final Iterable<LocalizationsDelegate<dynamic>>? localizationsDelegates;
  37 + final LocaleListResolutionCallback? localeListResolutionCallback;
  38 + final LocaleResolutionCallback? localeResolutionCallback;
  39 + final Iterable<Locale> supportedLocales;
  40 + final bool showPerformanceOverlay;
  41 + final bool checkerboardRasterCacheImages;
  42 + final bool checkerboardOffscreenLayers;
  43 + final bool showSemanticsDebugger;
  44 + final bool debugShowCheckedModeBanner;
  45 + final Map<LogicalKeySet, Intent>? shortcuts;
  46 + final ScrollBehavior? scrollBehavior;
  47 + final ThemeData? highContrastTheme;
  48 + final ThemeData? highContrastDarkTheme;
  49 + final Map<Type, Action<Intent>>? actions;
  50 + final bool debugShowMaterialGrid;
  51 + final ValueChanged<Routing?>? routingCallback;
  52 + final Transition? defaultTransition;
  53 + final bool? opaqueRoute;
  54 + final VoidCallback? onInit;
  55 + final VoidCallback? onReady;
  56 + final VoidCallback? onDispose;
  57 + final bool? enableLog;
  58 + final LogWriterCallback? logWriterCallback;
  59 + final bool? popGesture;
  60 + final SmartManagement smartManagement;
  61 + final Bindings? initialBinding;
  62 + final Duration? transitionDuration;
  63 + final bool? defaultGlobalState;
  64 + final List<GetPage>? getPages;
  65 + final GetPage? unknownRoute;
  66 + final RouteInformationProvider? routeInformationProvider;
  67 + final RouteInformationParser<Object>? routeInformationParser;
  68 + final RouterDelegate<Object>? routerDelegate;
  69 + final BackButtonDispatcher? backButtonDispatcher;
13 const GetMaterialApp({ 70 const GetMaterialApp({
14 Key? key, 71 Key? key,
15 this.navigatorKey, 72 this.navigatorKey,
@@ -72,63 +129,6 @@ class GetMaterialApp extends StatelessWidget { @@ -72,63 +129,6 @@ class GetMaterialApp extends StatelessWidget {
72 backButtonDispatcher = null, 129 backButtonDispatcher = null,
73 super(key: key); 130 super(key: key);
74 131
75 - final GlobalKey<NavigatorState>? navigatorKey;  
76 - final GlobalKey<ScaffoldMessengerState>? scaffoldMessengerKey;  
77 - final Widget? home;  
78 - final Map<String, WidgetBuilder>? routes;  
79 - final String? initialRoute;  
80 - final RouteFactory? onGenerateRoute;  
81 - final InitialRouteListFactory? onGenerateInitialRoutes;  
82 - final RouteFactory? onUnknownRoute;  
83 - final List<NavigatorObserver>? navigatorObservers;  
84 - final TransitionBuilder? builder;  
85 - final String title;  
86 - final GenerateAppTitle? onGenerateTitle;  
87 - final ThemeData? theme;  
88 - final ThemeData? darkTheme;  
89 - final ThemeMode themeMode;  
90 - final CustomTransition? customTransition;  
91 - final Color? color;  
92 - final Map<String, Map<String, String>>? translationsKeys;  
93 - final Translations? translations;  
94 - final TextDirection? textDirection;  
95 - final Locale? locale;  
96 - final Locale? fallbackLocale;  
97 - final Iterable<LocalizationsDelegate<dynamic>>? localizationsDelegates;  
98 - final LocaleListResolutionCallback? localeListResolutionCallback;  
99 - final LocaleResolutionCallback? localeResolutionCallback;  
100 - final Iterable<Locale> supportedLocales;  
101 - final bool showPerformanceOverlay;  
102 - final bool checkerboardRasterCacheImages;  
103 - final bool checkerboardOffscreenLayers;  
104 - final bool showSemanticsDebugger;  
105 - final bool debugShowCheckedModeBanner;  
106 - final Map<LogicalKeySet, Intent>? shortcuts;  
107 - final ScrollBehavior? scrollBehavior;  
108 - final ThemeData? highContrastTheme;  
109 - final ThemeData? highContrastDarkTheme;  
110 - final Map<Type, Action<Intent>>? actions;  
111 - final bool debugShowMaterialGrid;  
112 - final ValueChanged<Routing?>? routingCallback;  
113 - final Transition? defaultTransition;  
114 - final bool? opaqueRoute;  
115 - final VoidCallback? onInit;  
116 - final VoidCallback? onReady;  
117 - final VoidCallback? onDispose;  
118 - final bool? enableLog;  
119 - final LogWriterCallback? logWriterCallback;  
120 - final bool? popGesture;  
121 - final SmartManagement smartManagement;  
122 - final Bindings? initialBinding;  
123 - final Duration? transitionDuration;  
124 - final bool? defaultGlobalState;  
125 - final List<GetPage>? getPages;  
126 - final GetPage? unknownRoute;  
127 - final RouteInformationProvider? routeInformationProvider;  
128 - final RouteInformationParser<Object>? routeInformationParser;  
129 - final RouterDelegate<Object>? routerDelegate;  
130 - final BackButtonDispatcher? backButtonDispatcher;  
131 -  
132 GetMaterialApp.router({ 132 GetMaterialApp.router({
133 Key? key, 133 Key? key,
134 this.routeInformationProvider, 134 this.routeInformationProvider,
@@ -200,31 +200,6 @@ class GetMaterialApp extends StatelessWidget { @@ -200,31 +200,6 @@ class GetMaterialApp extends StatelessWidget {
200 Get.routeInformationParser = routeInformationParser; 200 Get.routeInformationParser = routeInformationParser;
201 } 201 }
202 202
203 - Route<dynamic> generator(RouteSettings settings) {  
204 - return PageRedirect(settings: settings, unknownRoute: unknownRoute).page();  
205 - }  
206 -  
207 - List<Route<dynamic>> initialRoutesGenerate(String name) {  
208 - return [  
209 - PageRedirect(  
210 - settings: RouteSettings(name: name),  
211 - unknownRoute: unknownRoute,  
212 - ).page()  
213 - ];  
214 - }  
215 -  
216 - Widget defaultBuilder(BuildContext context, Widget? child) {  
217 - return Directionality(  
218 - textDirection: textDirection ??  
219 - (rtlLanguages.contains(Get.locale?.languageCode)  
220 - ? TextDirection.rtl  
221 - : TextDirection.ltr),  
222 - child: builder == null  
223 - ? (child ?? Material())  
224 - : builder!(context, child ?? Material()),  
225 - );  
226 - }  
227 -  
228 @override 203 @override
229 Widget build(BuildContext context) => GetBuilder<GetMaterialController>( 204 Widget build(BuildContext context) => GetBuilder<GetMaterialController>(
230 init: Get.rootController, 205 init: Get.rootController,
@@ -270,7 +245,6 @@ class GetMaterialApp extends StatelessWidget { @@ -270,7 +245,6 @@ class GetMaterialApp extends StatelessWidget {
270 ? MaterialApp.router( 245 ? MaterialApp.router(
271 routerDelegate: routerDelegate!, 246 routerDelegate: routerDelegate!,
272 routeInformationParser: routeInformationParser!, 247 routeInformationParser: routeInformationParser!,
273 - scaffoldMessengerKey: scaffoldMessengerKey,  
274 backButtonDispatcher: backButtonDispatcher, 248 backButtonDispatcher: backButtonDispatcher,
275 routeInformationProvider: routeInformationProvider, 249 routeInformationProvider: routeInformationProvider,
276 key: _.unikey, 250 key: _.unikey,
@@ -283,6 +257,8 @@ class GetMaterialApp extends StatelessWidget { @@ -283,6 +257,8 @@ class GetMaterialApp extends StatelessWidget {
283 _.darkTheme ?? darkTheme ?? theme ?? ThemeData.fallback(), 257 _.darkTheme ?? darkTheme ?? theme ?? ThemeData.fallback(),
284 themeMode: _.themeMode ?? themeMode, 258 themeMode: _.themeMode ?? themeMode,
285 locale: Get.locale ?? locale, 259 locale: Get.locale ?? locale,
  260 + scaffoldMessengerKey:
  261 + scaffoldMessengerKey ?? _.scaffoldMessengerKey,
286 localizationsDelegates: localizationsDelegates, 262 localizationsDelegates: localizationsDelegates,
287 localeListResolutionCallback: localeListResolutionCallback, 263 localeListResolutionCallback: localeListResolutionCallback,
288 localeResolutionCallback: localeResolutionCallback, 264 localeResolutionCallback: localeResolutionCallback,
@@ -301,7 +277,8 @@ class GetMaterialApp extends StatelessWidget { @@ -301,7 +277,8 @@ class GetMaterialApp extends StatelessWidget {
301 navigatorKey: (navigatorKey == null 277 navigatorKey: (navigatorKey == null
302 ? Get.key 278 ? Get.key
303 : Get.addKey(navigatorKey!)), 279 : Get.addKey(navigatorKey!)),
304 - scaffoldMessengerKey: scaffoldMessengerKey, 280 + scaffoldMessengerKey:
  281 + scaffoldMessengerKey ?? _.scaffoldMessengerKey,
305 home: home, 282 home: home,
306 routes: routes ?? const <String, WidgetBuilder>{}, 283 routes: routes ?? const <String, WidgetBuilder>{},
307 initialRoute: initialRoute, 284 initialRoute: initialRoute,
@@ -343,4 +320,29 @@ class GetMaterialApp extends StatelessWidget { @@ -343,4 +320,29 @@ class GetMaterialApp extends StatelessWidget {
343 // actions: actions, 320 // actions: actions,
344 ), 321 ),
345 ); 322 );
  323 +
  324 + Widget defaultBuilder(BuildContext context, Widget? child) {
  325 + return Directionality(
  326 + textDirection: textDirection ??
  327 + (rtlLanguages.contains(Get.locale?.languageCode)
  328 + ? TextDirection.rtl
  329 + : TextDirection.ltr),
  330 + child: builder == null
  331 + ? (child ?? Material())
  332 + : builder!(context, child ?? Material()),
  333 + );
  334 + }
  335 +
  336 + Route<dynamic> generator(RouteSettings settings) {
  337 + return PageRedirect(settings: settings, unknownRoute: unknownRoute).page();
  338 + }
  339 +
  340 + List<Route<dynamic>> initialRoutesGenerate(String name) {
  341 + return [
  342 + PageRedirect(
  343 + settings: RouteSettings(name: name),
  344 + unknownRoute: unknownRoute,
  345 + ).page()
  346 + ];
  347 + }
346 } 348 }
1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
  2 +
2 import '../../../get_state_manager/get_state_manager.dart'; 3 import '../../../get_state_manager/get_state_manager.dart';
3 import '../../../get_utils/get_utils.dart'; 4 import '../../../get_utils/get_utils.dart';
4 import '../routes/custom_transition.dart'; 5 import '../routes/custom_transition.dart';
@@ -12,6 +13,8 @@ class GetMaterialController extends GetxController { @@ -12,6 +13,8 @@ class GetMaterialController extends GetxController {
12 ThemeData? darkTheme; 13 ThemeData? darkTheme;
13 ThemeMode? themeMode; 14 ThemeMode? themeMode;
14 15
  16 + final scaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
  17 +
15 bool defaultPopGesture = GetPlatform.isIOS; 18 bool defaultPopGesture = GetPlatform.isIOS;
16 bool defaultOpaqueRoute = true; 19 bool defaultOpaqueRoute = true;
17 20
@@ -31,6 +34,8 @@ class GetMaterialController extends GetxController { @@ -31,6 +34,8 @@ class GetMaterialController extends GetxController {
31 34
32 var _key = GlobalKey<NavigatorState>(debugLabel: 'Key Created by default'); 35 var _key = GlobalKey<NavigatorState>(debugLabel: 'Key Created by default');
33 36
  37 + Map<dynamic, GlobalKey<NavigatorState>> keys = {};
  38 +
34 GlobalKey<NavigatorState> get key => _key; 39 GlobalKey<NavigatorState> get key => _key;
35 40
36 GlobalKey<NavigatorState>? addKey(GlobalKey<NavigatorState> newKey) { 41 GlobalKey<NavigatorState>? addKey(GlobalKey<NavigatorState> newKey) {
@@ -38,7 +43,10 @@ class GetMaterialController extends GetxController { @@ -38,7 +43,10 @@ class GetMaterialController extends GetxController {
38 return key; 43 return key;
39 } 44 }
40 45
41 - Map<dynamic, GlobalKey<NavigatorState>> keys = {}; 46 + void restartApp() {
  47 + unikey = UniqueKey();
  48 + update();
  49 + }
42 50
43 void setTheme(ThemeData value) { 51 void setTheme(ThemeData value) {
44 if (darkTheme == null) { 52 if (darkTheme == null) {
@@ -57,9 +65,4 @@ class GetMaterialController extends GetxController { @@ -57,9 +65,4 @@ class GetMaterialController extends GetxController {
57 themeMode = value; 65 themeMode = value;
58 update(); 66 update();
59 } 67 }
60 -  
61 - void restartApp() {  
62 - unikey = UniqueKey();  
63 - update();  
64 - }  
65 } 68 }
@@ -5,37 +5,8 @@ import '../../../../instance_manager.dart'; @@ -5,37 +5,8 @@ import '../../../../instance_manager.dart';
5 import '../../../get_navigation.dart'; 5 import '../../../get_navigation.dart';
6 import '../../dialog/dialog_route.dart'; 6 import '../../dialog/dialog_route.dart';
7 import '../../router_report.dart'; 7 import '../../router_report.dart';
8 -import '../../snackbar/snack_route.dart';  
9 import '../default_route.dart'; 8 import '../default_route.dart';
10 9
11 -class Routing {  
12 - String current;  
13 - String previous;  
14 - dynamic args;  
15 - String removed;  
16 - Route<dynamic>? route;  
17 - bool? isBack;  
18 - bool? isSnackbar;  
19 - bool? isBottomSheet;  
20 - bool? isDialog;  
21 -  
22 - Routing({  
23 - this.current = '',  
24 - this.previous = '',  
25 - this.args,  
26 - this.removed = '',  
27 - this.route,  
28 - this.isBack,  
29 - this.isSnackbar,  
30 - this.isBottomSheet,  
31 - this.isDialog,  
32 - });  
33 -  
34 - void update(void fn(Routing value)) {  
35 - fn(this);  
36 - }  
37 -}  
38 -  
39 /// Extracts the name of a route based on it's instance type 10 /// Extracts the name of a route based on it's instance type
40 /// or null if not possible. 11 /// or null if not possible.
41 String? _extractRouteName(Route? route) { 12 String? _extractRouteName(Route? route) {
@@ -58,49 +29,70 @@ String? _extractRouteName(Route? route) { @@ -58,49 +29,70 @@ String? _extractRouteName(Route? route) {
58 return null; 29 return null;
59 } 30 }
60 31
61 -/// This is basically a util for rules about 'what a route is'  
62 -class _RouteData {  
63 - final bool isGetPageRoute;  
64 - final bool isSnackbar;  
65 - final bool isBottomSheet;  
66 - final bool isDialog;  
67 - final String? name;  
68 -  
69 - _RouteData({  
70 - required this.name,  
71 - required this.isGetPageRoute,  
72 - required this.isSnackbar,  
73 - required this.isBottomSheet,  
74 - required this.isDialog,  
75 - });  
76 -  
77 - factory _RouteData.ofRoute(Route? route) {  
78 - return _RouteData(  
79 - name: _extractRouteName(route),  
80 - isGetPageRoute: route is GetPageRoute,  
81 - isSnackbar: route is SnackRoute,  
82 - isDialog: route is GetDialogRoute,  
83 - isBottomSheet: route is GetModalBottomSheetRoute,  
84 - );  
85 - }  
86 -}  
87 -  
88 class GetObserver extends NavigatorObserver { 32 class GetObserver extends NavigatorObserver {
89 final Function(Routing?)? routing; 33 final Function(Routing?)? routing;
90 34
  35 + final Routing? _routeSend;
  36 +
91 GetObserver([this.routing, this._routeSend]); 37 GetObserver([this.routing, this._routeSend]);
92 38
93 - final Routing? _routeSend; 39 + @override
  40 + void didPop(Route route, Route? previousRoute) {
  41 + super.didPop(route, previousRoute);
  42 + final currentRoute = _RouteData.ofRoute(route);
  43 + final newRoute = _RouteData.ofRoute(previousRoute);
  44 +
  45 + // if (currentRoute.isSnackbar) {
  46 + // // Get.log("CLOSE SNACKBAR ${currentRoute.name}");
  47 + // Get.log("CLOSE SNACKBAR");
  48 + // } else
  49 +
  50 + if (currentRoute.isBottomSheet || currentRoute.isDialog) {
  51 + Get.log("CLOSE ${currentRoute.name}");
  52 + } else if (currentRoute.isGetPageRoute) {
  53 + Get.log("CLOSE TO ROUTE ${currentRoute.name}");
  54 + }
  55 + if (previousRoute != null) {
  56 + RouterReportManager.reportCurrentRoute(previousRoute);
  57 + }
  58 +
  59 + // Here we use a 'inverse didPush set', meaning that we use
  60 + // previous route instead of 'route' because this is
  61 + // a 'inverse push'
  62 + _routeSend?.update((value) {
  63 + // Only PageRoute is allowed to change current value
  64 + if (previousRoute is PageRoute) {
  65 + value.current = _extractRouteName(previousRoute) ?? '';
  66 + value.previous = newRoute.name ?? '';
  67 + } else if (value.previous.isNotEmpty) {
  68 + value.current = value.previous;
  69 + }
  70 +
  71 + value.args = previousRoute?.settings.arguments;
  72 + value.route = previousRoute;
  73 + value.isBack = true;
  74 + value.removed = '';
  75 + // value.isSnackbar = newRoute.isSnackbar;
  76 + value.isBottomSheet = newRoute.isBottomSheet;
  77 + value.isDialog = newRoute.isDialog;
  78 + });
  79 +
  80 + // print('currentRoute.isDialog ${currentRoute.isDialog}');
  81 +
  82 + routing?.call(_routeSend);
  83 + }
94 84
95 @override 85 @override
96 void didPush(Route route, Route? previousRoute) { 86 void didPush(Route route, Route? previousRoute) {
97 super.didPush(route, previousRoute); 87 super.didPush(route, previousRoute);
98 final newRoute = _RouteData.ofRoute(route); 88 final newRoute = _RouteData.ofRoute(route);
99 89
100 - if (newRoute.isSnackbar) {  
101 - // Get.log("OPEN SNACKBAR ${newRoute.name}");  
102 - Get.log("OPEN SNACKBAR");  
103 - } else if (newRoute.isBottomSheet || newRoute.isDialog) { 90 + // if (newRoute.isSnackbar) {
  91 + // // Get.log("OPEN SNACKBAR ${newRoute.name}");
  92 + // Get.log("OPEN SNACKBAR");
  93 + // } else
  94 +
  95 + if (newRoute.isBottomSheet || newRoute.isDialog) {
104 Get.log("OPEN ${newRoute.name}"); 96 Get.log("OPEN ${newRoute.name}");
105 } else if (newRoute.isGetPageRoute) { 97 } else if (newRoute.isGetPageRoute) {
106 Get.log("GOING TO ROUTE ${newRoute.name}"); 98 Get.log("GOING TO ROUTE ${newRoute.name}");
@@ -121,7 +113,7 @@ class GetObserver extends NavigatorObserver { @@ -121,7 +113,7 @@ class GetObserver extends NavigatorObserver {
121 value.route = route; 113 value.route = route;
122 value.isBack = false; 114 value.isBack = false;
123 value.removed = ''; 115 value.removed = '';
124 - value.isSnackbar = newRoute.isSnackbar ? true : value.isSnackbar ?? false; 116 + // value.isSnackbar = newRoute.isSnackbar ? true : value.isSnackbar ?? false;
125 value.isBottomSheet = 117 value.isBottomSheet =
126 newRoute.isBottomSheet ? true : value.isBottomSheet ?? false; 118 newRoute.isBottomSheet ? true : value.isBottomSheet ?? false;
127 value.isDialog = newRoute.isDialog ? true : value.isDialog ?? false; 119 value.isDialog = newRoute.isDialog ? true : value.isDialog ?? false;
@@ -133,46 +125,27 @@ class GetObserver extends NavigatorObserver { @@ -133,46 +125,27 @@ class GetObserver extends NavigatorObserver {
133 } 125 }
134 126
135 @override 127 @override
136 - void didPop(Route route, Route? previousRoute) {  
137 - super.didPop(route, previousRoute); 128 + void didRemove(Route route, Route? previousRoute) {
  129 + super.didRemove(route, previousRoute);
  130 + final routeName = _extractRouteName(route);
138 final currentRoute = _RouteData.ofRoute(route); 131 final currentRoute = _RouteData.ofRoute(route);
139 - final newRoute = _RouteData.ofRoute(previousRoute);  
140 132
141 - if (currentRoute.isSnackbar) {  
142 - // Get.log("CLOSE SNACKBAR ${currentRoute.name}");  
143 - Get.log("CLOSE SNACKBAR");  
144 - } else if (currentRoute.isBottomSheet || currentRoute.isDialog) {  
145 - Get.log("CLOSE ${currentRoute.name}");  
146 - } else if (currentRoute.isGetPageRoute) {  
147 - Get.log("CLOSE TO ROUTE ${currentRoute.name}");  
148 - }  
149 - if (previousRoute != null) {  
150 - RouterReportManager.reportCurrentRoute(previousRoute);  
151 - } 133 + Get.log("REMOVING ROUTE $routeName");
152 134
153 - // Here we use a 'inverse didPush set', meaning that we use  
154 - // previous route instead of 'route' because this is  
155 - // a 'inverse push'  
156 _routeSend?.update((value) { 135 _routeSend?.update((value) {
157 - // Only PageRoute is allowed to change current value  
158 - if (previousRoute is PageRoute) {  
159 - value.current = _extractRouteName(previousRoute) ?? '';  
160 - value.previous = newRoute.name ?? '';  
161 - } else if (value.previous.isNotEmpty) {  
162 - value.current = value.previous;  
163 - }  
164 -  
165 - value.args = previousRoute?.settings.arguments;  
166 value.route = previousRoute; 136 value.route = previousRoute;
167 - value.isBack = true;  
168 - value.removed = '';  
169 - value.isSnackbar = newRoute.isSnackbar;  
170 - value.isBottomSheet = newRoute.isBottomSheet;  
171 - value.isDialog = newRoute.isDialog; 137 + value.isBack = false;
  138 + value.removed = routeName ?? '';
  139 + value.previous = routeName ?? '';
  140 + // value.isSnackbar = currentRoute.isSnackbar ? false : value.isSnackbar;
  141 + value.isBottomSheet =
  142 + currentRoute.isBottomSheet ? false : value.isBottomSheet;
  143 + value.isDialog = currentRoute.isDialog ? false : value.isDialog;
172 }); 144 });
173 145
174 - // print('currentRoute.isDialog ${currentRoute.isDialog}');  
175 - 146 + if (route is GetPageRoute) {
  147 + RouterReportManager.reportRouteWillDispose(route);
  148 + }
176 routing?.call(_routeSend); 149 routing?.call(_routeSend);
177 } 150 }
178 151
@@ -201,7 +174,7 @@ class GetObserver extends NavigatorObserver { @@ -201,7 +174,7 @@ class GetObserver extends NavigatorObserver {
201 value.isBack = false; 174 value.isBack = false;
202 value.removed = ''; 175 value.removed = '';
203 value.previous = '$oldName'; 176 value.previous = '$oldName';
204 - value.isSnackbar = currentRoute.isSnackbar ? false : value.isSnackbar; 177 + // value.isSnackbar = currentRoute.isSnackbar ? false : value.isSnackbar;
205 value.isBottomSheet = 178 value.isBottomSheet =
206 currentRoute.isBottomSheet ? false : value.isBottomSheet; 179 currentRoute.isBottomSheet ? false : value.isBottomSheet;
207 value.isDialog = currentRoute.isDialog ? false : value.isDialog; 180 value.isDialog = currentRoute.isDialog ? false : value.isDialog;
@@ -212,29 +185,59 @@ class GetObserver extends NavigatorObserver { @@ -212,29 +185,59 @@ class GetObserver extends NavigatorObserver {
212 185
213 routing?.call(_routeSend); 186 routing?.call(_routeSend);
214 } 187 }
  188 +}
215 189
216 - @override  
217 - void didRemove(Route route, Route? previousRoute) {  
218 - super.didRemove(route, previousRoute);  
219 - final routeName = _extractRouteName(route);  
220 - final currentRoute = _RouteData.ofRoute(route); 190 +class Routing {
  191 + String current;
  192 + String previous;
  193 + dynamic args;
  194 + String removed;
  195 + Route<dynamic>? route;
  196 + bool? isBack;
  197 + // bool? isSnackbar;
  198 + bool? isBottomSheet;
  199 + bool? isDialog;
221 200
222 - Get.log("REMOVING ROUTE $routeName"); 201 + Routing({
  202 + this.current = '',
  203 + this.previous = '',
  204 + this.args,
  205 + this.removed = '',
  206 + this.route,
  207 + this.isBack,
  208 + // this.isSnackbar,
  209 + this.isBottomSheet,
  210 + this.isDialog,
  211 + });
223 212
224 - _routeSend?.update((value) {  
225 - value.route = previousRoute;  
226 - value.isBack = false;  
227 - value.removed = routeName ?? '';  
228 - value.previous = routeName ?? '';  
229 - value.isSnackbar = currentRoute.isSnackbar ? false : value.isSnackbar;  
230 - value.isBottomSheet =  
231 - currentRoute.isBottomSheet ? false : value.isBottomSheet;  
232 - value.isDialog = currentRoute.isDialog ? false : value.isDialog;  
233 - }); 213 + void update(void fn(Routing value)) {
  214 + fn(this);
  215 + }
  216 +}
234 217
235 - if (route is GetPageRoute) {  
236 - RouterReportManager.reportRouteWillDispose(route);  
237 - }  
238 - routing?.call(_routeSend); 218 +/// This is basically a util for rules about 'what a route is'
  219 +class _RouteData {
  220 + final bool isGetPageRoute;
  221 + //final bool isSnackbar;
  222 + final bool isBottomSheet;
  223 + final bool isDialog;
  224 + final String? name;
  225 +
  226 + _RouteData({
  227 + required this.name,
  228 + required this.isGetPageRoute,
  229 + // required this.isSnackbar,
  230 + required this.isBottomSheet,
  231 + required this.isDialog,
  232 + });
  233 +
  234 + factory _RouteData.ofRoute(Route? route) {
  235 + return _RouteData(
  236 + name: _extractRouteName(route),
  237 + isGetPageRoute: route is GetPageRoute,
  238 + // isSnackbar: route is SnackRoute,
  239 + isDialog: route is GetDialogRoute,
  240 + isBottomSheet: route is GetModalBottomSheetRoute,
  241 + );
239 } 242 }
240 } 243 }
1 import 'dart:async'; 1 import 'dart:async';
2 import 'dart:ui'; 2 import 'dart:ui';
  3 +
3 import 'package:flutter/material.dart'; 4 import 'package:flutter/material.dart';
4 import 'package:flutter/scheduler.dart'; 5 import 'package:flutter/scheduler.dart';
  6 +
5 import '../../../get_core/get_core.dart'; 7 import '../../../get_core/get_core.dart';
6 import '../../get_navigation.dart'; 8 import '../../get_navigation.dart';
7 9
  10 +typedef OnTap = void Function(GetSnackBar snack);
8 typedef SnackbarStatusCallback = void Function(SnackbarStatus? status); 11 typedef SnackbarStatusCallback = void Function(SnackbarStatus? status);
9 -typedef OnTap = void Function(GetBar snack);  
10 -  
11 -class GetBar<T extends Object> extends StatefulWidget {  
12 - GetBar({  
13 - Key? key,  
14 - this.title,  
15 - this.message,  
16 - this.titleText,  
17 - this.messageText,  
18 - this.icon,  
19 - this.shouldIconPulse = true,  
20 - this.maxWidth,  
21 - this.margin = const EdgeInsets.all(0.0),  
22 - this.padding = const EdgeInsets.all(16),  
23 - this.borderRadius = 0.0,  
24 - this.borderColor,  
25 - this.borderWidth = 1.0,  
26 - this.backgroundColor = const Color(0xFF303030),  
27 - this.leftBarIndicatorColor,  
28 - this.boxShadows,  
29 - this.backgroundGradient,  
30 - this.mainButton,  
31 - this.onTap,  
32 - this.duration,  
33 - this.isDismissible = true,  
34 - this.dismissDirection = SnackDismissDirection.VERTICAL,  
35 - this.showProgressIndicator = false,  
36 - this.progressIndicatorController,  
37 - this.progressIndicatorBackgroundColor,  
38 - this.progressIndicatorValueColor,  
39 - this.snackPosition = SnackPosition.BOTTOM,  
40 - this.snackStyle = SnackStyle.FLOATING,  
41 - this.forwardAnimationCurve = Curves.easeOutCirc,  
42 - this.reverseAnimationCurve = Curves.easeOutCirc,  
43 - this.animationDuration = const Duration(seconds: 1),  
44 - this.barBlur = 0.0,  
45 - this.overlayBlur = 0.0,  
46 - this.overlayColor = Colors.transparent,  
47 - this.userInputForm,  
48 - SnackbarStatusCallback? snackbarStatus,  
49 - }) : snackbarStatus = (snackbarStatus ?? (status) {}),  
50 - super(key: key);  
51 12
  13 +class GetSnackBar extends StatefulWidget {
52 /// A callback for you to listen to the different Snack status 14 /// A callback for you to listen to the different Snack status
53 - final SnackbarStatusCallback snackbarStatus; 15 + final SnackbarStatusCallback? snackbarStatus;
54 16
55 /// The title displayed to the user 17 /// The title displayed to the user
56 final String? title; 18 final String? title;
57 19
  20 + final DismissDirection? dismissDirection;
  21 +
58 /// The message displayed to the user. 22 /// The message displayed to the user.
59 final String? message; 23 final String? message;
60 24
@@ -150,11 +114,6 @@ class GetBar<T extends Object> extends StatefulWidget { @@ -150,11 +114,6 @@ class GetBar<T extends Object> extends StatefulWidget {
150 /// [SnackPosition.BOTTOM] is the default. 114 /// [SnackPosition.BOTTOM] is the default.
151 final SnackPosition snackPosition; 115 final SnackPosition snackPosition;
152 116
153 - /// [SnackDismissDirection.VERTICAL] by default.  
154 - /// Can also be [SnackDismissDirection.HORIZONTAL] in which case both left  
155 - /// and right dismiss are allowed.  
156 - final SnackDismissDirection dismissDirection;  
157 -  
158 /// Snack can be floating or be grounded to the edge of the screen. 117 /// Snack can be floating or be grounded to the edge of the screen.
159 /// If grounded, I do not recommend using [margin] or [borderRadius]. 118 /// If grounded, I do not recommend using [margin] or [borderRadius].
160 /// [SnackStyle.FLOATING] is the default 119 /// [SnackStyle.FLOATING] is the default
@@ -192,22 +151,73 @@ class GetBar<T extends Object> extends StatefulWidget { @@ -192,22 +151,73 @@ class GetBar<T extends Object> extends StatefulWidget {
192 /// Every other widget is ignored if this is not null. 151 /// Every other widget is ignored if this is not null.
193 final Form? userInputForm; 152 final Form? userInputForm;
194 153
  154 + const GetSnackBar({
  155 + Key? key,
  156 + this.title,
  157 + this.message,
  158 + this.titleText,
  159 + this.messageText,
  160 + this.icon,
  161 + this.shouldIconPulse = true,
  162 + this.maxWidth,
  163 + this.margin = const EdgeInsets.all(0.0),
  164 + this.padding = const EdgeInsets.all(16),
  165 + this.borderRadius = 0.0,
  166 + this.borderColor,
  167 + this.borderWidth = 1.0,
  168 + this.backgroundColor = const Color(0xFF303030),
  169 + this.leftBarIndicatorColor,
  170 + this.boxShadows,
  171 + this.backgroundGradient,
  172 + this.mainButton,
  173 + this.onTap,
  174 + this.duration,
  175 + this.isDismissible = true,
  176 + this.dismissDirection,
  177 + this.showProgressIndicator = false,
  178 + this.progressIndicatorController,
  179 + this.progressIndicatorBackgroundColor,
  180 + this.progressIndicatorValueColor,
  181 + this.snackPosition = SnackPosition.BOTTOM,
  182 + this.snackStyle = SnackStyle.FLOATING,
  183 + this.forwardAnimationCurve = Curves.easeOutCirc,
  184 + this.reverseAnimationCurve = Curves.easeOutCirc,
  185 + this.animationDuration = const Duration(seconds: 1),
  186 + this.barBlur = 0.0,
  187 + this.overlayBlur = 0.0,
  188 + this.overlayColor = Colors.transparent,
  189 + this.userInputForm,
  190 + this.snackbarStatus,
  191 + }) : super(key: key);
  192 +
  193 + @override
  194 + State createState() => _GetSnackBarState();
  195 +
195 /// Show the snack. It's call [SnackbarStatus.OPENING] state 196 /// Show the snack. It's call [SnackbarStatus.OPENING] state
196 /// followed by [SnackbarStatus.OPEN] 197 /// followed by [SnackbarStatus.OPEN]
197 - Future<T?>? show<T>() async { 198 + SnackbarController show() {
198 return Get.showSnackbar(this); 199 return Get.showSnackbar(this);
199 } 200 }
200 -  
201 - @override  
202 - State createState() {  
203 - return _GetBarState<T>();  
204 - }  
205 } 201 }
206 202
207 -class _GetBarState<K extends Object> extends State<GetBar>  
208 - with TickerProviderStateMixin {  
209 - SnackbarStatus? currentStatus; 203 +/// Indicates Status of snackbar
  204 +/// [SnackbarStatus.OPEN] Snack is fully open, [SnackbarStatus.CLOSED] Snackbar
  205 +/// has closed,
  206 +/// [SnackbarStatus.OPENING] Starts with the opening animation and ends
  207 +/// with the full
  208 +/// snackbar display, [SnackbarStatus.CLOSING] Starts with the closing animation
  209 +/// and ends
  210 +/// with the full snackbar dispose
  211 +enum SnackbarStatus { OPEN, CLOSED, OPENING, CLOSING }
  212 +
  213 +/// Indicates if snack is going to start at the [TOP] or at the [BOTTOM]
  214 +enum SnackPosition { TOP, BOTTOM }
210 215
  216 +/// Indicates if snack will be attached to the edge of the screen or not
  217 +enum SnackStyle { FLOATING, GROUNDED }
  218 +
  219 +class _GetSnackBarState extends State<GetSnackBar>
  220 + with TickerProviderStateMixin {
211 AnimationController? _fadeController; 221 AnimationController? _fadeController;
212 late Animation<double> _fadeAnimation; 222 late Animation<double> _fadeAnimation;
213 223
@@ -223,6 +233,49 @@ class _GetBarState<K extends Object> extends State<GetBar> @@ -223,6 +233,49 @@ class _GetBarState<K extends Object> extends State<GetBar>
223 FocusScopeNode? _focusNode; 233 FocusScopeNode? _focusNode;
224 late FocusAttachment _focusAttachment; 234 late FocusAttachment _focusAttachment;
225 235
  236 + final Completer<Size> _boxHeightCompleter = Completer<Size>();
  237 +
  238 + late VoidCallback _progressListener;
  239 +
  240 + late CurvedAnimation _progressAnimation;
  241 +
  242 + final _backgroundBoxKey = GlobalKey();
  243 +
  244 + @override
  245 + Widget build(BuildContext context) {
  246 + return Align(
  247 + heightFactor: 1.0,
  248 + child: Material(
  249 + color: widget.snackStyle == SnackStyle.FLOATING
  250 + ? Colors.transparent
  251 + : widget.backgroundColor,
  252 + child: SafeArea(
  253 + minimum: widget.snackPosition == SnackPosition.BOTTOM
  254 + ? EdgeInsets.only(
  255 + bottom: MediaQuery.of(context).viewInsets.bottom)
  256 + : EdgeInsets.only(top: MediaQuery.of(context).padding.top),
  257 + bottom: widget.snackPosition == SnackPosition.BOTTOM,
  258 + top: widget.snackPosition == SnackPosition.TOP,
  259 + left: false,
  260 + right: false,
  261 + child: _getSnack(),
  262 + ),
  263 + ),
  264 + );
  265 + }
  266 +
  267 + @override
  268 + void dispose() {
  269 + _fadeController?.dispose();
  270 +
  271 + widget.progressIndicatorController?.removeListener(_progressListener);
  272 + widget.progressIndicatorController?.dispose();
  273 +
  274 + _focusAttachment.detach();
  275 + _focusNode!.dispose();
  276 + super.dispose();
  277 + }
  278 +
226 @override 279 @override
227 void initState() { 280 void initState() {
228 super.initState(); 281 super.initState();
@@ -250,25 +303,31 @@ Set either a message or messageText"""); @@ -250,25 +303,31 @@ Set either a message or messageText""");
250 _focusAttachment = _focusNode!.attach(context); 303 _focusAttachment = _focusNode!.attach(context);
251 } 304 }
252 305
253 - @override  
254 - void dispose() {  
255 - _fadeController?.dispose();  
256 -  
257 - widget.progressIndicatorController?.removeListener(_progressListener);  
258 - widget.progressIndicatorController?.dispose();  
259 -  
260 - _focusAttachment.detach();  
261 - _focusNode!.dispose();  
262 - super.dispose(); 306 + Widget _buildLeftBarIndicator() {
  307 + if (widget.leftBarIndicatorColor != null) {
  308 + return FutureBuilder<Size>(
  309 + future: _boxHeightCompleter.future,
  310 + builder: (buildContext, snapshot) {
  311 + if (snapshot.hasData) {
  312 + return Container(
  313 + color: widget.leftBarIndicatorColor,
  314 + width: 5.0,
  315 + height: snapshot.data!.height,
  316 + );
  317 + } else {
  318 + return _emptyWidget;
  319 + }
  320 + },
  321 + );
  322 + } else {
  323 + return _emptyWidget;
  324 + }
263 } 325 }
264 326
265 - final Completer<Size> _boxHeightCompleter = Completer<Size>();  
266 -  
267 void _configureLeftBarFuture() { 327 void _configureLeftBarFuture() {
268 SchedulerBinding.instance!.addPostFrameCallback( 328 SchedulerBinding.instance!.addPostFrameCallback(
269 (_) { 329 (_) {
270 - final keyContext = backgroundBoxKey.currentContext;  
271 - 330 + final keyContext = _backgroundBoxKey.currentContext;
272 if (keyContext != null) { 331 if (keyContext != null) {
273 final box = keyContext.findRenderObject() as RenderBox; 332 final box = keyContext.findRenderObject() as RenderBox;
274 _boxHeightCompleter.complete(box.size); 333 _boxHeightCompleter.complete(box.size);
@@ -277,6 +336,19 @@ Set either a message or messageText"""); @@ -277,6 +336,19 @@ Set either a message or messageText""");
277 ); 336 );
278 } 337 }
279 338
  339 + void _configureProgressIndicatorAnimation() {
  340 + if (widget.showProgressIndicator &&
  341 + widget.progressIndicatorController != null) {
  342 + _progressListener = () {
  343 + setState(() {});
  344 + };
  345 + widget.progressIndicatorController!.addListener(_progressListener);
  346 +
  347 + _progressAnimation = CurvedAnimation(
  348 + curve: Curves.linear, parent: widget.progressIndicatorController!);
  349 + }
  350 + }
  351 +
280 void _configurePulseAnimation() { 352 void _configurePulseAnimation() {
281 _fadeController = 353 _fadeController =
282 AnimationController(vsync: this, duration: _pulseAnimationDuration); 354 AnimationController(vsync: this, duration: _pulseAnimationDuration);
@@ -299,95 +371,9 @@ Set either a message or messageText"""); @@ -299,95 +371,9 @@ Set either a message or messageText""");
299 _fadeController!.forward(); 371 _fadeController!.forward();
300 } 372 }
301 373
302 - late VoidCallback _progressListener;  
303 -  
304 - void _configureProgressIndicatorAnimation() {  
305 - if (widget.showProgressIndicator &&  
306 - widget.progressIndicatorController != null) {  
307 - _progressListener = () {  
308 - setState(() {});  
309 - };  
310 - widget.progressIndicatorController!.addListener(_progressListener);  
311 -  
312 - _progressAnimation = CurvedAnimation(  
313 - curve: Curves.linear, parent: widget.progressIndicatorController!);  
314 - }  
315 - }  
316 -  
317 - @override  
318 - Widget build(BuildContext context) {  
319 - return Align(  
320 - heightFactor: 1.0,  
321 - child: Material(  
322 - color: widget.snackStyle == SnackStyle.FLOATING  
323 - ? Colors.transparent  
324 - : widget.backgroundColor,  
325 - child: SafeArea(  
326 - minimum: widget.snackPosition == SnackPosition.BOTTOM  
327 - ? EdgeInsets.only(  
328 - // bottom: (GetUtils.isGreaterThan(  
329 - // MediaQuery.of(context).viewInsets.bottom,  
330 - // MediaQuery.of(context).padding.bottom)  
331 - // ? MediaQuery.of(context).viewInsets.bottom  
332 - // : MediaQuery.of(context).padding.bottom))  
333 - bottom: MediaQuery.of(context).viewInsets.bottom)  
334 - : EdgeInsets.only(top: MediaQuery.of(context).padding.top),  
335 - bottom: widget.snackPosition == SnackPosition.BOTTOM,  
336 - top: widget.snackPosition == SnackPosition.TOP,  
337 - left: false,  
338 - right: false,  
339 - child: _getSnack(),  
340 - ),  
341 - ),  
342 - );  
343 - }  
344 -  
345 - Widget _getSnack() {  
346 - Widget snack;  
347 -  
348 - if (widget.userInputForm != null) {  
349 - snack = _generateInputSnack();  
350 - } else {  
351 - snack = _generateSnack();  
352 - }  
353 -  
354 - return Stack(  
355 - children: [  
356 - FutureBuilder<Size>(  
357 - future: _boxHeightCompleter.future,  
358 - builder: (context, snapshot) {  
359 - if (snapshot.hasData) {  
360 - if (widget.barBlur == 0) {  
361 - return _emptyWidget;  
362 - }  
363 - return ClipRRect(  
364 - borderRadius: BorderRadius.circular(widget.borderRadius),  
365 - child: BackdropFilter(  
366 - filter: ImageFilter.blur(  
367 - sigmaX: widget.barBlur!, sigmaY: widget.barBlur!),  
368 - child: Container(  
369 - height: snapshot.data!.height,  
370 - width: snapshot.data!.width,  
371 - decoration: BoxDecoration(  
372 - color: Colors.transparent,  
373 - borderRadius: BorderRadius.circular(widget.borderRadius),  
374 - ),  
375 - ),  
376 - ),  
377 - );  
378 - } else {  
379 - return _emptyWidget;  
380 - }  
381 - },  
382 - ),  
383 - snack,  
384 - ],  
385 - );  
386 - }  
387 -  
388 Widget _generateInputSnack() { 374 Widget _generateInputSnack() {
389 return Container( 375 return Container(
390 - key: backgroundBoxKey, 376 + key: _backgroundBoxKey,
391 constraints: widget.maxWidth != null 377 constraints: widget.maxWidth != null
392 ? BoxConstraints(maxWidth: widget.maxWidth!) 378 ? BoxConstraints(maxWidth: widget.maxWidth!)
393 : null, 379 : null,
@@ -412,12 +398,9 @@ Set either a message or messageText"""); @@ -412,12 +398,9 @@ Set either a message or messageText""");
412 ); 398 );
413 } 399 }
414 400
415 - late CurvedAnimation _progressAnimation;  
416 - GlobalKey backgroundBoxKey = GlobalKey();  
417 -  
418 Widget _generateSnack() { 401 Widget _generateSnack() {
419 return Container( 402 return Container(
420 - key: backgroundBoxKey, 403 + key: _backgroundBoxKey,
421 constraints: widget.maxWidth != null 404 constraints: widget.maxWidth != null
422 ? BoxConstraints(maxWidth: widget.maxWidth!) 405 ? BoxConstraints(maxWidth: widget.maxWidth!)
423 : null, 406 : null,
@@ -611,25 +594,11 @@ Set either a message or messageText"""); @@ -611,25 +594,11 @@ Set either a message or messageText""");
611 } 594 }
612 } 595 }
613 596
614 - Widget _buildLeftBarIndicator() {  
615 - if (widget.leftBarIndicatorColor != null) {  
616 - return FutureBuilder<Size>(  
617 - future: _boxHeightCompleter.future,  
618 - builder: (buildContext, snapshot) {  
619 - if (snapshot.hasData) {  
620 - return Container(  
621 - color: widget.leftBarIndicatorColor,  
622 - width: 5.0,  
623 - height: snapshot.data!.height,  
624 - );  
625 - } else {  
626 - return _emptyWidget;  
627 - }  
628 - },  
629 - );  
630 - } else {  
631 - return _emptyWidget;  
632 - } 597 + Text _getDefaultNotificationText() {
  598 + return Text(
  599 + widget.message ?? "",
  600 + style: TextStyle(fontSize: 14.0, color: Colors.white),
  601 + );
633 } 602 }
634 603
635 Widget? _getIcon() { 604 Widget? _getIcon() {
@@ -645,6 +614,53 @@ Set either a message or messageText"""); @@ -645,6 +614,53 @@ Set either a message or messageText""");
645 } 614 }
646 } 615 }
647 616
  617 + Widget? _getMainActionButton() {
  618 + return widget.mainButton;
  619 + }
  620 +
  621 + Widget _getSnack() {
  622 + Widget snack;
  623 +
  624 + if (widget.userInputForm != null) {
  625 + snack = _generateInputSnack();
  626 + } else {
  627 + snack = _generateSnack();
  628 + }
  629 +
  630 + return Stack(
  631 + children: [
  632 + FutureBuilder<Size>(
  633 + future: _boxHeightCompleter.future,
  634 + builder: (context, snapshot) {
  635 + if (snapshot.hasData) {
  636 + if (widget.barBlur == 0) {
  637 + return _emptyWidget;
  638 + }
  639 + return ClipRRect(
  640 + borderRadius: BorderRadius.circular(widget.borderRadius),
  641 + child: BackdropFilter(
  642 + filter: ImageFilter.blur(
  643 + sigmaX: widget.barBlur!, sigmaY: widget.barBlur!),
  644 + child: Container(
  645 + height: snapshot.data!.height,
  646 + width: snapshot.data!.width,
  647 + decoration: BoxDecoration(
  648 + color: Colors.transparent,
  649 + borderRadius: BorderRadius.circular(widget.borderRadius),
  650 + ),
  651 + ),
  652 + ),
  653 + );
  654 + } else {
  655 + return _emptyWidget;
  656 + }
  657 + },
  658 + ),
  659 + snack,
  660 + ],
  661 + );
  662 + }
  663 +
648 Widget _getTitleText() { 664 Widget _getTitleText() {
649 return widget.titleText ?? 665 return widget.titleText ??
650 Text( 666 Text(
@@ -653,36 +669,4 @@ Set either a message or messageText"""); @@ -653,36 +669,4 @@ Set either a message or messageText""");
653 fontSize: 16.0, color: Colors.white, fontWeight: FontWeight.bold), 669 fontSize: 16.0, color: Colors.white, fontWeight: FontWeight.bold),
654 ); 670 );
655 } 671 }
656 -  
657 - Text _getDefaultNotificationText() {  
658 - return Text(  
659 - widget.message ?? "",  
660 - style: TextStyle(fontSize: 14.0, color: Colors.white),  
661 - );  
662 - }  
663 -  
664 - Widget? _getMainActionButton() {  
665 - return widget.mainButton;  
666 - }  
667 } 672 }
668 -  
669 -/// Indicates if snack is going to start at the [TOP] or at the [BOTTOM]  
670 -enum SnackPosition { TOP, BOTTOM }  
671 -  
672 -/// Indicates if snack will be attached to the edge of the screen or not  
673 -enum SnackStyle { FLOATING, GROUNDED }  
674 -  
675 -/// Indicates the direction in which it is possible to dismiss  
676 -/// If vertical, dismiss up will be allowed if [SnackPosition.TOP]  
677 -/// If vertical, dismiss down will be allowed if [SnackPosition.BOTTOM]  
678 -enum SnackDismissDirection { HORIZONTAL, VERTICAL }  
679 -  
680 -/// Indicates Status of snackbar  
681 -/// [SnackbarStatus.OPEN] Snack is fully open, [SnackbarStatus.CLOSED] Snackbar  
682 -/// has closed,  
683 -/// [SnackbarStatus.OPENING] Starts with the opening animation and ends  
684 -/// with the full  
685 -/// snackbar display, [SnackbarStatus.CLOSING] Starts with the closing animation  
686 -/// and ends  
687 -/// with the full snackbar dispose  
688 -enum SnackbarStatus { OPEN, CLOSED, OPENING, CLOSING }  
1 -import 'dart:async';  
2 -import 'dart:ui';  
3 -import 'package:flutter/widgets.dart';  
4 -import '../../../get_core/get_core.dart';  
5 -import '../../get_navigation.dart';  
6 -import 'snack.dart';  
7 -  
8 -class SnackRoute<T> extends OverlayRoute<T> {  
9 - late Animation<double> _filterBlurAnimation;  
10 - late Animation<Color?> _filterColorAnimation;  
11 -  
12 - SnackRoute({  
13 - required this.snack,  
14 - RouteSettings? settings,  
15 - }) : super(settings: settings) {  
16 - _builder = Builder(builder: (_) {  
17 - return GestureDetector(  
18 - child: snack,  
19 - onTap: snack.onTap != null ? () => snack.onTap!(snack) : null,  
20 - );  
21 - });  
22 -  
23 - _configureAlignment(snack.snackPosition);  
24 - _snackbarStatus = snack.snackbarStatus;  
25 - }  
26 -  
27 - _configureAlignment(SnackPosition snackPosition) {  
28 - switch (snack.snackPosition) {  
29 - case SnackPosition.TOP:  
30 - {  
31 - _initialAlignment = Alignment(-1.0, -2.0);  
32 - _endAlignment = Alignment(-1.0, -1.0);  
33 - break;  
34 - }  
35 - case SnackPosition.BOTTOM:  
36 - {  
37 - _initialAlignment = Alignment(-1.0, 2.0);  
38 - _endAlignment = Alignment(-1.0, 1.0);  
39 - break;  
40 - }  
41 - }  
42 - }  
43 -  
44 - GetBar snack;  
45 - Builder? _builder;  
46 -  
47 - final Completer<T> _transitionCompleter = Completer<T>();  
48 -  
49 - late SnackbarStatusCallback _snackbarStatus;  
50 - Alignment? _initialAlignment;  
51 - Alignment? _endAlignment;  
52 - bool _wasDismissedBySwipe = false;  
53 - bool _onTappedDismiss = false;  
54 -  
55 - Timer? _timer;  
56 -  
57 - bool get opaque => false;  
58 -  
59 - @override  
60 - Iterable<OverlayEntry> createOverlayEntries() {  
61 - return <OverlayEntry>[  
62 - if (snack.overlayBlur > 0.0) ...[  
63 - OverlayEntry(  
64 - builder: (context) {  
65 - return GestureDetector(  
66 - onTap: () {  
67 - if (snack.isDismissible && !_onTappedDismiss) {  
68 - _onTappedDismiss = true;  
69 - Get.back();  
70 - }  
71 - },  
72 - child: AnimatedBuilder(  
73 - animation: _filterBlurAnimation,  
74 - builder: (context, child) {  
75 - return BackdropFilter(  
76 - filter: ImageFilter.blur(  
77 - sigmaX: _filterBlurAnimation.value,  
78 - sigmaY: _filterBlurAnimation.value),  
79 - child: Container(  
80 - constraints: BoxConstraints.expand(),  
81 - color: _filterColorAnimation.value,  
82 - ),  
83 - );  
84 - },  
85 - ),  
86 - );  
87 - },  
88 - maintainState: false,  
89 - opaque: opaque,  
90 - ),  
91 - ],  
92 - OverlayEntry(  
93 - builder: (context) {  
94 - final Widget annotatedChild = Semantics(  
95 - child: AlignTransition(  
96 - alignment: _animation!,  
97 - child: snack.isDismissible  
98 - ? _getDismissibleSnack(_builder)  
99 - : _getSnack(),  
100 - ),  
101 - focused: false,  
102 - container: true,  
103 - explicitChildNodes: true,  
104 - );  
105 - return annotatedChild;  
106 - },  
107 - maintainState: false,  
108 - opaque: opaque,  
109 - ),  
110 - ];  
111 - }  
112 -  
113 - String dismissibleKeyGen = "";  
114 -  
115 - Widget _getDismissibleSnack(Widget? child) {  
116 - return Dismissible(  
117 - direction: _getDismissDirection(),  
118 - resizeDuration: null,  
119 - confirmDismiss: (_) {  
120 - if (currentStatus == SnackbarStatus.OPENING ||  
121 - currentStatus == SnackbarStatus.CLOSING) {  
122 - return Future.value(false);  
123 - }  
124 - return Future.value(true);  
125 - },  
126 - key: Key(dismissibleKeyGen),  
127 - onDismissed: (_) {  
128 - dismissibleKeyGen += "1";  
129 - _cancelTimer();  
130 - _wasDismissedBySwipe = true;  
131 -  
132 - if (isCurrent) {  
133 - navigator!.pop();  
134 - } else {  
135 - navigator!.removeRoute(this);  
136 - }  
137 - },  
138 - child: _getSnack(),  
139 - );  
140 - }  
141 -  
142 - Widget _getSnack() {  
143 - return Container(  
144 - margin: snack.margin,  
145 - child: _builder,  
146 - );  
147 - }  
148 -  
149 - DismissDirection _getDismissDirection() {  
150 - if (snack.dismissDirection == SnackDismissDirection.HORIZONTAL) {  
151 - return DismissDirection.horizontal;  
152 - } else {  
153 - if (snack.snackPosition == SnackPosition.TOP) {  
154 - return DismissDirection.up;  
155 - }  
156 - return DismissDirection.down;  
157 - }  
158 - }  
159 -  
160 - @override  
161 - bool get finishedWhenPopped =>  
162 - _controller!.status == AnimationStatus.dismissed;  
163 -  
164 - /// The animation that drives the route's transition and the previous route's  
165 - /// forward transition.  
166 - Animation<Alignment>? _animation;  
167 -  
168 - /// The animation controller that the route uses to drive the transitions.  
169 - ///  
170 - /// The animation itself is exposed by the [animation] property.  
171 - AnimationController? _controller;  
172 -  
173 - /// Called to create the animation controller that will drive the transitions  
174 - /// to this route from the previous one, and back to the previous route  
175 - /// from this one.  
176 - AnimationController createAnimationController() {  
177 - assert(!_transitionCompleter.isCompleted,  
178 - 'Cannot reuse a $runtimeType after disposing it.');  
179 - assert(snack.animationDuration >= Duration.zero);  
180 - return AnimationController(  
181 - duration: snack.animationDuration,  
182 - debugLabel: debugLabel,  
183 - vsync: navigator!,  
184 - );  
185 - }  
186 -  
187 - /// Called to create the animation that exposes the current progress of  
188 - /// the transition controlled by the animation controller created by  
189 - /// `createAnimationController()`.  
190 - Animation<Alignment> createAnimation() {  
191 - assert(!_transitionCompleter.isCompleted,  
192 - 'Cannot reuse a $runtimeType after disposing it.');  
193 - assert(_controller != null);  
194 - return AlignmentTween(begin: _initialAlignment, end: _endAlignment).animate(  
195 - CurvedAnimation(  
196 - parent: _controller!,  
197 - curve: snack.forwardAnimationCurve,  
198 - reverseCurve: snack.reverseAnimationCurve,  
199 - ),  
200 - );  
201 - }  
202 -  
203 - Animation<double> createBlurFilterAnimation() {  
204 - return Tween(begin: 0.0, end: snack.overlayBlur).animate(  
205 - CurvedAnimation(  
206 - parent: _controller!,  
207 - curve: Interval(  
208 - 0.0,  
209 - 0.35,  
210 - curve: Curves.easeInOutCirc,  
211 - ),  
212 - ),  
213 - );  
214 - }  
215 -  
216 - Animation<Color?> createColorFilterAnimation() {  
217 - return ColorTween(begin: Color(0x00000000), end: snack.overlayColor)  
218 - .animate(  
219 - CurvedAnimation(  
220 - parent: _controller!,  
221 - curve: Interval(  
222 - 0.0,  
223 - 0.35,  
224 - curve: Curves.easeInOutCirc,  
225 - ),  
226 - ),  
227 - );  
228 - }  
229 -  
230 - T? _result;  
231 - SnackbarStatus? currentStatus;  
232 -  
233 - void _handleStatusChanged(AnimationStatus status) {  
234 - switch (status) {  
235 - case AnimationStatus.completed:  
236 - currentStatus = SnackbarStatus.OPEN;  
237 - _snackbarStatus(currentStatus);  
238 - if (overlayEntries.isNotEmpty) overlayEntries.first.opaque = opaque;  
239 -  
240 - break;  
241 - case AnimationStatus.forward:  
242 - currentStatus = SnackbarStatus.OPENING;  
243 - _snackbarStatus(currentStatus);  
244 - break;  
245 - case AnimationStatus.reverse:  
246 - currentStatus = SnackbarStatus.CLOSING;  
247 - _snackbarStatus(currentStatus);  
248 - if (overlayEntries.isNotEmpty) overlayEntries.first.opaque = false;  
249 - break;  
250 - case AnimationStatus.dismissed:  
251 - assert(!overlayEntries.first.opaque);  
252 - // We might still be the current route if a subclass is controlling the  
253 - // the transition and hits the dismissed status. For example, the iOS  
254 - // back gesture drives this animation to the dismissed status before  
255 - // popping the navigator.  
256 - currentStatus = SnackbarStatus.CLOSED;  
257 - _snackbarStatus(currentStatus);  
258 -  
259 - if (!isCurrent) {  
260 - navigator!.finalizeRoute(this);  
261 - // assert(overlayEntries.isEmpty);  
262 - }  
263 - break;  
264 - }  
265 - changedInternalState();  
266 - }  
267 -  
268 - @override  
269 - void install() {  
270 - assert(!_transitionCompleter.isCompleted,  
271 - 'Cannot install a $runtimeType after disposing it.');  
272 - _controller = createAnimationController();  
273 - assert(_controller != null,  
274 - '$runtimeType.createAnimationController() returned null.');  
275 - _filterBlurAnimation = createBlurFilterAnimation();  
276 - _filterColorAnimation = createColorFilterAnimation();  
277 - _animation = createAnimation();  
278 - assert(_animation != null, '$runtimeType.createAnimation() returned null.');  
279 - super.install();  
280 - }  
281 -  
282 - @override  
283 - TickerFuture didPush() {  
284 - super.didPush();  
285 - assert(  
286 - _controller != null,  
287 - // ignore: lines_longer_than_80_chars  
288 - '$runtimeType.didPush called before calling install() or after calling dispose().',  
289 - );  
290 - assert(  
291 - !_transitionCompleter.isCompleted,  
292 - 'Cannot reuse a $runtimeType after disposing it.',  
293 - );  
294 - _animation!.addStatusListener(_handleStatusChanged);  
295 - _configureTimer();  
296 - return _controller!.forward();  
297 - }  
298 -  
299 - @override  
300 - void didReplace(Route<dynamic>? oldRoute) {  
301 - assert(  
302 - _controller != null,  
303 - // ignore: lines_longer_than_80_chars  
304 - '$runtimeType.didReplace called before calling install() or after calling dispose().',  
305 - );  
306 - assert(  
307 - !_transitionCompleter.isCompleted,  
308 - 'Cannot reuse a $runtimeType after disposing it.',  
309 - );  
310 -  
311 - if (oldRoute is SnackRoute) {  
312 - _controller!.value = oldRoute._controller!.value;  
313 - }  
314 - _animation!.addStatusListener(_handleStatusChanged);  
315 - super.didReplace(oldRoute);  
316 - }  
317 -  
318 - @override  
319 - bool didPop(T? result) {  
320 - assert(  
321 - _controller != null,  
322 - // ignore: lines_longer_than_80_chars  
323 - '$runtimeType.didPop called before calling install() or after calling dispose().',  
324 - );  
325 - assert(  
326 - !_transitionCompleter.isCompleted,  
327 - 'Cannot reuse a $runtimeType after disposing it.',  
328 - );  
329 -  
330 - _result = result;  
331 - _cancelTimer();  
332 -  
333 - if (_wasDismissedBySwipe) {  
334 - Timer(Duration(milliseconds: 200), () {  
335 - _controller!.reset();  
336 - });  
337 -  
338 - _wasDismissedBySwipe = false;  
339 - } else {  
340 - _controller!.reverse();  
341 - }  
342 -  
343 - return super.didPop(result);  
344 - }  
345 -  
346 - void _configureTimer() {  
347 - if (snack.duration != null) {  
348 - if (_timer != null && _timer!.isActive) {  
349 - _timer!.cancel();  
350 - }  
351 - _timer = Timer(snack.duration!, () {  
352 - if (isCurrent) {  
353 - navigator!.pop();  
354 - } else if (isActive) {  
355 - navigator!.removeRoute(this);  
356 - }  
357 - });  
358 - } else {  
359 - if (_timer != null) {  
360 - _timer!.cancel();  
361 - }  
362 - }  
363 - }  
364 -  
365 - void _cancelTimer() {  
366 - if (_timer != null && _timer!.isActive) {  
367 - _timer!.cancel();  
368 - }  
369 - }  
370 -  
371 - /// Whether this route can perform a transition to the given route.  
372 - /// Subclasses can override this method to restrict the set of routes they  
373 - /// need to coordinate transitions with.  
374 - bool canTransitionTo(SnackRoute<dynamic> nextRoute) => true;  
375 -  
376 - /// Whether this route can perform a transition from the given route.  
377 - ///  
378 - /// Subclasses can override this method to restrict the set of routes they  
379 - /// need to coordinate transitions with.  
380 - bool canTransitionFrom(SnackRoute<dynamic> previousRoute) => true;  
381 -  
382 - @override  
383 - void dispose() {  
384 - assert(!_transitionCompleter.isCompleted,  
385 - 'Cannot dispose a $runtimeType twice.');  
386 - _controller?.dispose();  
387 - _transitionCompleter.complete(_result);  
388 - super.dispose();  
389 - }  
390 -  
391 - /// A short description of this route useful for debugging.  
392 - String get debugLabel => '$runtimeType';  
393 -}  
  1 +import 'dart:async';
  2 +import 'dart:ui';
  3 +
  4 +import 'package:flutter/material.dart';
  5 +
  6 +import '../../../get.dart';
  7 +
  8 +class SnackbarController {
  9 + static final _snackBarQueue = _SnackBarQueue();
  10 + static bool get isSnackbarBeingShown => _snackBarQueue.isJobInProgress;
  11 +
  12 + late Animation<double> _filterBlurAnimation;
  13 + late Animation<Color?> _filterColorAnimation;
  14 +
  15 + final GetSnackBar snack;
  16 + final _transitionCompleter = Completer<SnackbarController>();
  17 +
  18 + late SnackbarStatusCallback? _snackbarStatus;
  19 + late final Alignment? _initialAlignment;
  20 + late final Alignment? _endAlignment;
  21 +
  22 + bool _wasDismissedBySwipe = false;
  23 +
  24 + bool _onTappedDismiss = false;
  25 +
  26 + Timer? _timer;
  27 +
  28 + /// The animation that drives the route's transition and the previous route's
  29 + /// forward transition.
  30 + late final Animation<Alignment> _animation;
  31 +
  32 + /// The animation controller that the route uses to drive the transitions.
  33 + ///
  34 + /// The animation itself is exposed by the [animation] property.
  35 + late final AnimationController _controller;
  36 +
  37 + SnackbarStatus? _currentStatus;
  38 +
  39 + final _overlayEntries = <OverlayEntry>[];
  40 +
  41 + OverlayState? _overlayState;
  42 +
  43 + SnackbarController(this.snack);
  44 +
  45 + Future<SnackbarController> get future => _transitionCompleter.future;
  46 +
  47 + Future<void> close() async {
  48 + _removeEntry();
  49 + await future;
  50 + }
  51 +
  52 + Future<void> show() {
  53 + return _snackBarQueue.addJob(this);
  54 + }
  55 +
  56 + void _cancelTimer() {
  57 + if (_timer != null && _timer!.isActive) {
  58 + _timer!.cancel();
  59 + }
  60 + }
  61 +
  62 + // ignore: avoid_returning_this
  63 + void _configureAlignment(SnackPosition snackPosition) {
  64 + switch (snack.snackPosition) {
  65 + case SnackPosition.TOP:
  66 + {
  67 + _initialAlignment = const Alignment(-1.0, -2.0);
  68 + _endAlignment = const Alignment(-1.0, -1.0);
  69 + break;
  70 + }
  71 + case SnackPosition.BOTTOM:
  72 + {
  73 + _initialAlignment = const Alignment(-1.0, 2.0);
  74 + _endAlignment = const Alignment(-1.0, 1.0);
  75 + break;
  76 + }
  77 + }
  78 + }
  79 +
  80 + void _configureOverlay() {
  81 + _overlayState = Overlay.of(Get.overlayContext!);
  82 + _overlayEntries.clear();
  83 + _overlayEntries.addAll(_createOverlayEntries(_getBodyWidget()));
  84 + _overlayState!.insertAll(_overlayEntries);
  85 + _configureSnackBarDisplay();
  86 + }
  87 +
  88 + void _configureSnackBarDisplay() {
  89 + assert(!_transitionCompleter.isCompleted,
  90 + 'Cannot configure a snackbar after disposing it.');
  91 + _controller = _createAnimationController();
  92 + _configureAlignment(snack.snackPosition);
  93 + _snackbarStatus = snack.snackbarStatus;
  94 + _filterBlurAnimation = _createBlurFilterAnimation();
  95 + _filterColorAnimation = _createColorOverlayColor();
  96 + _animation = _createAnimation();
  97 + _animation.addStatusListener(_handleStatusChanged);
  98 + _configureTimer();
  99 + _controller.forward();
  100 + }
  101 +
  102 + void _configureTimer() {
  103 + if (snack.duration != null) {
  104 + if (_timer != null && _timer!.isActive) {
  105 + _timer!.cancel();
  106 + }
  107 + _timer = Timer(snack.duration!, _removeEntry);
  108 + } else {
  109 + if (_timer != null) {
  110 + _timer!.cancel();
  111 + }
  112 + }
  113 + }
  114 +
  115 + /// Called to create the animation that exposes the current progress of
  116 + /// the transition controlled by the animation controller created by
  117 + /// `createAnimationController()`.
  118 + Animation<Alignment> _createAnimation() {
  119 + assert(!_transitionCompleter.isCompleted,
  120 + 'Cannot create a animation from a disposed snackbar');
  121 + return AlignmentTween(begin: _initialAlignment, end: _endAlignment).animate(
  122 + CurvedAnimation(
  123 + parent: _controller,
  124 + curve: snack.forwardAnimationCurve,
  125 + reverseCurve: snack.reverseAnimationCurve,
  126 + ),
  127 + );
  128 + }
  129 +
  130 + /// Called to create the animation controller that will drive the transitions
  131 + /// to this route from the previous one, and back to the previous route
  132 + /// from this one.
  133 + AnimationController _createAnimationController() {
  134 + assert(!_transitionCompleter.isCompleted,
  135 + 'Cannot create a animationController from a disposed snackbar');
  136 + assert(snack.animationDuration >= Duration.zero);
  137 + return AnimationController(
  138 + duration: snack.animationDuration,
  139 + debugLabel: '$runtimeType',
  140 + vsync: navigator!,
  141 + );
  142 + }
  143 +
  144 + Animation<double> _createBlurFilterAnimation() {
  145 + return Tween(begin: 0.0, end: snack.overlayBlur).animate(
  146 + CurvedAnimation(
  147 + parent: _controller,
  148 + curve: const Interval(
  149 + 0.0,
  150 + 0.35,
  151 + curve: Curves.easeInOutCirc,
  152 + ),
  153 + ),
  154 + );
  155 + }
  156 +
  157 + Animation<Color?> _createColorOverlayColor() {
  158 + return ColorTween(begin: const Color(0x00000000), end: snack.overlayColor)
  159 + .animate(
  160 + CurvedAnimation(
  161 + parent: _controller,
  162 + curve: const Interval(
  163 + 0.0,
  164 + 0.35,
  165 + curve: Curves.easeInOutCirc,
  166 + ),
  167 + ),
  168 + );
  169 + }
  170 +
  171 + Iterable<OverlayEntry> _createOverlayEntries(Widget child) {
  172 + return <OverlayEntry>[
  173 + if (snack.overlayBlur > 0.0) ...[
  174 + OverlayEntry(
  175 + builder: (context) => GestureDetector(
  176 + onTap: () {
  177 + if (snack.isDismissible && !_onTappedDismiss) {
  178 + _onTappedDismiss = true;
  179 + Get.back();
  180 + }
  181 + },
  182 + child: AnimatedBuilder(
  183 + animation: _filterBlurAnimation,
  184 + builder: (context, child) {
  185 + return BackdropFilter(
  186 + filter: ImageFilter.blur(
  187 + sigmaX: _filterBlurAnimation.value,
  188 + sigmaY: _filterBlurAnimation.value),
  189 + child: Container(
  190 + constraints: const BoxConstraints.expand(),
  191 + color: _filterColorAnimation.value,
  192 + ),
  193 + );
  194 + },
  195 + ),
  196 + ),
  197 + maintainState: false,
  198 + opaque: false,
  199 + ),
  200 + ],
  201 + OverlayEntry(
  202 + builder: (context) => Semantics(
  203 + child: AlignTransition(
  204 + alignment: _animation,
  205 + child: snack.isDismissible
  206 + ? _getDismissibleSnack(child)
  207 + : _getSnackbarContainer(child),
  208 + ),
  209 + focused: false,
  210 + container: true,
  211 + explicitChildNodes: true,
  212 + ),
  213 + maintainState: false,
  214 + opaque: false,
  215 + ),
  216 + ];
  217 + }
  218 +
  219 + Widget _getBodyWidget() {
  220 + return Builder(builder: (_) {
  221 + return GestureDetector(
  222 + child: snack,
  223 + onTap: snack.onTap != null ? () => snack.onTap?.call(snack) : null,
  224 + );
  225 + });
  226 + }
  227 +
  228 + DismissDirection _getDefaultDismissDirection() {
  229 + if (snack.snackPosition == SnackPosition.TOP) {
  230 + return DismissDirection.up;
  231 + }
  232 + return DismissDirection.down;
  233 + }
  234 +
  235 + Widget _getDismissibleSnack(Widget child) {
  236 + return Dismissible(
  237 + direction: snack.dismissDirection ?? _getDefaultDismissDirection(),
  238 + resizeDuration: null,
  239 + confirmDismiss: (_) {
  240 + if (_currentStatus == SnackbarStatus.OPENING ||
  241 + _currentStatus == SnackbarStatus.CLOSING) {
  242 + return Future.value(false);
  243 + }
  244 + return Future.value(true);
  245 + },
  246 + key: const Key('dismissible'),
  247 + onDismissed: (_) {
  248 + _onDismiss();
  249 + },
  250 + child: _getSnackbarContainer(child),
  251 + );
  252 + }
  253 +
  254 + Widget _getSnackbarContainer(Widget child) {
  255 + return Container(
  256 + margin: snack.margin,
  257 + child: child,
  258 + );
  259 + }
  260 +
  261 + void _handleStatusChanged(AnimationStatus status) {
  262 + switch (status) {
  263 + case AnimationStatus.completed:
  264 + _currentStatus = SnackbarStatus.OPEN;
  265 + _snackbarStatus?.call(_currentStatus);
  266 + if (_overlayEntries.isNotEmpty) _overlayEntries.first.opaque = false;
  267 +
  268 + break;
  269 + case AnimationStatus.forward:
  270 + _currentStatus = SnackbarStatus.OPENING;
  271 + _snackbarStatus?.call(_currentStatus);
  272 + break;
  273 + case AnimationStatus.reverse:
  274 + _currentStatus = SnackbarStatus.CLOSING;
  275 + _snackbarStatus?.call(_currentStatus);
  276 + if (_overlayEntries.isNotEmpty) _overlayEntries.first.opaque = false;
  277 + break;
  278 + case AnimationStatus.dismissed:
  279 + assert(!_overlayEntries.first.opaque);
  280 + _currentStatus = SnackbarStatus.CLOSED;
  281 + _snackbarStatus?.call(_currentStatus);
  282 + _removeOverlay();
  283 + break;
  284 + }
  285 + }
  286 +
  287 + void _onDismiss() {
  288 + _cancelTimer();
  289 + _wasDismissedBySwipe = true;
  290 + _removeEntry();
  291 + }
  292 +
  293 + void _removeEntry() {
  294 + assert(
  295 + !_transitionCompleter.isCompleted,
  296 + 'Cannot remove entry from a disposed snackbar',
  297 + );
  298 +
  299 + _cancelTimer();
  300 +
  301 + if (_wasDismissedBySwipe) {
  302 + Timer(const Duration(milliseconds: 200), _controller.reset);
  303 +
  304 + _wasDismissedBySwipe = false;
  305 + } else {
  306 + _controller.reverse();
  307 + }
  308 + }
  309 +
  310 + void _removeOverlay() {
  311 + for (var element in _overlayEntries) {
  312 + element.remove();
  313 + }
  314 +
  315 + assert(!_transitionCompleter.isCompleted, 'Cannot remove overlay twice.');
  316 + _controller.dispose();
  317 + _overlayEntries.clear();
  318 + _transitionCompleter.complete(this);
  319 + }
  320 +
  321 + Future<void> _show() {
  322 + _configureOverlay();
  323 + return future;
  324 + }
  325 +
  326 + static void cancelAllSnackbars() {
  327 + _snackBarQueue.cancelAllJobs();
  328 + }
  329 +
  330 + static void closeCurrentSnackbar() {
  331 + _snackBarQueue.closeCurrentJob();
  332 + }
  333 +}
  334 +
  335 +class _SnackBarQueue {
  336 + final _queue = GetQueue();
  337 +
  338 + bool _isJobInProgress = false;
  339 +
  340 + SnackbarController? _currentSnackbar;
  341 +
  342 + bool get isJobInProgress => _isJobInProgress;
  343 +
  344 + Future<void> addJob(SnackbarController job) async {
  345 + _isJobInProgress = true;
  346 + _currentSnackbar = job;
  347 + final data = await _queue.add(job._show);
  348 + _isJobInProgress = false;
  349 + _currentSnackbar = null;
  350 + return data;
  351 + }
  352 +
  353 + void cancelAllJobs() {
  354 + _currentSnackbar?.close();
  355 + _queue.cancelAllJobs();
  356 + }
  357 +
  358 + void closeCurrentJob() {
  359 + _currentSnackbar?.close();
  360 + }
  361 +}
@@ -4,8 +4,8 @@ class GetMicrotask { @@ -4,8 +4,8 @@ class GetMicrotask {
4 int _version = 0; 4 int _version = 0;
5 int _microtask = 0; 5 int _microtask = 0;
6 6
7 - int get version => _version;  
8 int get microtask => _microtask; 7 int get microtask => _microtask;
  8 + int get version => _version;
9 9
10 void exec(Function callback) { 10 void exec(Function callback) {
11 if (_microtask == _version) { 11 if (_microtask == _version) {
@@ -23,6 +23,17 @@ class GetQueue { @@ -23,6 +23,17 @@ class GetQueue {
23 final List<_Item> _queue = []; 23 final List<_Item> _queue = [];
24 bool _active = false; 24 bool _active = false;
25 25
  26 + Future<T> add<T>(Function job) {
  27 + var completer = Completer<T>();
  28 + _queue.add(_Item(completer, job));
  29 + _check();
  30 + return completer.future;
  31 + }
  32 +
  33 + void cancelAllJobs() {
  34 + _queue.clear();
  35 + }
  36 +
26 void _check() async { 37 void _check() async {
27 if (!_active && _queue.isNotEmpty) { 38 if (!_active && _queue.isNotEmpty) {
28 _active = true; 39 _active = true;
@@ -36,13 +47,6 @@ class GetQueue { @@ -36,13 +47,6 @@ class GetQueue {
36 _check(); 47 _check();
37 } 48 }
38 } 49 }
39 -  
40 - Future<T> add<T>(Function job) {  
41 - var completer = Completer<T>();  
42 - _queue.add(_Item(completer, job));  
43 - _check();  
44 - return completer.future;  
45 - }  
46 } 50 }
47 51
48 class _Item { 52 class _Item {