LCOV - code coverage report
Current view: top level - src/snackbar - snack_route.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 90 144 62.5 %
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:get/src/snackbar/snack.dart';
       5             : 
       6             : class SnackRoute<T> extends OverlayRoute<T> {
       7             :   final GetBar snack;
       8             :   final Builder _builder;
       9             :   final Completer<T> _transitionCompleter = Completer<T>();
      10             :   final SnackStatusCallback _onStatusChanged;
      11             :   Alignment _initialAlignment;
      12             :   Alignment _endAlignment;
      13             :   bool _wasDismissedBySwipe = false;
      14             :   Timer _timer;
      15             :   T _result;
      16             :   SnackStatus currentStatus;
      17             : 
      18           1 :   SnackRoute({
      19             :     @required this.snack,
      20             :     RouteSettings settings,
      21           1 :   })  : _builder = Builder(builder: (BuildContext innerContext) {
      22           0 :           return GestureDetector(
      23             :             child: snack,
      24           0 :             onTap: snack.onTap != null ? () => snack.onTap(snack) : null,
      25             :           );
      26             :         }),
      27           1 :         _onStatusChanged = snack.onStatusChanged,
      28           1 :         super(settings: settings) {
      29           3 :     _configureAlignment(this.snack.snackPosition);
      30             :   }
      31             : 
      32           1 :   void _configureAlignment(SnackPosition snackPosition) {
      33           2 :     switch (snack.snackPosition) {
      34           1 :       case SnackPosition.TOP:
      35             :         {
      36           4 :           _initialAlignment = Alignment(-1.0, -2.0);
      37           4 :           _endAlignment = Alignment(-1.0, -1.0);
      38             :           break;
      39             :         }
      40           1 :       case SnackPosition.BOTTOM:
      41             :         {
      42           3 :           _initialAlignment = Alignment(-1.0, 2.0);
      43           3 :           _endAlignment = Alignment(-1.0, 1.0);
      44             :           break;
      45             :         }
      46             :     }
      47             :   }
      48             : 
      49           0 :   Future<T> get completed => _transitionCompleter.future;
      50           1 :   bool get opaque => false;
      51             : 
      52           1 :   @override
      53             :   Iterable<OverlayEntry> createOverlayEntries() {
      54           1 :     final List<OverlayEntry> overlays = [];
      55             : 
      56           1 :     overlays.add(
      57           1 :       OverlayEntry(
      58           0 :           builder: (BuildContext context) {
      59           0 :             final Widget annotatedChild = Semantics(
      60           0 :               child: AlignTransition(
      61           0 :                 alignment: _animation,
      62           0 :                 child: _getSnack(),
      63             :               ),
      64             :               focused: false,
      65             :               container: true,
      66             :               explicitChildNodes: true,
      67             :             );
      68             :             return annotatedChild;
      69             :           },
      70             :           maintainState: false,
      71           1 :           opaque: opaque),
      72             :     );
      73             : 
      74             :     return overlays;
      75             :   }
      76             : 
      77             :   /// This string is a workaround until Dismissible supports a returning item
      78             :   String dismissibleKeyGen = "";
      79             : 
      80           0 :   Widget _getSnack() {
      81           0 :     return Container(
      82           0 :       margin: snack.margin,
      83           0 :       child: _builder,
      84             :     );
      85             :   }
      86             : 
      87           1 :   @override
      88             :   bool get finishedWhenPopped =>
      89           3 :       _controller.status == AnimationStatus.dismissed;
      90             : 
      91             :   /// The animation that drives the route's transition and the previous route's
      92             :   /// forward transition.
      93           0 :   Animation<Alignment> get animation => _animation;
      94             :   Animation<Alignment> _animation;
      95             : 
      96             :   /// The animation controller that the route uses to drive the transitions.
      97             :   ///
      98             :   /// The animation itself is exposed by the [animation] property.
      99           0 :   @protected
     100           0 :   AnimationController get controller => _controller;
     101             :   AnimationController _controller;
     102             : 
     103             :   /// Called to create the animation controller that will drive the transitions to
     104             :   /// this route from the previous one, and back to the previous route from this
     105             :   /// one.
     106           1 :   AnimationController createAnimationController() {
     107           2 :     assert(!_transitionCompleter.isCompleted,
     108           0 :         'Cannot reuse a $runtimeType after disposing it.');
     109           2 :     assert(snack.animationDuration != null &&
     110           3 :         snack.animationDuration >= Duration.zero);
     111           1 :     return AnimationController(
     112           2 :       duration: snack.animationDuration,
     113           1 :       debugLabel: debugLabel,
     114           1 :       vsync: navigator,
     115             :     );
     116             :   }
     117             : 
     118             :   /// Called to create the animation that exposes the current progress of
     119             :   /// the transition controlled by the animation controller created by
     120             :   /// [createAnimationController()].
     121           1 :   Animation<Alignment> createAnimation() {
     122           2 :     assert(!_transitionCompleter.isCompleted,
     123           0 :         'Cannot reuse a $runtimeType after disposing it.');
     124           1 :     assert(_controller != null);
     125           4 :     return AlignmentTween(begin: _initialAlignment, end: _endAlignment).animate(
     126           1 :       CurvedAnimation(
     127           1 :         parent: _controller,
     128           2 :         curve: snack.forwardAnimationCurve,
     129           2 :         reverseCurve: snack.reverseAnimationCurve,
     130             :       ),
     131             :     );
     132             :   }
     133             : 
     134           0 :   Animation<double> createBlurFilterAnimation() {
     135           0 :     if (snack.overlayBlur == null) return null;
     136             : 
     137           0 :     return Tween(begin: 0.0, end: snack.overlayBlur).animate(
     138           0 :       CurvedAnimation(
     139           0 :         parent: _controller,
     140           0 :         curve: Interval(
     141             :           0.0,
     142             :           0.35,
     143             :           curve: Curves.easeInOutCirc,
     144             :         ),
     145             :       ),
     146             :     );
     147             :   }
     148             : 
     149           0 :   Animation<Color> createColorFilterAnimation() {
     150           0 :     if (snack.overlayColor == null) return null;
     151             : 
     152           0 :     return ColorTween(begin: Colors.transparent, end: snack.overlayColor)
     153           0 :         .animate(
     154           0 :       CurvedAnimation(
     155           0 :         parent: _controller,
     156           0 :         curve: Interval(
     157             :           0.0,
     158             :           0.35,
     159             :           curve: Curves.easeInOutCirc,
     160             :         ),
     161             :       ),
     162             :     );
     163             :   }
     164             : 
     165             :   //copy of `routes.dart`
     166           1 :   void _handleStatusChanged(AnimationStatus status) {
     167             :     switch (status) {
     168           1 :       case AnimationStatus.completed:
     169           0 :         currentStatus = SnackStatus.SHOWING;
     170           0 :         _onStatusChanged(currentStatus);
     171           0 :         if (overlayEntries.isNotEmpty) overlayEntries.first.opaque = opaque;
     172             : 
     173             :         break;
     174           1 :       case AnimationStatus.forward:
     175           1 :         currentStatus = SnackStatus.IS_APPEARING;
     176           3 :         _onStatusChanged(currentStatus);
     177             :         break;
     178           1 :       case AnimationStatus.reverse:
     179           0 :         currentStatus = SnackStatus.IS_HIDING;
     180           0 :         _onStatusChanged(currentStatus);
     181           0 :         if (overlayEntries.isNotEmpty) overlayEntries.first.opaque = false;
     182             :         break;
     183           1 :       case AnimationStatus.dismissed:
     184           3 :         assert(!overlayEntries.first.opaque);
     185             :         // We might still be the current route if a subclass is controlling the
     186             :         // the transition and hits the dismissed status. For example, the iOS
     187             :         // back gesture drives this animation to the dismissed status before
     188             :         // popping the navigator.
     189           1 :         currentStatus = SnackStatus.DISMISSED;
     190           3 :         _onStatusChanged(currentStatus);
     191             : 
     192           1 :         if (!isCurrent) {
     193           0 :           navigator.finalizeRoute(this);
     194           0 :           assert(overlayEntries.isEmpty);
     195             :         }
     196             :         break;
     197             :     }
     198           1 :     changedInternalState();
     199             :   }
     200             : 
     201           1 :   @override
     202             :   void install() {
     203           2 :     assert(!_transitionCompleter.isCompleted,
     204           0 :         'Cannot install a $runtimeType after disposing it.');
     205           2 :     _controller = createAnimationController();
     206           1 :     assert(_controller != null,
     207           0 :         '$runtimeType.createAnimationController() returned null.');
     208           2 :     _animation = createAnimation();
     209           1 :     assert(_animation != null, '$runtimeType.createAnimation() returned null.');
     210           1 :     super.install();
     211             :   }
     212             : 
     213           1 :   @override
     214             :   TickerFuture didPush() {
     215           1 :     assert(_controller != null,
     216           0 :         '$runtimeType.didPush called before calling install() or after calling dispose().');
     217           2 :     assert(!_transitionCompleter.isCompleted,
     218           0 :         'Cannot reuse a $runtimeType after disposing it.');
     219           3 :     _animation.addStatusListener(_handleStatusChanged);
     220           1 :     _configureTimer();
     221           1 :     super.didPush();
     222           2 :     return _controller.forward();
     223             :   }
     224             : 
     225           1 :   @override
     226             :   bool didPop(T result) {
     227           1 :     assert(_controller != null,
     228           0 :         '$runtimeType.didPop called before calling install() or after calling dispose().');
     229           2 :     assert(!_transitionCompleter.isCompleted,
     230           0 :         'Cannot reuse a $runtimeType after disposing it.');
     231             : 
     232           1 :     _result = result;
     233           1 :     _cancelTimer();
     234             : 
     235           1 :     if (_wasDismissedBySwipe) {
     236           0 :       Timer(Duration(milliseconds: 200), () {
     237           0 :         _controller.reset();
     238             :       });
     239             : 
     240           0 :       _wasDismissedBySwipe = false;
     241             :     } else {
     242           2 :       _controller.reverse();
     243             :     }
     244             : 
     245           1 :     return super.didPop(result);
     246             :   }
     247             : 
     248           1 :   void _configureTimer() {
     249           2 :     if (snack.duration != null) {
     250           1 :       if (_timer != null && _timer.isActive) {
     251           0 :         _timer.cancel();
     252             :       }
     253           5 :       _timer = Timer(snack.duration, () {
     254           1 :         if (this.isCurrent) {
     255           2 :           navigator.pop();
     256           0 :         } else if (this.isActive) {
     257           0 :           navigator.removeRoute(this);
     258             :         }
     259             :       });
     260             :     } else {
     261           0 :       if (_timer != null) {
     262           0 :         _timer.cancel();
     263             :       }
     264             :     }
     265             :   }
     266             : 
     267           1 :   void _cancelTimer() {
     268           3 :     if (_timer != null && _timer.isActive) {
     269           0 :       _timer.cancel();
     270             :     }
     271             :   }
     272             : 
     273           1 :   @override
     274             :   void dispose() {
     275           2 :     assert(!_transitionCompleter.isCompleted,
     276           0 :         'Cannot dispose a $runtimeType twice.');
     277           2 :     _controller?.dispose();
     278           3 :     _transitionCompleter.complete(_result);
     279           1 :     super.dispose();
     280             :   }
     281             : 
     282             :   /// A short description of this route useful for debugging.
     283           3 :   String get debugLabel => '$runtimeType';
     284             : 
     285           1 :   @override
     286           3 :   String toString() => '$runtimeType(animation: $_controller)';
     287             : }
     288             : 
     289           1 : SnackRoute showSnack<T>({@required GetBar snack}) {
     290           1 :   return SnackRoute<T>(
     291             :     snack: snack,
     292           1 :     settings: RouteSettings(name: 'snackbar'),
     293             :   );
     294             : }

Generated by: LCOV version 1.14