Jonny Borges

prevent snackbars appear simultaneosly

@@ -2,28 +2,51 @@ import 'package:flutter/foundation.dart'; @@ -2,28 +2,51 @@ import 'package:flutter/foundation.dart';
2 import 'package:flutter/material.dart'; 2 import 'package:flutter/material.dart';
3 import 'package:get/get.dart'; 3 import 'package:get/get.dart';
4 4
5 -import 'lang/translation_service.dart';  
6 -import 'routes/app_pages.dart';  
7 -import 'shared/logger/logger_utils.dart';  
8 -  
9 void main() { 5 void main() {
10 runApp(MyApp()); 6 runApp(MyApp());
11 } 7 }
12 8
13 -class MyApp extends StatelessWidget {  
14 - const MyApp({Key? key}) : super(key: key); 9 +// class MyApp extends StatelessWidget {
  10 +// const MyApp({Key? key}) : super(key: key);
  11 +
  12 +// @override
  13 +// Widget build(BuildContext context) {
  14 +// return GetMaterialApp.router(
  15 +// debugShowCheckedModeBanner: false,
  16 +// enableLog: true,
  17 +// logWriterCallback: Logger.write,
  18 +// // initialRoute: AppPages.INITIAL,
  19 +// getPages: AppPages.routes,
  20 +// locale: TranslationService.locale,
  21 +// fallbackLocale: TranslationService.fallbackLocale,
  22 +// translations: TranslationService(),
  23 +// );
  24 +// }
  25 +// }
15 26
  27 +class First extends StatelessWidget {
16 @override 28 @override
17 Widget build(BuildContext context) { 29 Widget build(BuildContext context) {
18 - return GetMaterialApp.router(  
19 - debugShowCheckedModeBanner: false,  
20 - enableLog: true,  
21 - logWriterCallback: Logger.write,  
22 - // initialRoute: AppPages.INITIAL,  
23 - getPages: AppPages.routes,  
24 - locale: TranslationService.locale,  
25 - fallbackLocale: TranslationService.fallbackLocale,  
26 - translations: TranslationService(), 30 + return Scaffold(
  31 + appBar: AppBar(
  32 + title: Text('page one'),
  33 + leading: IconButton(
  34 + icon: Icon(Icons.more),
  35 + onPressed: () async {
  36 + var controller = Get.snackbar('dsdsds', 'sdsdsdsds');
  37 + },
  38 + ),
  39 + ),
  40 + body: Center(
  41 + child: Container(
  42 + height: 300,
  43 + width: 300,
  44 + child: ElevatedButton(
  45 + onPressed: () {},
  46 + child: Text('next screen'),
  47 + ),
  48 + ),
  49 + ),
27 ); 50 );
28 } 51 }
29 } 52 }
@@ -33,98 +56,68 @@ class MyApp extends StatelessWidget { @@ -33,98 +56,68 @@ class MyApp extends StatelessWidget {
33 // runApp(MyApp()); 56 // runApp(MyApp());
34 // } 57 // }
35 58
36 -// class MyApp extends StatelessWidget {  
37 -// MyApp({Key? key}) : super(key: key);  
38 -  
39 -// @override  
40 -// Widget build(BuildContext context) {  
41 -// return GetMaterialApp.router(  
42 -// getPages: [  
43 -// GetPage(  
44 -// participatesInRootNavigator: true,  
45 -// name: '/first',  
46 -// page: () => First()),  
47 -// GetPage(  
48 -// name: '/second',  
49 -// page: () => Second(),  
50 -// ),  
51 -// GetPage(  
52 -// name: '/third',  
53 -// page: () => Third(),  
54 -// ),  
55 -// ],  
56 -// debugShowCheckedModeBanner: false,  
57 -// );  
58 -// }  
59 -// } 59 +class MyApp extends StatelessWidget {
  60 + MyApp({Key? key}) : super(key: key);
60 61
61 -// class First extends StatelessWidget {  
62 -// @override  
63 -// Widget build(BuildContext context) {  
64 -// return Scaffold(  
65 -// appBar: AppBar(  
66 -// title: Text('page one'),  
67 -// leading: IconButton(  
68 -// icon: Icon(Icons.more),  
69 -// onPressed: () {  
70 -// Get.changeTheme(  
71 -// context.isDarkMode ? ThemeData.light() : ThemeData.dark());  
72 -// },  
73 -// ),  
74 -// ),  
75 -// body: Center(  
76 -// child: Container(  
77 -// height: 300,  
78 -// width: 300,  
79 -// child: ElevatedButton(  
80 -// onPressed: () {},  
81 -// child: Text('next screen'),  
82 -// ),  
83 -// ),  
84 -// ),  
85 -// );  
86 -// }  
87 -// } 62 + @override
  63 + Widget build(BuildContext context) {
  64 + return GetMaterialApp.router(
  65 + getPages: [
  66 + GetPage(
  67 + participatesInRootNavigator: true, name: '/', page: () => First()),
  68 + GetPage(
  69 + name: '/second',
  70 + page: () => Second(),
  71 + ),
  72 + GetPage(
  73 + name: '/third',
  74 + page: () => Third(),
  75 + ),
  76 + ],
  77 + debugShowCheckedModeBanner: false,
  78 + );
  79 + }
  80 +}
88 81
89 -// class Second extends StatelessWidget {  
90 -// @override  
91 -// Widget build(BuildContext context) {  
92 -// return Scaffold(  
93 -// appBar: AppBar(  
94 -// title: Text('page two ${Get.parameters["id"]}'),  
95 -// ),  
96 -// body: Center(  
97 -// child: Container(  
98 -// height: 300,  
99 -// width: 300,  
100 -// child: ElevatedButton(  
101 -// onPressed: () {},  
102 -// child: Text('next screen'),  
103 -// ),  
104 -// ),  
105 -// ),  
106 -// );  
107 -// }  
108 -// } 82 +class Second extends StatelessWidget {
  83 + @override
  84 + Widget build(BuildContext context) {
  85 + return Scaffold(
  86 + appBar: AppBar(
  87 + title: Text('page two ${Get.parameters["id"]}'),
  88 + ),
  89 + body: Center(
  90 + child: Container(
  91 + height: 300,
  92 + width: 300,
  93 + child: ElevatedButton(
  94 + onPressed: () {},
  95 + child: Text('next screen'),
  96 + ),
  97 + ),
  98 + ),
  99 + );
  100 + }
  101 +}
109 102
110 -// class Third extends StatelessWidget {  
111 -// @override  
112 -// Widget build(BuildContext context) {  
113 -// return Scaffold(  
114 -// backgroundColor: Colors.red,  
115 -// appBar: AppBar(  
116 -// title: Text('page three'),  
117 -// ),  
118 -// body: Center(  
119 -// child: Container(  
120 -// height: 300,  
121 -// width: 300,  
122 -// child: ElevatedButton(  
123 -// onPressed: () {},  
124 -// child: Text('go to first screen'),  
125 -// ),  
126 -// ),  
127 -// ),  
128 -// );  
129 -// }  
130 -// } 103 +class Third extends StatelessWidget {
  104 + @override
  105 + Widget build(BuildContext context) {
  106 + return Scaffold(
  107 + backgroundColor: Colors.red,
  108 + appBar: AppBar(
  109 + title: Text('page three'),
  110 + ),
  111 + body: Center(
  112 + child: Container(
  113 + height: 300,
  114 + width: 300,
  115 + child: ElevatedButton(
  116 + onPressed: () {},
  117 + child: Text('go to first screen'),
  118 + ),
  119 + ),
  120 + ),
  121 + );
  122 + }
  123 +}
@@ -17,3 +17,4 @@ export 'src/routes/observers/route_observer.dart'; @@ -17,3 +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/snackbar_controller.dart';
@@ -298,7 +298,7 @@ extension ExtensionSnackbar on GetInterface { @@ -298,7 +298,7 @@ extension ExtensionSnackbar on GetInterface {
298 OnTap? onTap, 298 OnTap? onTap,
299 Duration duration = const Duration(seconds: 3), 299 Duration duration = const Duration(seconds: 3),
300 bool isDismissible = true, 300 bool isDismissible = true,
301 - SnackDismissDirection dismissDirection = SnackDismissDirection.VERTICAL, 301 + DismissDirection? dismissDirection,
302 bool showProgressIndicator = false, 302 bool showProgressIndicator = false,
303 AnimationController? progressIndicatorController, 303 AnimationController? progressIndicatorController,
304 Color? progressIndicatorBackgroundColor, 304 Color? progressIndicatorBackgroundColor,
@@ -314,7 +314,7 @@ extension ExtensionSnackbar on GetInterface { @@ -314,7 +314,7 @@ extension ExtensionSnackbar on GetInterface {
314 Color? overlayColor, 314 Color? overlayColor,
315 Form? userInputForm, 315 Form? userInputForm,
316 }) async { 316 }) async {
317 - final getBar = GetBar( 317 + final getBar = GetSnackBar(
318 snackbarStatus: snackbarStatus, 318 snackbarStatus: snackbarStatus,
319 title: title, 319 title: title,
320 message: message, 320 message: message,
@@ -361,11 +361,13 @@ extension ExtensionSnackbar on GetInterface { @@ -361,11 +361,13 @@ extension ExtensionSnackbar on GetInterface {
361 } 361 }
362 } 362 }
363 363
364 - Future<void> showSnackbar<T>(GetBar snackbar) {  
365 - return SnackbarController(snackbar).show(); 364 + SnackbarController showSnackbar(GetSnackBar snackbar) {
  365 + final controller = SnackbarController(snackbar);
  366 + controller.show();
  367 + return controller;
366 } 368 }
367 369
368 - void snackbar<T>( 370 + SnackbarController snackbar(
369 String title, 371 String title,
370 String message, { 372 String message, {
371 Color? colorText, 373 Color? colorText,
@@ -392,7 +394,7 @@ extension ExtensionSnackbar on GetInterface { @@ -392,7 +394,7 @@ extension ExtensionSnackbar on GetInterface {
392 OnTap? onTap, 394 OnTap? onTap,
393 bool? isDismissible, 395 bool? isDismissible,
394 bool? showProgressIndicator, 396 bool? showProgressIndicator,
395 - SnackDismissDirection? dismissDirection, 397 + DismissDirection? dismissDirection,
396 AnimationController? progressIndicatorController, 398 AnimationController? progressIndicatorController,
397 Color? progressIndicatorBackgroundColor, 399 Color? progressIndicatorBackgroundColor,
398 Animation<Color>? progressIndicatorValueColor, 400 Animation<Color>? progressIndicatorValueColor,
@@ -405,8 +407,8 @@ extension ExtensionSnackbar on GetInterface { @@ -405,8 +407,8 @@ extension ExtensionSnackbar on GetInterface {
405 SnackbarStatusCallback? snackbarStatus, 407 SnackbarStatusCallback? snackbarStatus,
406 Color? overlayColor, 408 Color? overlayColor,
407 Form? userInputForm, 409 Form? userInputForm,
408 - }) async {  
409 - final getBar = GetBar( 410 + }) {
  411 + final getSnackBar = GetSnackBar(
410 snackbarStatus: snackbarStatus, 412 snackbarStatus: snackbarStatus,
411 titleText: titleText ?? 413 titleText: titleText ??
412 Text( 414 Text(
@@ -444,7 +446,7 @@ extension ExtensionSnackbar on GetInterface { @@ -444,7 +446,7 @@ extension ExtensionSnackbar on GetInterface {
444 mainButton: mainButton, 446 mainButton: mainButton,
445 onTap: onTap, 447 onTap: onTap,
446 isDismissible: isDismissible ?? true, 448 isDismissible: isDismissible ?? true,
447 - dismissDirection: dismissDirection ?? SnackDismissDirection.VERTICAL, 449 + dismissDirection: dismissDirection,
448 showProgressIndicator: showProgressIndicator ?? false, 450 showProgressIndicator: showProgressIndicator ?? false,
449 progressIndicatorController: progressIndicatorController, 451 progressIndicatorController: progressIndicatorController,
450 progressIndicatorBackgroundColor: progressIndicatorBackgroundColor, 452 progressIndicatorBackgroundColor: progressIndicatorBackgroundColor,
@@ -457,14 +459,17 @@ extension ExtensionSnackbar on GetInterface { @@ -457,14 +459,17 @@ extension ExtensionSnackbar on GetInterface {
457 overlayColor: overlayColor ?? Colors.transparent, 459 overlayColor: overlayColor ?? Colors.transparent,
458 userInputForm: userInputForm); 460 userInputForm: userInputForm);
459 461
  462 + final controller = SnackbarController(getSnackBar);
  463 +
460 if (instantInit) { 464 if (instantInit) {
461 - showSnackbar<T>(getBar); 465 + controller.show();
462 } else { 466 } else {
463 //routing.isSnackbar = true; 467 //routing.isSnackbar = true;
464 SchedulerBinding.instance!.addPostFrameCallback((_) { 468 SchedulerBinding.instance!.addPostFrameCallback((_) {
465 - showSnackbar<T>(getBar); 469 + controller.show();
466 }); 470 });
467 } 471 }
  472 + return controller;
468 } 473 }
469 } 474 }
470 475
@@ -7,16 +7,18 @@ import 'package:flutter/scheduler.dart'; @@ -7,16 +7,18 @@ import 'package:flutter/scheduler.dart';
7 import '../../../get_core/get_core.dart'; 7 import '../../../get_core/get_core.dart';
8 import '../../get_navigation.dart'; 8 import '../../get_navigation.dart';
9 9
10 -typedef OnTap = void Function(GetBar snack); 10 +typedef OnTap = void Function(GetSnackBar snack);
11 typedef SnackbarStatusCallback = void Function(SnackbarStatus? status); 11 typedef SnackbarStatusCallback = void Function(SnackbarStatus? status);
12 12
13 -class GetBar<T extends Object> extends StatefulWidget { 13 +class GetSnackBar extends StatefulWidget {
14 /// A callback for you to listen to the different Snack status 14 /// A callback for you to listen to the different Snack status
15 final SnackbarStatusCallback? snackbarStatus; 15 final SnackbarStatusCallback? snackbarStatus;
16 16
17 /// The title displayed to the user 17 /// The title displayed to the user
18 final String? title; 18 final String? title;
19 19
  20 + final DismissDirection? dismissDirection;
  21 +
20 /// The message displayed to the user. 22 /// The message displayed to the user.
21 final String? message; 23 final String? message;
22 24
@@ -112,11 +114,6 @@ class GetBar<T extends Object> extends StatefulWidget { @@ -112,11 +114,6 @@ class GetBar<T extends Object> extends StatefulWidget {
112 /// [SnackPosition.BOTTOM] is the default. 114 /// [SnackPosition.BOTTOM] is the default.
113 final SnackPosition snackPosition; 115 final SnackPosition snackPosition;
114 116
115 - /// [SnackDismissDirection.VERTICAL] by default.  
116 - /// Can also be [SnackDismissDirection.HORIZONTAL] in which case both left  
117 - /// and right dismiss are allowed.  
118 - final SnackDismissDirection dismissDirection;  
119 -  
120 /// 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.
121 /// If grounded, I do not recommend using [margin] or [borderRadius]. 118 /// If grounded, I do not recommend using [margin] or [borderRadius].
122 /// [SnackStyle.FLOATING] is the default 119 /// [SnackStyle.FLOATING] is the default
@@ -154,7 +151,7 @@ class GetBar<T extends Object> extends StatefulWidget { @@ -154,7 +151,7 @@ class GetBar<T extends Object> extends StatefulWidget {
154 /// Every other widget is ignored if this is not null. 151 /// Every other widget is ignored if this is not null.
155 final Form? userInputForm; 152 final Form? userInputForm;
156 153
157 - const GetBar({ 154 + const GetSnackBar({
158 Key? key, 155 Key? key,
159 this.title, 156 this.title,
160 this.message, 157 this.message,
@@ -176,7 +173,7 @@ class GetBar<T extends Object> extends StatefulWidget { @@ -176,7 +173,7 @@ class GetBar<T extends Object> extends StatefulWidget {
176 this.onTap, 173 this.onTap,
177 this.duration, 174 this.duration,
178 this.isDismissible = true, 175 this.isDismissible = true,
179 - this.dismissDirection = SnackDismissDirection.VERTICAL, 176 + this.dismissDirection,
180 this.showProgressIndicator = false, 177 this.showProgressIndicator = false,
181 this.progressIndicatorController, 178 this.progressIndicatorController,
182 this.progressIndicatorBackgroundColor, 179 this.progressIndicatorBackgroundColor,
@@ -194,13 +191,11 @@ class GetBar<T extends Object> extends StatefulWidget { @@ -194,13 +191,11 @@ class GetBar<T extends Object> extends StatefulWidget {
194 }) : super(key: key); 191 }) : super(key: key);
195 192
196 @override 193 @override
197 - State createState() {  
198 - return _GetBarState<T>();  
199 - } 194 + State createState() => _GetSnackBarState();
200 195
201 /// Show the snack. It's call [SnackbarStatus.OPENING] state 196 /// Show the snack. It's call [SnackbarStatus.OPENING] state
202 /// followed by [SnackbarStatus.OPEN] 197 /// followed by [SnackbarStatus.OPEN]
203 - Future<void> show<T>() async { 198 + SnackbarController show() {
204 return Get.showSnackbar(this); 199 return Get.showSnackbar(this);
205 } 200 }
206 } 201 }
@@ -215,21 +210,14 @@ class GetBar<T extends Object> extends StatefulWidget { @@ -215,21 +210,14 @@ class GetBar<T extends Object> extends StatefulWidget {
215 /// with the full snackbar dispose 210 /// with the full snackbar dispose
216 enum SnackbarStatus { OPEN, CLOSED, OPENING, CLOSING } 211 enum SnackbarStatus { OPEN, CLOSED, OPENING, CLOSING }
217 212
218 -/// Indicates the direction in which it is possible to dismiss  
219 -/// If vertical, dismiss up will be allowed if [SnackPosition.TOP]  
220 -/// If vertical, dismiss down will be allowed if [SnackPosition.BOTTOM]  
221 -enum SnackDismissDirection { HORIZONTAL, VERTICAL }  
222 -  
223 /// Indicates if snack is going to start at the [TOP] or at the [BOTTOM] 213 /// Indicates if snack is going to start at the [TOP] or at the [BOTTOM]
224 enum SnackPosition { TOP, BOTTOM } 214 enum SnackPosition { TOP, BOTTOM }
225 215
226 /// Indicates if snack will be attached to the edge of the screen or not 216 /// Indicates if snack will be attached to the edge of the screen or not
227 enum SnackStyle { FLOATING, GROUNDED } 217 enum SnackStyle { FLOATING, GROUNDED }
228 218
229 -class _GetBarState<K extends Object> extends State<GetBar> 219 +class _GetSnackBarState extends State<GetSnackBar>
230 with TickerProviderStateMixin { 220 with TickerProviderStateMixin {
231 - SnackbarStatus? currentStatus;  
232 -  
233 AnimationController? _fadeController; 221 AnimationController? _fadeController;
234 late Animation<double> _fadeAnimation; 222 late Animation<double> _fadeAnimation;
235 223
@@ -251,7 +239,7 @@ class _GetBarState<K extends Object> extends State<GetBar> @@ -251,7 +239,7 @@ class _GetBarState<K extends Object> extends State<GetBar>
251 239
252 late CurvedAnimation _progressAnimation; 240 late CurvedAnimation _progressAnimation;
253 241
254 - GlobalKey backgroundBoxKey = GlobalKey(); 242 + final _backgroundBoxKey = GlobalKey();
255 243
256 @override 244 @override
257 Widget build(BuildContext context) { 245 Widget build(BuildContext context) {
@@ -339,8 +327,7 @@ Set either a message or messageText"""); @@ -339,8 +327,7 @@ Set either a message or messageText""");
339 void _configureLeftBarFuture() { 327 void _configureLeftBarFuture() {
340 SchedulerBinding.instance!.addPostFrameCallback( 328 SchedulerBinding.instance!.addPostFrameCallback(
341 (_) { 329 (_) {
342 - final keyContext = backgroundBoxKey.currentContext;  
343 - 330 + final keyContext = _backgroundBoxKey.currentContext;
344 if (keyContext != null) { 331 if (keyContext != null) {
345 final box = keyContext.findRenderObject() as RenderBox; 332 final box = keyContext.findRenderObject() as RenderBox;
346 _boxHeightCompleter.complete(box.size); 333 _boxHeightCompleter.complete(box.size);
@@ -386,7 +373,7 @@ Set either a message or messageText"""); @@ -386,7 +373,7 @@ Set either a message or messageText""");
386 373
387 Widget _generateInputSnack() { 374 Widget _generateInputSnack() {
388 return Container( 375 return Container(
389 - key: backgroundBoxKey, 376 + key: _backgroundBoxKey,
390 constraints: widget.maxWidth != null 377 constraints: widget.maxWidth != null
391 ? BoxConstraints(maxWidth: widget.maxWidth!) 378 ? BoxConstraints(maxWidth: widget.maxWidth!)
392 : null, 379 : null,
@@ -413,7 +400,7 @@ Set either a message or messageText"""); @@ -413,7 +400,7 @@ Set either a message or messageText""");
413 400
414 Widget _generateSnack() { 401 Widget _generateSnack() {
415 return Container( 402 return Container(
416 - key: backgroundBoxKey, 403 + key: _backgroundBoxKey,
417 constraints: widget.maxWidth != null 404 constraints: widget.maxWidth != null
418 ? BoxConstraints(maxWidth: widget.maxWidth!) 405 ? BoxConstraints(maxWidth: widget.maxWidth!)
419 : null, 406 : null,
@@ -6,28 +6,30 @@ import 'package:flutter/material.dart'; @@ -6,28 +6,30 @@ import 'package:flutter/material.dart';
6 import '../../../get.dart'; 6 import '../../../get.dart';
7 7
8 class SnackbarController { 8 class SnackbarController {
  9 + static final _queue = GetQueue();
9 late Animation<double> _filterBlurAnimation; 10 late Animation<double> _filterBlurAnimation;
10 late Animation<Color?> _filterColorAnimation; 11 late Animation<Color?> _filterColorAnimation;
11 - final GetBar<Object> snack;  
12 12
13 - final Completer _transitionCompleter = Completer();  
14 - late SnackbarStatusCallback? _snackbarStatus; 13 + final GetSnackBar snack;
  14 + final _transitionCompleter = Completer<SnackbarController>();
15 15
  16 + late SnackbarStatusCallback? _snackbarStatus;
16 late final Alignment? _initialAlignment; 17 late final Alignment? _initialAlignment;
17 - late final Alignment? _endAlignment;  
18 18
  19 + late final Alignment? _endAlignment;
19 bool _wasDismissedBySwipe = false; 20 bool _wasDismissedBySwipe = false;
20 bool _onTappedDismiss = false; 21 bool _onTappedDismiss = false;
  22 +
21 Timer? _timer; 23 Timer? _timer;
22 24
23 /// The animation that drives the route's transition and the previous route's 25 /// The animation that drives the route's transition and the previous route's
24 /// forward transition. 26 /// forward transition.
25 - late Animation<Alignment> _animation; 27 + late final Animation<Alignment> _animation;
26 28
27 /// The animation controller that the route uses to drive the transitions. 29 /// The animation controller that the route uses to drive the transitions.
28 /// 30 ///
29 /// The animation itself is exposed by the [animation] property. 31 /// The animation itself is exposed by the [animation] property.
30 - late AnimationController _controller; 32 + late final AnimationController _controller;
31 33
32 SnackbarStatus? _currentStatus; 34 SnackbarStatus? _currentStatus;
33 35
@@ -37,72 +39,20 @@ class SnackbarController { @@ -37,72 +39,20 @@ class SnackbarController {
37 39
38 SnackbarController(this.snack); 40 SnackbarController(this.snack);
39 41
40 - Future get future => _transitionCompleter.future; 42 + Future<SnackbarController> get future => _transitionCompleter.future;
41 43
42 bool get isSnackbarBeingShown => _currentStatus != SnackbarStatus.CLOSED; 44 bool get isSnackbarBeingShown => _currentStatus != SnackbarStatus.CLOSED;
43 45
44 - Animation<double> createBlurFilterAnimation() {  
45 - return Tween(begin: 0.0, end: snack.overlayBlur).animate(  
46 - CurvedAnimation(  
47 - parent: _controller,  
48 - curve: const Interval(  
49 - 0.0,  
50 - 0.35,  
51 - curve: Curves.easeInOutCirc,  
52 - ),  
53 - ),  
54 - );  
55 - }  
56 -  
57 - Animation<Color?> createColorOverlayColor() {  
58 - return ColorTween(begin: const Color(0x00000000), end: snack.overlayColor)  
59 - .animate(  
60 - CurvedAnimation(  
61 - parent: _controller,  
62 - curve: const Interval(  
63 - 0.0,  
64 - 0.35,  
65 - curve: Curves.easeInOutCirc,  
66 - ),  
67 - ),  
68 - );  
69 - }  
70 -  
71 - void removeEntry() {  
72 - assert(  
73 - !_transitionCompleter.isCompleted,  
74 - 'Cannot remove entry from a disposed snackbar',  
75 - );  
76 -  
77 - _cancelTimer();  
78 -  
79 - if (_wasDismissedBySwipe) {  
80 - Timer(const Duration(milliseconds: 200), () {  
81 - _controller.reset();  
82 - });  
83 -  
84 - _wasDismissedBySwipe = false;  
85 - } else {  
86 - _controller.reverse();  
87 - }  
88 - }  
89 -  
90 - void removeOverlay() {  
91 - for (var element in _overlayEntries) {  
92 - element.remove();  
93 - }  
94 -  
95 - assert(!_transitionCompleter.isCompleted, 'Cannot remove overlay twice.');  
96 - _controller.dispose();  
97 - _overlayEntries.clear();  
98 - _transitionCompleter.complete(); 46 + Future<void> close() async {
  47 + _removeEntry();
  48 + await future;
99 } 49 }
100 50
101 Future<void> show() { 51 Future<void> show() {
102 - _configureOverlay();  
103 - return future; 52 + return _queue.add(_show);
104 } 53 }
105 54
  55 + // ignore: avoid_returning_this
106 void _cancelTimer() { 56 void _cancelTimer() {
107 if (_timer != null && _timer!.isActive) { 57 if (_timer != null && _timer!.isActive) {
108 _timer!.cancel(); 58 _timer!.cancel();
@@ -138,12 +88,10 @@ class SnackbarController { @@ -138,12 +88,10 @@ class SnackbarController {
138 assert(!_transitionCompleter.isCompleted, 88 assert(!_transitionCompleter.isCompleted,
139 'Cannot configure a snackbar after disposing it.'); 89 'Cannot configure a snackbar after disposing it.');
140 _controller = _createAnimationController(); 90 _controller = _createAnimationController();
141 -  
142 _configureAlignment(snack.snackPosition); 91 _configureAlignment(snack.snackPosition);
143 _snackbarStatus = snack.snackbarStatus; 92 _snackbarStatus = snack.snackbarStatus;
144 -  
145 - _filterBlurAnimation = createBlurFilterAnimation();  
146 - _filterColorAnimation = createColorOverlayColor(); 93 + _filterBlurAnimation = _createBlurFilterAnimation();
  94 + _filterColorAnimation = _createColorOverlayColor();
147 _animation = _createAnimation(); 95 _animation = _createAnimation();
148 _animation.addStatusListener(_handleStatusChanged); 96 _animation.addStatusListener(_handleStatusChanged);
149 _configureTimer(); 97 _configureTimer();
@@ -155,7 +103,7 @@ class SnackbarController { @@ -155,7 +103,7 @@ class SnackbarController {
155 if (_timer != null && _timer!.isActive) { 103 if (_timer != null && _timer!.isActive) {
156 _timer!.cancel(); 104 _timer!.cancel();
157 } 105 }
158 - _timer = Timer(snack.duration!, removeEntry); 106 + _timer = Timer(snack.duration!, _removeEntry);
159 } else { 107 } else {
160 if (_timer != null) { 108 if (_timer != null) {
161 _timer!.cancel(); 109 _timer!.cancel();
@@ -192,6 +140,33 @@ class SnackbarController { @@ -192,6 +140,33 @@ class SnackbarController {
192 ); 140 );
193 } 141 }
194 142
  143 + Animation<double> _createBlurFilterAnimation() {
  144 + return Tween(begin: 0.0, end: snack.overlayBlur).animate(
  145 + CurvedAnimation(
  146 + parent: _controller,
  147 + curve: const Interval(
  148 + 0.0,
  149 + 0.35,
  150 + curve: Curves.easeInOutCirc,
  151 + ),
  152 + ),
  153 + );
  154 + }
  155 +
  156 + Animation<Color?> _createColorOverlayColor() {
  157 + return ColorTween(begin: const Color(0x00000000), end: snack.overlayColor)
  158 + .animate(
  159 + CurvedAnimation(
  160 + parent: _controller,
  161 + curve: const Interval(
  162 + 0.0,
  163 + 0.35,
  164 + curve: Curves.easeInOutCirc,
  165 + ),
  166 + ),
  167 + );
  168 + }
  169 +
195 Iterable<OverlayEntry> _createOverlayEntries(Widget child) { 170 Iterable<OverlayEntry> _createOverlayEntries(Widget child) {
196 return <OverlayEntry>[ 171 return <OverlayEntry>[
197 if (snack.overlayBlur > 0.0) ...[ 172 if (snack.overlayBlur > 0.0) ...[
@@ -249,20 +224,16 @@ class SnackbarController { @@ -249,20 +224,16 @@ class SnackbarController {
249 }); 224 });
250 } 225 }
251 226
252 - DismissDirection _getDismissDirection() {  
253 - if (snack.dismissDirection == SnackDismissDirection.HORIZONTAL) {  
254 - return DismissDirection.horizontal;  
255 - } else {  
256 - if (snack.snackPosition == SnackPosition.TOP) {  
257 - return DismissDirection.up;  
258 - }  
259 - return DismissDirection.down; 227 + DismissDirection _getDefaultDismissDirection() {
  228 + if (snack.snackPosition == SnackPosition.TOP) {
  229 + return DismissDirection.up;
260 } 230 }
  231 + return DismissDirection.down;
261 } 232 }
262 233
263 Widget _getDismissibleSnack(Widget child) { 234 Widget _getDismissibleSnack(Widget child) {
264 return Dismissible( 235 return Dismissible(
265 - direction: _getDismissDirection(), 236 + direction: snack.dismissDirection ?? _getDefaultDismissDirection(),
266 resizeDuration: null, 237 resizeDuration: null,
267 confirmDismiss: (_) { 238 confirmDismiss: (_) {
268 if (_currentStatus == SnackbarStatus.OPENING || 239 if (_currentStatus == SnackbarStatus.OPENING ||
@@ -273,9 +244,7 @@ class SnackbarController { @@ -273,9 +244,7 @@ class SnackbarController {
273 }, 244 },
274 key: const Key('dismissible'), 245 key: const Key('dismissible'),
275 onDismissed: (_) { 246 onDismissed: (_) {
276 - _cancelTimer();  
277 - _wasDismissedBySwipe = true;  
278 - removeEntry(); 247 + _onDismiss();
279 }, 248 },
280 child: _getSnackbarContainer(child), 249 child: _getSnackbarContainer(child),
281 ); 250 );
@@ -309,8 +278,51 @@ class SnackbarController { @@ -309,8 +278,51 @@ class SnackbarController {
309 assert(!_overlayEntries.first.opaque); 278 assert(!_overlayEntries.first.opaque);
310 _currentStatus = SnackbarStatus.CLOSED; 279 _currentStatus = SnackbarStatus.CLOSED;
311 _snackbarStatus?.call(_currentStatus); 280 _snackbarStatus?.call(_currentStatus);
312 - removeOverlay(); 281 + _removeOverlay();
313 break; 282 break;
314 } 283 }
315 } 284 }
  285 +
  286 + void _onDismiss() {
  287 + _cancelTimer();
  288 + _wasDismissedBySwipe = true;
  289 + _removeEntry();
  290 + }
  291 +
  292 + void _registerSnackbar() {}
  293 +
  294 + void _removeEntry() {
  295 + assert(
  296 + !_transitionCompleter.isCompleted,
  297 + 'Cannot remove entry from a disposed snackbar',
  298 + );
  299 +
  300 + _cancelTimer();
  301 +
  302 + if (_wasDismissedBySwipe) {
  303 + Timer(const Duration(milliseconds: 200), _controller.reset);
  304 +
  305 + _wasDismissedBySwipe = false;
  306 + } else {
  307 + _controller.reverse();
  308 + }
  309 + }
  310 +
  311 + void _removeOverlay() {
  312 + for (var element in _overlayEntries) {
  313 + element.remove();
  314 + }
  315 +
  316 + assert(!_transitionCompleter.isCompleted, 'Cannot remove overlay twice.');
  317 + _controller.dispose();
  318 + _overlayEntries.clear();
  319 + _transitionCompleter.complete(this);
  320 + }
  321 +
  322 + Future<void> _show() {
  323 + _configureOverlay();
  324 + return future;
  325 + }
  326 +
  327 + void _unRegisterSnackbar() {}
316 } 328 }