LCOV - code coverage report
Current view: top level - src/snackbar - snack.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 10 273 3.7 %
Date: 2020-07-01 03:00:01 Functions: 0 0 -

          Line data    Source code
       1             : import 'dart:async';
       2             : import 'dart:ui';
       3             : import 'package:flutter/material.dart';
       4             : import 'package:flutter/scheduler.dart';
       5             : import 'package:get/get.dart';
       6             : import 'snack_route.dart' as snackroute;
       7             : 
       8             : typedef void SnackStatusCallback(SnackStatus status);
       9             : typedef void OnTap(GetBar snack);
      10             : 
      11             : // ignore: must_be_immutable
      12             : class GetBar<T extends Object> extends StatefulWidget {
      13           1 :   GetBar(
      14             :       {Key key,
      15             :       String title,
      16             :       String message,
      17             :       Widget titleText,
      18             :       Widget messageText,
      19             :       Widget icon,
      20             :       bool shouldIconPulse = true,
      21             :       double maxWidth,
      22             :       EdgeInsets margin = const EdgeInsets.all(0.0),
      23             :       EdgeInsets padding = const EdgeInsets.all(16),
      24             :       double borderRadius = 0.0,
      25             :       Color borderColor,
      26             :       double borderWidth = 1.0,
      27             :       Color backgroundColor = const Color(0xFF303030),
      28             :       Color leftBarIndicatorColor,
      29             :       List<BoxShadow> boxShadows,
      30             :       Gradient backgroundGradient,
      31             :       FlatButton mainButton,
      32             :       OnTap onTap,
      33             :       Duration duration,
      34             :       bool isDismissible = true,
      35             :       SnackDismissDirection dismissDirection = SnackDismissDirection.VERTICAL,
      36             :       bool showProgressIndicator = false,
      37             :       AnimationController progressIndicatorController,
      38             :       Color progressIndicatorBackgroundColor,
      39             :       Animation<Color> progressIndicatorValueColor,
      40             :       SnackPosition snackPosition = SnackPosition.BOTTOM,
      41             :       SnackStyle snackStyle = SnackStyle.FLOATING,
      42             :       Curve forwardAnimationCurve = Curves.easeOutCirc,
      43             :       Curve reverseAnimationCurve = Curves.easeOutCirc,
      44             :       Duration animationDuration = const Duration(seconds: 1),
      45             :       SnackStatusCallback onStatusChanged,
      46             :       double barBlur = 0.0,
      47             :       double overlayBlur = 0.0,
      48             :       Color overlayColor = Colors.transparent,
      49             :       Form userInputForm})
      50             :       : this.title = title,
      51             :         this.message = message,
      52             :         this.titleText = titleText,
      53             :         this.messageText = messageText,
      54             :         this.icon = icon,
      55             :         this.shouldIconPulse = shouldIconPulse,
      56             :         this.maxWidth = maxWidth,
      57             :         this.margin = margin,
      58             :         this.padding = padding,
      59             :         this.borderRadius = borderRadius,
      60             :         this.borderColor = borderColor,
      61             :         this.borderWidth = borderWidth,
      62             :         this.backgroundColor = backgroundColor,
      63             :         this.leftBarIndicatorColor = leftBarIndicatorColor,
      64             :         this.boxShadows = boxShadows,
      65             :         this.backgroundGradient = backgroundGradient,
      66             :         this.mainButton = mainButton,
      67             :         this.onTap = onTap,
      68             :         this.duration = duration,
      69             :         this.isDismissible = isDismissible,
      70             :         this.dismissDirection = dismissDirection,
      71             :         this.showProgressIndicator = showProgressIndicator,
      72             :         this.progressIndicatorController = progressIndicatorController,
      73             :         this.progressIndicatorBackgroundColor =
      74             :             progressIndicatorBackgroundColor,
      75             :         this.progressIndicatorValueColor = progressIndicatorValueColor,
      76             :         this.snackPosition = snackPosition,
      77             :         this.snackStyle = snackStyle,
      78             :         this.forwardAnimationCurve = forwardAnimationCurve,
      79             :         this.reverseAnimationCurve = reverseAnimationCurve,
      80             :         this.animationDuration = animationDuration,
      81             :         this.barBlur = barBlur,
      82             :         this.overlayBlur = overlayBlur,
      83             :         this.overlayColor = overlayColor,
      84             :         this.userInputForm = userInputForm,
      85           1 :         super(key: key) {
      86           2 :     this.onStatusChanged = onStatusChanged ?? (status) {};
      87             :   }
      88             : 
      89             :   /// A callback for you to listen to the different Snack status
      90             :   SnackStatusCallback onStatusChanged;
      91             : 
      92             :   /// The title displayed to the user
      93             :   final String title;
      94             : 
      95             :   /// The message displayed to the user.
      96             :   final String message;
      97             : 
      98             :   /// Replaces [title]. Although this accepts a [Widget], it is meant to receive [Text] or [RichText]
      99             :   final Widget titleText;
     100             : 
     101             :   /// Replaces [message]. Although this accepts a [Widget], it is meant to receive [Text] or  [RichText]
     102             :   final Widget messageText;
     103             : 
     104             :   /// Will be ignored if [backgroundGradient] is not null
     105             :   final Color backgroundColor;
     106             : 
     107             :   /// If not null, shows a left vertical colored bar on notification.
     108             :   /// It is not possible to use it with a [Form] and I do not recommend using it with [LinearProgressIndicator]
     109             :   final Color leftBarIndicatorColor;
     110             : 
     111             :   /// [boxShadows] The shadows generated by Snack. Leave it null if you don't want a shadow.
     112             :   /// You can use more than one if you feel the need.
     113             :   /// Check (this example)[https://github.com/flutter/flutter/blob/master/packages/flutter/lib/src/material/shadows.dart]
     114             :   final List<BoxShadow> boxShadows;
     115             : 
     116             :   /// Makes [backgroundColor] be ignored.
     117             :   final Gradient backgroundGradient;
     118             : 
     119             :   /// You can use any widget here, but I recommend [Icon] or [Image] as indication of what kind
     120             :   /// of message you are displaying. Other widgets may break the layout
     121             :   final Widget icon;
     122             : 
     123             :   /// An option to animate the icon (if present). Defaults to true.
     124             :   final bool shouldIconPulse;
     125             : 
     126             :   /// A [FlatButton] widget if you need an action from the user.
     127             :   final FlatButton mainButton;
     128             : 
     129             :   /// A callback that registers the user's click anywhere. An alternative to [mainButton]
     130             :   final OnTap onTap;
     131             : 
     132             :   /// How long until Snack will hide itself (be dismissed). To make it indefinite, leave it null.
     133             :   final Duration duration;
     134             : 
     135             :   /// True if you want to show a [LinearProgressIndicator].
     136             :   final bool showProgressIndicator;
     137             : 
     138             :   /// An optional [AnimationController] when you want to control the progress of your [LinearProgressIndicator].
     139             :   final AnimationController progressIndicatorController;
     140             : 
     141             :   /// A [LinearProgressIndicator] configuration parameter.
     142             :   final Color progressIndicatorBackgroundColor;
     143             : 
     144             :   /// A [LinearProgressIndicator] configuration parameter.
     145             :   final Animation<Color> progressIndicatorValueColor;
     146             : 
     147             :   /// Determines if the user can swipe or click the overlay (if [overlayBlur] > 0) to dismiss.
     148             :   /// It is recommended that you set [duration] != null if this is false.
     149             :   /// If the user swipes to dismiss or clicks the overlay, no value will be returned.
     150             :   final bool isDismissible;
     151             : 
     152             :   /// Used to limit Snack width (usually on large screens)
     153             :   final double maxWidth;
     154             : 
     155             :   /// Adds a custom margin to Snack
     156             :   final EdgeInsets margin;
     157             : 
     158             :   /// Adds a custom padding to Snack
     159             :   /// The default follows material design guide line
     160             :   final EdgeInsets padding;
     161             : 
     162             :   /// Adds a radius to all corners of Snack. Best combined with [margin].
     163             :   /// I do not recommend using it with [showProgressIndicator] or [leftBarIndicatorColor].
     164             :   final double borderRadius;
     165             : 
     166             :   /// Adds a border to every side of Snack
     167             :   /// I do not recommend using it with [showProgressIndicator] or [leftBarIndicatorColor].
     168             :   final Color borderColor;
     169             : 
     170             :   /// Changes the width of the border if [borderColor] is specified
     171             :   final double borderWidth;
     172             : 
     173             :   /// Snack can be based on [SnackPosition.TOP] or on [SnackPosition.BOTTOM] of your screen.
     174             :   /// [SnackPosition.BOTTOM] is the default.
     175             :   final SnackPosition snackPosition;
     176             : 
     177             :   /// [SnackDismissDirection.VERTICAL] by default.
     178             :   /// Can also be [SnackDismissDirection.HORIZONTAL] in which case both left and right dismiss are allowed.
     179             :   final SnackDismissDirection dismissDirection;
     180             : 
     181             :   /// Snack can be floating or be grounded to the edge of the screen.
     182             :   /// If grounded, I do not recommend using [margin] or [borderRadius]. [SnackStyle.FLOATING] is the default
     183             :   /// If grounded, I do not recommend using a [backgroundColor] with transparency or [barBlur]
     184             :   final SnackStyle snackStyle;
     185             : 
     186             :   /// The [Curve] animation used when show() is called. [Curves.easeOut] is default
     187             :   final Curve forwardAnimationCurve;
     188             : 
     189             :   /// The [Curve] animation used when dismiss() is called. [Curves.fastOutSlowIn] is default
     190             :   final Curve reverseAnimationCurve;
     191             : 
     192             :   /// Use it to speed up or slow down the animation duration
     193             :   final Duration animationDuration;
     194             : 
     195             :   /// Default is 0.0. If different than 0.0, blurs only Snack's background.
     196             :   /// To take effect, make sure your [backgroundColor] has some opacity.
     197             :   /// The greater the value, the greater the blur.
     198             :   final double barBlur;
     199             : 
     200             :   /// Default is 0.0. If different than 0.0, creates a blurred
     201             :   /// overlay that prevents the user from interacting with the screen.
     202             :   /// The greater the value, the greater the blur.
     203             :   final double overlayBlur;
     204             : 
     205             :   /// Default is [Colors.transparent]. Only takes effect if [overlayBlur] > 0.0.
     206             :   /// Make sure you use a color with transparency here e.g. Colors.grey[600].withOpacity(0.2).
     207             :   final Color overlayColor;
     208             : 
     209             :   /// A [TextFormField] in case you want a simple user input. Every other widget is ignored if this is not null.
     210             :   final Form userInputForm;
     211             : 
     212             :   snackroute.SnackRoute<T> _snackRoute;
     213             : 
     214             :   /// Show the snack. Kicks in [SnackStatus.IS_APPEARING] state followed by [SnackStatus.SHOWING]
     215           1 :   Future<T> show() async {
     216           2 :     _snackRoute = snackroute.showSnack<T>(
     217             :       snack: this,
     218             :     ) as SnackRoute<T>;
     219           6 :     return await Get.key.currentState.push(_snackRoute);
     220             :   }
     221             : 
     222             :   /// Dismisses the snack causing is to return a future containing [result].
     223             :   /// When this future finishes, it is guaranteed that Snack was dismissed.
     224           0 :   Future<T> dismiss([T result]) async {
     225             :     // If route was never initialized, do nothing
     226           0 :     if (_snackRoute == null) {
     227             :       return null;
     228             :     }
     229             : 
     230           0 :     if (_snackRoute.isCurrent) {
     231           0 :       _snackRoute.navigator.pop(result);
     232           0 :       return _snackRoute.completed;
     233           0 :     } else if (_snackRoute.isActive) {
     234             :       // removeRoute is called every time you dismiss a Snack that is not the top route.
     235             :       // It will not animate back and listeners will not detect SnackStatus.IS_HIDING or SnackStatus.DISMISSED
     236             :       // To avoid this, always make sure that Snack is the top route when it is being dismissed
     237           0 :       _snackRoute.navigator.removeRoute(_snackRoute);
     238             :     }
     239             : 
     240             :     return null;
     241             :   }
     242             : 
     243             :   /// Checks if the snack is visible
     244           0 :   bool isShowing() {
     245           0 :     return _snackRoute?.currentStatus == SnackStatus.SHOWING;
     246             :   }
     247             : 
     248             :   /// Checks if the snack is dismissed
     249           0 :   bool isDismissed() {
     250           0 :     return _snackRoute?.currentStatus == SnackStatus.DISMISSED;
     251             :   }
     252             : 
     253           0 :   @override
     254             :   State createState() {
     255           0 :     return _GetBarState<T>();
     256             :   }
     257             : }
     258             : 
     259             : class _GetBarState<K extends Object> extends State<GetBar>
     260             :     with TickerProviderStateMixin {
     261             :   SnackStatus currentStatus;
     262             : 
     263             :   AnimationController _fadeController;
     264             :   Animation<double> _fadeAnimation;
     265             : 
     266             :   final Widget _emptyWidget = SizedBox(width: 0.0, height: 0.0);
     267             :   final double _initialOpacity = 1.0;
     268             :   final double _finalOpacity = 0.4;
     269             : 
     270             :   final Duration _pulseAnimationDuration = Duration(seconds: 1);
     271             : 
     272             :   bool _isTitlePresent;
     273             :   double _messageTopMargin;
     274             : 
     275             :   FocusScopeNode _focusNode;
     276             :   FocusAttachment _focusAttachment;
     277             : 
     278           0 :   @override
     279             :   void initState() {
     280           0 :     super.initState();
     281             : 
     282             :     assert(
     283           0 :         ((widget.userInputForm != null ||
     284           0 :             ((widget.message != null && widget.message.isNotEmpty) ||
     285           0 :                 widget.messageText != null))),
     286             :         "A message is mandatory if you are not using userInputForm. Set either a message or messageText");
     287             : 
     288           0 :     _isTitlePresent = (widget.title != null || widget.titleText != null);
     289           0 :     _messageTopMargin = _isTitlePresent ? 6.0 : widget.padding.top;
     290             : 
     291           0 :     _configureLeftBarFuture();
     292           0 :     _configureProgressIndicatorAnimation();
     293             : 
     294           0 :     if (widget.icon != null && widget.shouldIconPulse) {
     295           0 :       _configurePulseAnimation();
     296           0 :       _fadeController?.forward();
     297             :     }
     298             : 
     299           0 :     _focusNode = FocusScopeNode();
     300           0 :     _focusAttachment = _focusNode.attach(context);
     301             :   }
     302             : 
     303           0 :   @override
     304             :   void dispose() {
     305           0 :     _fadeController?.dispose();
     306             : 
     307           0 :     widget.progressIndicatorController?.removeListener(_progressListener);
     308           0 :     widget.progressIndicatorController?.dispose();
     309             : 
     310           0 :     _focusAttachment.detach();
     311           0 :     _focusNode.dispose();
     312           0 :     super.dispose();
     313             :   }
     314             : 
     315             :   final Completer<Size> _boxHeightCompleter = Completer<Size>();
     316             : 
     317           0 :   void _configureLeftBarFuture() {
     318           0 :     SchedulerBinding.instance.addPostFrameCallback(
     319           0 :       (_) {
     320           0 :         final keyContext = backgroundBoxKey.currentContext;
     321             : 
     322             :         if (keyContext != null) {
     323           0 :           final RenderBox box = keyContext.findRenderObject();
     324           0 :           _boxHeightCompleter.complete(box.size);
     325             :         }
     326             :       },
     327             :     );
     328             :   }
     329             : 
     330           0 :   void _configurePulseAnimation() {
     331           0 :     _fadeController =
     332           0 :         AnimationController(vsync: this, duration: _pulseAnimationDuration);
     333           0 :     _fadeAnimation = Tween(begin: _initialOpacity, end: _finalOpacity).animate(
     334           0 :       CurvedAnimation(
     335           0 :         parent: _fadeController,
     336             :         curve: Curves.linear,
     337             :       ),
     338             :     );
     339             : 
     340           0 :     _fadeController.addStatusListener((status) {
     341           0 :       if (status == AnimationStatus.completed) {
     342           0 :         _fadeController.reverse();
     343             :       }
     344           0 :       if (status == AnimationStatus.dismissed) {
     345           0 :         _fadeController.forward();
     346             :       }
     347             :     });
     348             : 
     349           0 :     _fadeController.forward();
     350             :   }
     351             : 
     352             :   Function _progressListener;
     353             : 
     354           0 :   void _configureProgressIndicatorAnimation() {
     355           0 :     if (widget.showProgressIndicator &&
     356           0 :         widget.progressIndicatorController != null) {
     357           0 :       _progressListener = () {
     358           0 :         setState(() {});
     359             :       };
     360           0 :       widget.progressIndicatorController.addListener(_progressListener);
     361             : 
     362           0 :       _progressAnimation = CurvedAnimation(
     363           0 :           curve: Curves.linear, parent: widget.progressIndicatorController);
     364             :     }
     365             :   }
     366             : 
     367           0 :   @override
     368             :   Widget build(BuildContext context) {
     369           0 :     return Align(
     370             :       heightFactor: 1.0,
     371           0 :       child: Material(
     372           0 :         color: widget.snackStyle == SnackStyle.FLOATING
     373             :             ? Colors.transparent
     374           0 :             : widget.backgroundColor,
     375           0 :         child: SafeArea(
     376           0 :           minimum: widget.snackPosition == SnackPosition.BOTTOM
     377           0 :               ? EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom)
     378           0 :               : EdgeInsets.only(top: MediaQuery.of(context).padding.top),
     379           0 :           child: SafeArea(
     380           0 :             minimum: widget.snackPosition == SnackPosition.BOTTOM
     381           0 :                 ? EdgeInsets.only(
     382           0 :                     bottom: MediaQuery.of(context).viewInsets.bottom)
     383           0 :                 : EdgeInsets.only(top: MediaQuery.of(context).viewInsets.top),
     384           0 :             bottom: widget.snackPosition == SnackPosition.BOTTOM,
     385           0 :             top: widget.snackPosition == SnackPosition.TOP,
     386             :             left: false,
     387             :             right: false,
     388           0 :             child: _getSnack(),
     389             :           ),
     390             :         ),
     391             :       ),
     392             :     );
     393             :   }
     394             : 
     395           0 :   Widget _getSnack() {
     396             :     Widget snack;
     397             : 
     398           0 :     if (widget.userInputForm != null) {
     399           0 :       snack = _generateInputSnack();
     400             :     } else {
     401           0 :       snack = _generateSnack();
     402             :     }
     403             : 
     404           0 :     return Stack(
     405           0 :       children: [
     406           0 :         FutureBuilder(
     407           0 :           future: _boxHeightCompleter.future,
     408           0 :           builder: (context, AsyncSnapshot<Size> snapshot) {
     409           0 :             if (snapshot.hasData) {
     410           0 :               return ClipRRect(
     411           0 :                 borderRadius: BorderRadius.circular(widget.borderRadius),
     412           0 :                 child: BackdropFilter(
     413           0 :                   filter: ImageFilter.blur(
     414           0 :                       sigmaX: widget.barBlur, sigmaY: widget.barBlur),
     415           0 :                   child: Container(
     416           0 :                     height: snapshot.data.height,
     417           0 :                     width: snapshot.data.width,
     418           0 :                     decoration: BoxDecoration(
     419             :                       color: Colors.transparent,
     420           0 :                       borderRadius: BorderRadius.circular(widget.borderRadius),
     421             :                     ),
     422             :                   ),
     423             :                 ),
     424             :               );
     425             :             } else {
     426           0 :               return _emptyWidget;
     427             :             }
     428             :           },
     429             :         ),
     430             :         snack,
     431             :       ],
     432             :     );
     433             :   }
     434             : 
     435           0 :   Widget _generateInputSnack() {
     436           0 :     return Container(
     437           0 :       key: backgroundBoxKey,
     438           0 :       constraints: widget.maxWidth != null
     439           0 :           ? BoxConstraints(maxWidth: widget.maxWidth)
     440             :           : null,
     441           0 :       decoration: BoxDecoration(
     442           0 :         color: widget.backgroundColor,
     443           0 :         gradient: widget.backgroundGradient,
     444           0 :         boxShadow: widget.boxShadows,
     445           0 :         borderRadius: BorderRadius.circular(widget.borderRadius),
     446           0 :         border: widget.borderColor != null
     447           0 :             ? Border.all(color: widget.borderColor, width: widget.borderWidth)
     448             :             : null,
     449             :       ),
     450           0 :       child: Padding(
     451             :         padding: const EdgeInsets.only(
     452             :             left: 8.0, right: 8.0, bottom: 8.0, top: 16.0),
     453           0 :         child: FocusScope(
     454           0 :           child: widget.userInputForm,
     455           0 :           node: _focusNode,
     456             :           autofocus: true,
     457             :         ),
     458             :       ),
     459             :     );
     460             :   }
     461             : 
     462             :   CurvedAnimation _progressAnimation;
     463             :   GlobalKey backgroundBoxKey = GlobalKey();
     464             : 
     465           0 :   Widget _generateSnack() {
     466           0 :     return Container(
     467           0 :       key: backgroundBoxKey,
     468           0 :       constraints: widget.maxWidth != null
     469           0 :           ? BoxConstraints(maxWidth: widget.maxWidth)
     470             :           : null,
     471           0 :       decoration: BoxDecoration(
     472           0 :         color: widget.backgroundColor,
     473           0 :         gradient: widget.backgroundGradient,
     474           0 :         boxShadow: widget.boxShadows,
     475           0 :         borderRadius: BorderRadius.circular(widget.borderRadius),
     476           0 :         border: widget.borderColor != null
     477           0 :             ? Border.all(color: widget.borderColor, width: widget.borderWidth)
     478             :             : null,
     479             :       ),
     480           0 :       child: Column(
     481             :         mainAxisSize: MainAxisSize.min,
     482           0 :         children: [
     483           0 :           widget.showProgressIndicator
     484           0 :               ? LinearProgressIndicator(
     485           0 :                   value: widget.progressIndicatorController != null
     486           0 :                       ? _progressAnimation.value
     487             :                       : null,
     488           0 :                   backgroundColor: widget.progressIndicatorBackgroundColor,
     489           0 :                   valueColor: widget.progressIndicatorValueColor,
     490             :                 )
     491           0 :               : _emptyWidget,
     492           0 :           Row(
     493             :             mainAxisSize: MainAxisSize.max,
     494           0 :             children: _getAppropriateRowLayout(),
     495             :           ),
     496             :         ],
     497             :       ),
     498             :     );
     499             :   }
     500             : 
     501           0 :   List<Widget> _getAppropriateRowLayout() {
     502             :     double buttonRightPadding;
     503             :     double iconPadding = 0;
     504           0 :     if (widget.padding.right - 12 < 0) {
     505             :       buttonRightPadding = 4;
     506             :     } else {
     507           0 :       buttonRightPadding = widget.padding.right - 12;
     508             :     }
     509             : 
     510           0 :     if (widget.padding.left > 16.0) {
     511           0 :       iconPadding = widget.padding.left;
     512             :     }
     513             : 
     514           0 :     if (widget.icon == null && widget.mainButton == null) {
     515           0 :       return [
     516           0 :         _buildLeftBarIndicator(),
     517           0 :         Expanded(
     518             :           flex: 1,
     519           0 :           child: Column(
     520             :             crossAxisAlignment: CrossAxisAlignment.stretch,
     521             :             mainAxisSize: MainAxisSize.min,
     522           0 :             children: <Widget>[
     523           0 :               (_isTitlePresent)
     524           0 :                   ? Padding(
     525           0 :                       padding: EdgeInsets.only(
     526           0 :                         top: widget.padding.top,
     527           0 :                         left: widget.padding.left,
     528           0 :                         right: widget.padding.right,
     529             :                       ),
     530           0 :                       child: _getTitleText(),
     531             :                     )
     532           0 :                   : _emptyWidget,
     533           0 :               Padding(
     534           0 :                 padding: EdgeInsets.only(
     535           0 :                   top: _messageTopMargin,
     536           0 :                   left: widget.padding.left,
     537           0 :                   right: widget.padding.right,
     538           0 :                   bottom: widget.padding.bottom,
     539             :                 ),
     540           0 :                 child: widget.messageText ?? _getDefaultNotificationText(),
     541             :               ),
     542             :             ],
     543             :           ),
     544             :         ),
     545             :       ];
     546           0 :     } else if (widget.icon != null && widget.mainButton == null) {
     547           0 :       return <Widget>[
     548           0 :         _buildLeftBarIndicator(),
     549           0 :         ConstrainedBox(
     550           0 :           constraints: BoxConstraints.tightFor(width: 42.0 + iconPadding),
     551           0 :           child: _getIcon(),
     552             :         ),
     553           0 :         Expanded(
     554             :           flex: 1,
     555           0 :           child: Column(
     556             :             crossAxisAlignment: CrossAxisAlignment.stretch,
     557             :             mainAxisSize: MainAxisSize.min,
     558           0 :             children: <Widget>[
     559           0 :               (_isTitlePresent)
     560           0 :                   ? Padding(
     561           0 :                       padding: EdgeInsets.only(
     562           0 :                         top: widget.padding.top,
     563             :                         left: 4.0,
     564           0 :                         right: widget.padding.left,
     565             :                       ),
     566           0 :                       child: _getTitleText(),
     567             :                     )
     568           0 :                   : _emptyWidget,
     569           0 :               Padding(
     570           0 :                 padding: EdgeInsets.only(
     571           0 :                   top: _messageTopMargin,
     572             :                   left: 4.0,
     573           0 :                   right: widget.padding.right,
     574           0 :                   bottom: widget.padding.bottom,
     575             :                 ),
     576           0 :                 child: widget.messageText ?? _getDefaultNotificationText(),
     577             :               ),
     578             :             ],
     579             :           ),
     580             :         ),
     581             :       ];
     582           0 :     } else if (widget.icon == null && widget.mainButton != null) {
     583           0 :       return <Widget>[
     584           0 :         _buildLeftBarIndicator(),
     585           0 :         Expanded(
     586             :           flex: 1,
     587           0 :           child: Column(
     588             :             crossAxisAlignment: CrossAxisAlignment.stretch,
     589             :             mainAxisSize: MainAxisSize.min,
     590           0 :             children: <Widget>[
     591           0 :               (_isTitlePresent)
     592           0 :                   ? Padding(
     593           0 :                       padding: EdgeInsets.only(
     594           0 :                         top: widget.padding.top,
     595           0 :                         left: widget.padding.left,
     596           0 :                         right: widget.padding.right,
     597             :                       ),
     598           0 :                       child: _getTitleText(),
     599             :                     )
     600           0 :                   : _emptyWidget,
     601           0 :               Padding(
     602           0 :                 padding: EdgeInsets.only(
     603           0 :                   top: _messageTopMargin,
     604           0 :                   left: widget.padding.left,
     605             :                   right: 8.0,
     606           0 :                   bottom: widget.padding.bottom,
     607             :                 ),
     608           0 :                 child: widget.messageText ?? _getDefaultNotificationText(),
     609             :               ),
     610             :             ],
     611             :           ),
     612             :         ),
     613           0 :         Padding(
     614           0 :           padding: EdgeInsets.only(right: buttonRightPadding),
     615           0 :           child: _getMainActionButton(),
     616             :         ),
     617             :       ];
     618             :     } else {
     619           0 :       return <Widget>[
     620           0 :         _buildLeftBarIndicator(),
     621           0 :         ConstrainedBox(
     622           0 :           constraints: BoxConstraints.tightFor(width: 42.0 + iconPadding),
     623           0 :           child: _getIcon(),
     624             :         ),
     625           0 :         Expanded(
     626             :           flex: 1,
     627           0 :           child: Column(
     628             :             crossAxisAlignment: CrossAxisAlignment.stretch,
     629             :             mainAxisSize: MainAxisSize.min,
     630           0 :             children: <Widget>[
     631           0 :               (_isTitlePresent)
     632           0 :                   ? Padding(
     633           0 :                       padding: EdgeInsets.only(
     634           0 :                         top: widget.padding.top,
     635             :                         left: 4.0,
     636             :                         right: 8.0,
     637             :                       ),
     638           0 :                       child: _getTitleText(),
     639             :                     )
     640           0 :                   : _emptyWidget,
     641           0 :               Padding(
     642           0 :                 padding: EdgeInsets.only(
     643           0 :                   top: _messageTopMargin,
     644             :                   left: 4.0,
     645             :                   right: 8.0,
     646           0 :                   bottom: widget.padding.bottom,
     647             :                 ),
     648           0 :                 child: widget.messageText ?? _getDefaultNotificationText(),
     649             :               ),
     650             :             ],
     651             :           ),
     652             :         ),
     653           0 :         Padding(
     654           0 :               padding: EdgeInsets.only(right: buttonRightPadding),
     655           0 :               child: _getMainActionButton(),
     656             :             ) ??
     657           0 :             _emptyWidget,
     658             :       ];
     659             :     }
     660             :   }
     661             : 
     662           0 :   Widget _buildLeftBarIndicator() {
     663           0 :     if (widget.leftBarIndicatorColor != null) {
     664           0 :       return FutureBuilder(
     665           0 :         future: _boxHeightCompleter.future,
     666           0 :         builder: (BuildContext buildContext, AsyncSnapshot<Size> snapshot) {
     667           0 :           if (snapshot.hasData) {
     668           0 :             return Container(
     669           0 :               color: widget.leftBarIndicatorColor,
     670             :               width: 5.0,
     671           0 :               height: snapshot.data.height,
     672             :             );
     673             :           } else {
     674           0 :             return _emptyWidget;
     675             :           }
     676             :         },
     677             :       );
     678             :     } else {
     679           0 :       return _emptyWidget;
     680             :     }
     681             :   }
     682             : 
     683           0 :   Widget _getIcon() {
     684           0 :     if (widget.icon != null && widget.icon is Icon && widget.shouldIconPulse) {
     685           0 :       return FadeTransition(
     686           0 :         opacity: _fadeAnimation,
     687           0 :         child: widget.icon,
     688             :       );
     689           0 :     } else if (widget.icon != null) {
     690           0 :       return widget.icon;
     691             :     } else {
     692           0 :       return _emptyWidget;
     693             :     }
     694             :   }
     695             : 
     696           0 :   Widget _getTitleText() {
     697           0 :     return widget.titleText != null
     698           0 :         ? widget.titleText
     699           0 :         : Text(
     700           0 :             widget.title ?? "",
     701           0 :             style: TextStyle(
     702             :                 fontSize: 16.0,
     703             :                 color: Colors.white,
     704             :                 fontWeight: FontWeight.bold),
     705             :           );
     706             :   }
     707             : 
     708           0 :   Text _getDefaultNotificationText() {
     709           0 :     return Text(
     710           0 :       widget.message ?? "",
     711           0 :       style: TextStyle(fontSize: 14.0, color: Colors.white),
     712             :     );
     713             :   }
     714             : 
     715           0 :   FlatButton _getMainActionButton() {
     716           0 :     if (widget.mainButton != null) {
     717           0 :       return widget.mainButton;
     718             :     } else {
     719             :       return null;
     720             :     }
     721             :   }
     722             : }
     723             : 
     724             : /// Indicates if snack is going to start at the [TOP] or at the [BOTTOM]
     725          36 : enum SnackPosition { TOP, BOTTOM }
     726             : 
     727             : /// Indicates if snack will be attached to the edge of the screen or not
     728          36 : enum SnackStyle { FLOATING, GROUNDED }
     729             : 
     730             : /// Indicates the direction in which it is possible to dismiss
     731             : /// If vertical, dismiss up will be allowed if [SnackPosition.TOP]
     732             : /// If vertical, dismiss down will be allowed if [SnackPosition.BOTTOM]
     733          36 : enum SnackDismissDirection { HORIZONTAL, VERTICAL }
     734             : 
     735             : /// Indicates the animation status
     736             : /// [SnackStatus.SHOWING] Snack has stopped and the user can see it
     737             : /// [SnackStatus.DISMISSED] Snack has finished its mission and returned any pending values
     738             : /// [SnackStatus.IS_APPEARING] Snack is moving towards [SnackStatus.SHOWING]
     739             : /// [SnackStatus.IS_HIDING] Snack is moving towards [] [SnackStatus.DISMISSED]
     740          60 : enum SnackStatus { SHOWING, DISMISSED, IS_APPEARING, IS_HIDING }

Generated by: LCOV version 1.14