Jonny Borges

add queue, improve logic, close the specific snackbar inside a queue

@@ -7,7 +7,7 @@ import 'routes/app_pages.dart'; @@ -7,7 +7,7 @@ import 'routes/app_pages.dart';
7 import 'shared/logger/logger_utils.dart'; 7 import 'shared/logger/logger_utils.dart';
8 8
9 void main() { 9 void main() {
10 - runApp(const MyApp()); 10 + runApp(MyApp());
11 } 11 }
12 12
13 class MyApp extends StatelessWidget { 13 class MyApp extends StatelessWidget {
@@ -16,5 +16,5 @@ export 'src/routes/get_route.dart'; @@ -16,5 +16,5 @@ export 'src/routes/get_route.dart';
16 export 'src/routes/observers/route_observer.dart'; 16 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/snackbar.dart';
20 export 'src/snackbar/snackbar_controller.dart'; 20 export 'src/snackbar/snackbar_controller.dart';
@@ -8,6 +8,7 @@ import '../../../get_core/get_core.dart'; @@ -8,6 +8,7 @@ import '../../../get_core/get_core.dart';
8 import '../../get_navigation.dart'; 8 import '../../get_navigation.dart';
9 9
10 typedef OnTap = void Function(GetSnackBar snack); 10 typedef OnTap = void Function(GetSnackBar snack);
  11 +
11 typedef SnackbarStatusCallback = void Function(SnackbarStatus? status); 12 typedef SnackbarStatusCallback = void Function(SnackbarStatus? status);
12 13
13 class GetSnackBar extends StatefulWidget { 14 class GetSnackBar extends StatefulWidget {
@@ -17,6 +18,11 @@ class GetSnackBar extends StatefulWidget { @@ -17,6 +18,11 @@ class GetSnackBar extends StatefulWidget {
17 /// The title displayed to the user 18 /// The title displayed to the user
18 final String? title; 19 final String? title;
19 20
  21 + /// The direction in which the SnackBar can be dismissed.
  22 + ///
  23 + /// Cannot be null, defaults to [DismissDirection.down] when
  24 + /// [snackPosition] == [SnackPosition.BOTTOM] and [DismissDirection.up]
  25 + /// when [snackPosition] == [SnackPosition.TOP]
20 final DismissDirection? dismissDirection; 26 final DismissDirection? dismissDirection;
21 27
22 /// The message displayed to the user. 28 /// The message displayed to the user.
@@ -44,7 +50,8 @@ class GetSnackBar extends StatefulWidget { @@ -44,7 +50,8 @@ class GetSnackBar extends StatefulWidget {
44 /// Check (this example)[https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/material/shadows.dart] 50 /// Check (this example)[https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/material/shadows.dart]
45 final List<BoxShadow>? boxShadows; 51 final List<BoxShadow>? boxShadows;
46 52
47 - /// Makes [backgroundColor] be ignored. 53 + /// Give to GetSnackbar a gradient background.
  54 + /// It Makes [backgroundColor] be ignored.
48 final Gradient? backgroundGradient; 55 final Gradient? backgroundGradient;
49 56
50 /// You can use any widget here, but I recommend [Icon] or [Image] as 57 /// You can use any widget here, but I recommend [Icon] or [Image] as
@@ -55,7 +62,10 @@ class GetSnackBar extends StatefulWidget { @@ -55,7 +62,10 @@ class GetSnackBar extends StatefulWidget {
55 /// An option to animate the icon (if present). Defaults to true. 62 /// An option to animate the icon (if present). Defaults to true.
56 final bool shouldIconPulse; 63 final bool shouldIconPulse;
57 64
58 - /// A [TextButton] widget if you need an action from the user. 65 + /// (optional) An action that the user can take based on the snack bar.
  66 + ///
  67 + /// For example, the snack bar might let the user undo the operation that
  68 + /// prompted the snackbar.
59 final Widget? mainButton; 69 final Widget? mainButton;
60 70
61 /// A callback that registers the user's click anywhere. 71 /// A callback that registers the user's click anywhere.
@@ -200,6 +210,13 @@ class GetSnackBar extends StatefulWidget { @@ -200,6 +210,13 @@ class GetSnackBar extends StatefulWidget {
200 } 210 }
201 } 211 }
202 212
  213 +enum RowStyle {
  214 + icon,
  215 + action,
  216 + all,
  217 + none,
  218 +}
  219 +
203 /// Indicates Status of snackbar 220 /// Indicates Status of snackbar
204 /// [SnackbarStatus.OPEN] Snack is fully open, [SnackbarStatus.CLOSED] Snackbar 221 /// [SnackbarStatus.OPEN] Snack is fully open, [SnackbarStatus.CLOSED] Snackbar
205 /// has closed, 222 /// has closed,
@@ -235,12 +252,30 @@ class _GetSnackBarState extends State<GetSnackBar> @@ -235,12 +252,30 @@ class _GetSnackBarState extends State<GetSnackBar>
235 252
236 final Completer<Size> _boxHeightCompleter = Completer<Size>(); 253 final Completer<Size> _boxHeightCompleter = Completer<Size>();
237 254
238 - late VoidCallback _progressListener;  
239 -  
240 late CurvedAnimation _progressAnimation; 255 late CurvedAnimation _progressAnimation;
241 256
242 final _backgroundBoxKey = GlobalKey(); 257 final _backgroundBoxKey = GlobalKey();
243 258
  259 + double get buttonPadding {
  260 + if (widget.padding.right - 12 < 0) {
  261 + return 4;
  262 + } else {
  263 + return widget.padding.right - 12;
  264 + }
  265 + }
  266 +
  267 + RowStyle get _rowStyle {
  268 + if (widget.mainButton != null && widget.icon == null) {
  269 + return RowStyle.action;
  270 + } else if (widget.mainButton == null && widget.icon != null) {
  271 + return RowStyle.icon;
  272 + } else if (widget.mainButton != null && widget.icon != null) {
  273 + return RowStyle.all;
  274 + } else {
  275 + return RowStyle.none;
  276 + }
  277 + }
  278 +
244 @override 279 @override
245 Widget build(BuildContext context) { 280 Widget build(BuildContext context) {
246 return Align( 281 return Align(
@@ -258,7 +293,42 @@ class _GetSnackBarState extends State<GetSnackBar> @@ -258,7 +293,42 @@ class _GetSnackBarState extends State<GetSnackBar>
258 top: widget.snackPosition == SnackPosition.TOP, 293 top: widget.snackPosition == SnackPosition.TOP,
259 left: false, 294 left: false,
260 right: false, 295 right: false,
261 - child: _getSnack(), 296 + child: Stack(
  297 + children: [
  298 + FutureBuilder<Size>(
  299 + future: _boxHeightCompleter.future,
  300 + builder: (context, snapshot) {
  301 + if (snapshot.hasData) {
  302 + if (widget.barBlur == 0) {
  303 + return _emptyWidget;
  304 + }
  305 + return ClipRRect(
  306 + borderRadius: BorderRadius.circular(widget.borderRadius),
  307 + child: BackdropFilter(
  308 + filter: ImageFilter.blur(
  309 + sigmaX: widget.barBlur!, sigmaY: widget.barBlur!),
  310 + child: Container(
  311 + height: snapshot.data!.height,
  312 + width: snapshot.data!.width,
  313 + decoration: BoxDecoration(
  314 + color: Colors.transparent,
  315 + borderRadius:
  316 + BorderRadius.circular(widget.borderRadius),
  317 + ),
  318 + ),
  319 + ),
  320 + );
  321 + } else {
  322 + return _emptyWidget;
  323 + }
  324 + },
  325 + ),
  326 + if (widget.userInputForm != null)
  327 + _containerWithForm()
  328 + else
  329 + _containerWithoutForm()
  330 + ],
  331 + ),
262 ), 332 ),
263 ), 333 ),
264 ); 334 );
@@ -267,8 +337,7 @@ class _GetSnackBarState extends State<GetSnackBar> @@ -267,8 +337,7 @@ class _GetSnackBarState extends State<GetSnackBar>
267 @override 337 @override
268 void dispose() { 338 void dispose() {
269 _fadeController?.dispose(); 339 _fadeController?.dispose();
270 -  
271 - widget.progressIndicatorController?.removeListener(_progressListener); 340 + widget.progressIndicatorController?.removeListener(_updateProgress);
272 widget.progressIndicatorController?.dispose(); 341 widget.progressIndicatorController?.dispose();
273 342
274 _focusAttachment.detach(); 343 _focusAttachment.detach();
@@ -284,9 +353,8 @@ class _GetSnackBarState extends State<GetSnackBar> @@ -284,9 +353,8 @@ class _GetSnackBarState extends State<GetSnackBar>
284 widget.userInputForm != null || 353 widget.userInputForm != null ||
285 ((widget.message != null && widget.message!.isNotEmpty) || 354 ((widget.message != null && widget.message!.isNotEmpty) ||
286 widget.messageText != null), 355 widget.messageText != null),
287 - """  
288 -A message is mandatory if you are not using userInputForm.  
289 -Set either a message or messageText"""); 356 + '''
  357 +You need to either use message[String], or messageText[Widget] or define a userInputForm[Form] in GetSnackbar''');
290 358
291 _isTitlePresent = (widget.title != null || widget.titleText != null); 359 _isTitlePresent = (widget.title != null || widget.titleText != null);
292 _messageTopMargin = _isTitlePresent ? 6.0 : widget.padding.top; 360 _messageTopMargin = _isTitlePresent ? 6.0 : widget.padding.top;
@@ -339,10 +407,7 @@ Set either a message or messageText"""); @@ -339,10 +407,7 @@ Set either a message or messageText""");
339 void _configureProgressIndicatorAnimation() { 407 void _configureProgressIndicatorAnimation() {
340 if (widget.showProgressIndicator && 408 if (widget.showProgressIndicator &&
341 widget.progressIndicatorController != null) { 409 widget.progressIndicatorController != null) {
342 - _progressListener = () {  
343 - setState(() {});  
344 - };  
345 - widget.progressIndicatorController!.addListener(_progressListener); 410 + widget.progressIndicatorController!.addListener(_updateProgress);
346 411
347 _progressAnimation = CurvedAnimation( 412 _progressAnimation = CurvedAnimation(
348 curve: Curves.linear, parent: widget.progressIndicatorController!); 413 curve: Curves.linear, parent: widget.progressIndicatorController!);
@@ -371,7 +436,7 @@ Set either a message or messageText"""); @@ -371,7 +436,7 @@ Set either a message or messageText""");
371 _fadeController!.forward(); 436 _fadeController!.forward();
372 } 437 }
373 438
374 - Widget _generateInputSnack() { 439 + Widget _containerWithForm() {
375 return Container( 440 return Container(
376 key: _backgroundBoxKey, 441 key: _backgroundBoxKey,
377 constraints: widget.maxWidth != null 442 constraints: widget.maxWidth != null
@@ -383,7 +448,10 @@ Set either a message or messageText"""); @@ -383,7 +448,10 @@ Set either a message or messageText""");
383 boxShadow: widget.boxShadows, 448 boxShadow: widget.boxShadows,
384 borderRadius: BorderRadius.circular(widget.borderRadius), 449 borderRadius: BorderRadius.circular(widget.borderRadius),
385 border: widget.borderColor != null 450 border: widget.borderColor != null
386 - ? Border.all(color: widget.borderColor!, width: widget.borderWidth!) 451 + ? Border.all(
  452 + color: widget.borderColor!,
  453 + width: widget.borderWidth!,
  454 + )
387 : null, 455 : null,
388 ), 456 ),
389 child: Padding( 457 child: Padding(
@@ -398,7 +466,14 @@ Set either a message or messageText"""); @@ -398,7 +466,14 @@ Set either a message or messageText""");
398 ); 466 );
399 } 467 }
400 468
401 - Widget _generateSnack() { 469 + Widget _containerWithoutForm() {
  470 + final iconPadding = widget.padding.left > 16.0 ? widget.padding.left : 0.0;
  471 + final left = _rowStyle == RowStyle.icon || _rowStyle == RowStyle.all
  472 + ? 4.0
  473 + : widget.padding.left;
  474 + final right = _rowStyle == RowStyle.action || _rowStyle == RowStyle.all
  475 + ? 8.0
  476 + : widget.padding.right;
402 return Container( 477 return Container(
403 key: _backgroundBoxKey, 478 key: _backgroundBoxKey,
404 constraints: widget.maxWidth != null 479 constraints: widget.maxWidth != null
@@ -427,63 +502,12 @@ Set either a message or messageText"""); @@ -427,63 +502,12 @@ Set either a message or messageText""");
427 : _emptyWidget, 502 : _emptyWidget,
428 Row( 503 Row(
429 mainAxisSize: MainAxisSize.max, 504 mainAxisSize: MainAxisSize.max,
430 - children: _getAppropriateRowLayout(),  
431 - ),  
432 - ],  
433 - ),  
434 - );  
435 - }  
436 -  
437 - List<Widget> _getAppropriateRowLayout() {  
438 - double buttonRightPadding;  
439 - var iconPadding = 0.0;  
440 - if (widget.padding.right - 12 < 0) {  
441 - buttonRightPadding = 4;  
442 - } else {  
443 - buttonRightPadding = widget.padding.right - 12;  
444 - }  
445 -  
446 - if (widget.padding.left > 16.0) {  
447 - iconPadding = widget.padding.left;  
448 - }  
449 -  
450 - if (widget.icon == null && widget.mainButton == null) {  
451 - return [  
452 - _buildLeftBarIndicator(),  
453 - Expanded(  
454 - flex: 1,  
455 - child: Column(  
456 - crossAxisAlignment: CrossAxisAlignment.stretch,  
457 - mainAxisSize: MainAxisSize.min,  
458 - children: <Widget>[  
459 - (_isTitlePresent)  
460 - ? Padding(  
461 - padding: EdgeInsets.only(  
462 - top: widget.padding.top,  
463 - left: widget.padding.left,  
464 - right: widget.padding.right,  
465 - ),  
466 - child: _getTitleText(),  
467 - )  
468 - : _emptyWidget,  
469 - Padding(  
470 - padding: EdgeInsets.only(  
471 - top: _messageTopMargin,  
472 - left: widget.padding.left,  
473 - right: widget.padding.right,  
474 - bottom: widget.padding.bottom,  
475 - ),  
476 - child: widget.messageText ?? _getDefaultNotificationText(),  
477 - ),  
478 - ],  
479 - ),  
480 - ),  
481 - ];  
482 - } else if (widget.icon != null && widget.mainButton == null) {  
483 - return <Widget>[ 505 + children: [
484 _buildLeftBarIndicator(), 506 _buildLeftBarIndicator(),
  507 + if (_rowStyle == RowStyle.icon)
485 ConstrainedBox( 508 ConstrainedBox(
486 - constraints: BoxConstraints.tightFor(width: 42.0 + iconPadding), 509 + constraints:
  510 + BoxConstraints.tightFor(width: 42.0 + iconPadding),
487 child: _getIcon(), 511 child: _getIcon(),
488 ), 512 ),
489 Expanded( 513 Expanded(
@@ -492,112 +516,51 @@ Set either a message or messageText"""); @@ -492,112 +516,51 @@ Set either a message or messageText""");
492 crossAxisAlignment: CrossAxisAlignment.stretch, 516 crossAxisAlignment: CrossAxisAlignment.stretch,
493 mainAxisSize: MainAxisSize.min, 517 mainAxisSize: MainAxisSize.min,
494 children: <Widget>[ 518 children: <Widget>[
495 - (_isTitlePresent)  
496 - ? Padding(  
497 - padding: EdgeInsets.only(  
498 - top: widget.padding.top,  
499 - left: 4.0,  
500 - right: widget.padding.left,  
501 - ),  
502 - child: _getTitleText(),  
503 - )  
504 - : _emptyWidget, 519 + if (_isTitlePresent)
505 Padding( 520 Padding(
506 padding: EdgeInsets.only( 521 padding: EdgeInsets.only(
507 - top: _messageTopMargin,  
508 - left: 4.0,  
509 - right: widget.padding.right,  
510 - bottom: widget.padding.bottom,  
511 - ),  
512 - child: widget.messageText ?? _getDefaultNotificationText(),  
513 - ),  
514 - ], 522 + top: widget.padding.top,
  523 + left: left,
  524 + right: right,
515 ), 525 ),
  526 + child: widget.titleText ??
  527 + Text(
  528 + widget.title ?? "",
  529 + style: TextStyle(
  530 + fontSize: 16.0,
  531 + color: Colors.white,
  532 + fontWeight: FontWeight.bold,
516 ), 533 ),
517 - ];  
518 - } else if (widget.icon == null && widget.mainButton != null) {  
519 - return <Widget>[  
520 - _buildLeftBarIndicator(),  
521 - Expanded(  
522 - flex: 1,  
523 - child: Column(  
524 - crossAxisAlignment: CrossAxisAlignment.stretch,  
525 - mainAxisSize: MainAxisSize.min,  
526 - children: <Widget>[  
527 - (_isTitlePresent)  
528 - ? Padding(  
529 - padding: EdgeInsets.only(  
530 - top: widget.padding.top,  
531 - left: widget.padding.left,  
532 - right: widget.padding.right,  
533 ), 534 ),
534 - child: _getTitleText(),  
535 ) 535 )
536 - : _emptyWidget, 536 + else
  537 + _emptyWidget,
537 Padding( 538 Padding(
538 padding: EdgeInsets.only( 539 padding: EdgeInsets.only(
539 top: _messageTopMargin, 540 top: _messageTopMargin,
540 - left: widget.padding.left,  
541 - right: 8.0, 541 + left: left,
  542 + right: right,
542 bottom: widget.padding.bottom, 543 bottom: widget.padding.bottom,
543 ), 544 ),
544 - child: widget.messageText ?? _getDefaultNotificationText(),  
545 - ),  
546 - ],  
547 - ), 545 + child: widget.messageText ??
  546 + Text(
  547 + widget.message ?? "",
  548 + style:
  549 + TextStyle(fontSize: 14.0, color: Colors.white),
548 ), 550 ),
549 - Padding(  
550 - padding: EdgeInsets.only(right: buttonRightPadding),  
551 - child: _getMainActionButton(),  
552 ), 551 ),
553 - ];  
554 - } else {  
555 - return <Widget>[  
556 - _buildLeftBarIndicator(),  
557 - ConstrainedBox(  
558 - constraints: BoxConstraints.tightFor(width: 42.0 + iconPadding),  
559 - child: _getIcon(), 552 + ],
560 ), 553 ),
561 - Expanded(  
562 - flex: 1,  
563 - child: Column(  
564 - crossAxisAlignment: CrossAxisAlignment.stretch,  
565 - mainAxisSize: MainAxisSize.min,  
566 - children: <Widget>[  
567 - (_isTitlePresent)  
568 - ? Padding(  
569 - padding: EdgeInsets.only(  
570 - top: widget.padding.top,  
571 - left: 4.0,  
572 - right: 8.0,  
573 ), 554 ),
574 - child: _getTitleText(),  
575 - )  
576 - : _emptyWidget, 555 + if (_rowStyle == RowStyle.action)
577 Padding( 556 Padding(
578 - padding: EdgeInsets.only(  
579 - top: _messageTopMargin,  
580 - left: 4.0,  
581 - right: 8.0,  
582 - bottom: widget.padding.bottom,  
583 - ),  
584 - child: widget.messageText ?? _getDefaultNotificationText(), 557 + padding: EdgeInsets.only(right: buttonPadding),
  558 + child: widget.mainButton,
585 ), 559 ),
586 ], 560 ],
587 ), 561 ),
  562 + ],
588 ), 563 ),
589 - Padding(  
590 - padding: EdgeInsets.only(right: buttonRightPadding),  
591 - child: _getMainActionButton(),  
592 - ),  
593 - ];  
594 - }  
595 - }  
596 -  
597 - Text _getDefaultNotificationText() {  
598 - return Text(  
599 - widget.message ?? "",  
600 - style: TextStyle(fontSize: 14.0, color: Colors.white),  
601 ); 564 );
602 } 565 }
603 566
@@ -614,59 +577,5 @@ Set either a message or messageText"""); @@ -614,59 +577,5 @@ Set either a message or messageText""");
614 } 577 }
615 } 578 }
616 579
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 -  
664 - Widget _getTitleText() {  
665 - return widget.titleText ??  
666 - Text(  
667 - widget.title ?? "",  
668 - style: TextStyle(  
669 - fontSize: 16.0, color: Colors.white, fontWeight: FontWeight.bold),  
670 - );  
671 - } 580 + void _updateProgress() => setState(() {});
672 } 581 }
@@ -7,7 +7,7 @@ import '../../../get.dart'; @@ -7,7 +7,7 @@ import '../../../get.dart';
7 7
8 class SnackbarController { 8 class SnackbarController {
9 static final _snackBarQueue = _SnackBarQueue(); 9 static final _snackBarQueue = _SnackBarQueue();
10 - static bool get isSnackbarBeingShown => _snackBarQueue.isJobInProgress; 10 + static bool get isSnackbarBeingShown => _snackBarQueue._isJobInProgress;
11 11
12 late Animation<double> _filterBlurAnimation; 12 late Animation<double> _filterBlurAnimation;
13 late Animation<Color?> _filterColorAnimation; 13 late Animation<Color?> _filterColorAnimation;
@@ -54,7 +54,7 @@ class SnackbarController { @@ -54,7 +54,7 @@ class SnackbarController {
54 /// Only one GetSnackbar will be displayed at a time, and this method returns 54 /// Only one GetSnackbar will be displayed at a time, and this method returns
55 /// a future to when the snackbar disappears. 55 /// a future to when the snackbar disappears.
56 Future<void> show() { 56 Future<void> show() {
57 - return _snackBarQueue.addJob(this); 57 + return _snackBarQueue._addJob(this);
58 } 58 }
59 59
60 void _cancelTimer() { 60 void _cancelTimer() {
@@ -319,7 +319,8 @@ class SnackbarController { @@ -319,7 +319,8 @@ class SnackbarController {
319 element.remove(); 319 element.remove();
320 } 320 }
321 321
322 - assert(!_transitionCompleter.isCompleted, 'Cannot remove overlay twice.'); 322 + assert(!_transitionCompleter.isCompleted,
  323 + 'Cannot remove overlay from a disposed snackbar');
323 _controller.dispose(); 324 _controller.dispose();
324 _overlayEntries.clear(); 325 _overlayEntries.clear();
325 _transitionCompleter.complete(this); 326 _transitionCompleter.complete(this);
@@ -331,38 +332,39 @@ class SnackbarController { @@ -331,38 +332,39 @@ class SnackbarController {
331 } 332 }
332 333
333 static void cancelAllSnackbars() { 334 static void cancelAllSnackbars() {
334 - _snackBarQueue.cancelAllJobs(); 335 + _snackBarQueue._cancelAllJobs();
335 } 336 }
336 337
337 static Future<void> closeCurrentSnackbar() async { 338 static Future<void> closeCurrentSnackbar() async {
338 - await _snackBarQueue.closeCurrentJob(); 339 + await _snackBarQueue._closeCurrentJob();
339 } 340 }
340 } 341 }
341 342
342 class _SnackBarQueue { 343 class _SnackBarQueue {
343 final _queue = GetQueue(); 344 final _queue = GetQueue();
  345 + final _snackbarList = <SnackbarController>[];
344 346
345 - bool _isJobInProgress = false;  
346 -  
347 - SnackbarController? _currentSnackbar; 347 + SnackbarController? get _currentSnackbar {
  348 + if (_snackbarList.isEmpty) return null;
  349 + return _snackbarList.first;
  350 + }
348 351
349 - bool get isJobInProgress => _isJobInProgress; 352 + bool get _isJobInProgress => _snackbarList.isNotEmpty;
350 353
351 - Future<void> addJob(SnackbarController job) async {  
352 - _isJobInProgress = true;  
353 - _currentSnackbar = job; 354 + Future<void> _addJob(SnackbarController job) async {
  355 + _snackbarList.add(job);
354 final data = await _queue.add(job._show); 356 final data = await _queue.add(job._show);
355 - _isJobInProgress = false;  
356 - _currentSnackbar = null; 357 + _snackbarList.remove(job);
357 return data; 358 return data;
358 } 359 }
359 360
360 - void cancelAllJobs() {  
361 - _currentSnackbar?.close(); 361 + Future<void> _cancelAllJobs() async {
  362 + await _currentSnackbar?.close();
362 _queue.cancelAllJobs(); 363 _queue.cancelAllJobs();
  364 + _snackbarList.clear();
363 } 365 }
364 366
365 - Future<void> closeCurrentJob() async { 367 + Future<void> _closeCurrentJob() async {
366 await _currentSnackbar?.close(); 368 await _currentSnackbar?.close();
367 } 369 }
368 } 370 }