LCOV - code coverage report
Current view: top level - lib/src/effects - effects.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 78 86 90.7 %
Date: 2021-08-10 15:50:53 Functions: 0 0 -

          Line data    Source code
       1             : import 'package:flutter/material.dart';
       2             : 
       3             : import '../components/base_component.dart';
       4             : import '../components/position_component.dart';
       5             : import '../extensions/vector2.dart';
       6             : 
       7             : export './color_effect.dart';
       8             : export './move_effect.dart';
       9             : export './opacity_effect.dart';
      10             : export './rotate_effect.dart';
      11             : export './sequence_effect.dart';
      12             : export './size_effect.dart';
      13             : 
      14             : abstract class ComponentEffect<T extends BaseComponent> {
      15             :   T? component;
      16             :   Function()? onComplete;
      17             : 
      18             :   bool _isDisposed = false;
      19          14 :   bool get isDisposed => _isDisposed;
      20             : 
      21             :   bool _isPaused = false;
      22          14 :   bool get isPaused => _isPaused;
      23           0 :   void resume() => _isPaused = false;
      24           0 :   void pause() => _isPaused = true;
      25             : 
      26             :   /// If the animation should first follow the initial curve and then follow the
      27             :   /// curve backwards
      28             :   bool isInfinite;
      29             :   bool isAlternating;
      30             :   final bool isRelative;
      31             :   final bool _initialIsInfinite;
      32             :   final bool _initialIsAlternating;
      33             :   double? percentage;
      34             :   double curveProgress = 0.0;
      35             :   double peakTime = 0.0;
      36             :   double currentTime = 0.0;
      37             :   double driftTime = 0.0;
      38             :   int curveDirection = 1;
      39             :   Curve curve;
      40             : 
      41             :   /// If this is set to true the effect will not be set to its original state
      42             :   /// once it is done.
      43             :   bool skipEffectReset = false;
      44             : 
      45          24 :   double get iterationTime => peakTime * (isAlternating ? 2 : 1);
      46             : 
      47           7 :   ComponentEffect(
      48             :     this._initialIsInfinite,
      49             :     this._initialIsAlternating, {
      50             :     this.isRelative = false,
      51             :     Curve? curve,
      52             :     this.onComplete,
      53             :   })  : isInfinite = _initialIsInfinite,
      54             :         isAlternating = _initialIsAlternating,
      55             :         curve = curve ?? Curves.linear;
      56             : 
      57           7 :   @mustCallSuper
      58             :   void update(double dt) {
      59           7 :     if (isAlternating) {
      60          28 :       curveDirection = isMax() ? -1 : (isMin() ? 1 : curveDirection);
      61             :     }
      62           7 :     if (isInfinite) {
      63          24 :       if ((!isAlternating && isMax()) || (isAlternating && isMin())) {
      64           6 :         reset();
      65             :       }
      66             :     }
      67           7 :     if (!hasCompleted()) {
      68          42 :       currentTime += (dt + driftTime) * curveDirection;
      69          42 :       percentage = (currentTime / peakTime).clamp(0.0, 1.0).toDouble();
      70          28 :       curveProgress = curve.transform(percentage!);
      71           7 :       _updateDriftTime();
      72          35 :       currentTime = currentTime.clamp(0.0, peakTime).toDouble();
      73             :     }
      74             :   }
      75             : 
      76           7 :   @mustCallSuper
      77             :   void initialize(T component) {
      78           7 :     this.component = component;
      79             :   }
      80             : 
      81           0 :   void dispose() => _isDisposed = true;
      82             : 
      83             :   /// Whether the effect has completed or not.
      84           7 :   bool hasCompleted() {
      85          21 :     return (!isInfinite && !isAlternating && isMax()) ||
      86          20 :         (!isInfinite && isAlternating && isMin()) ||
      87           7 :         isDisposed;
      88             :   }
      89             : 
      90          28 :   bool isMax() => percentage == null ? false : percentage == 1.0;
      91          28 :   bool isMin() => percentage == null ? false : percentage == 0.0;
      92          30 :   bool isRootEffect() => component?.effects.contains(this) == true;
      93             : 
      94             :   /// Resets the effect and the component which the effect was added to.
      95           6 :   void reset() {
      96           6 :     resetEffect();
      97           6 :     setComponentToOriginalState();
      98             :   }
      99             : 
     100             :   /// Resets the effect to its original state so that it can be re-run.
     101           6 :   void resetEffect() {
     102           6 :     _isDisposed = false;
     103           6 :     percentage = null;
     104           6 :     currentTime = 0.0;
     105           6 :     curveDirection = 1;
     106          12 :     isInfinite = _initialIsInfinite;
     107          12 :     isAlternating = _initialIsAlternating;
     108             :   }
     109             : 
     110             :   // When the time overshoots the max and min it needs to add that time to
     111             :   // whatever is going to happen next, for example an alternation or
     112             :   // following effect in a SequenceEffect.
     113           7 :   void _updateDriftTime() {
     114           7 :     if (isMax()) {
     115          24 :       driftTime = currentTime - peakTime;
     116           7 :     } else if (isMin()) {
     117          18 :       driftTime = currentTime.abs();
     118             :     } else {
     119           7 :       driftTime = 0;
     120             :     }
     121             :   }
     122             : 
     123             :   /// Called when the effect is removed from the component.
     124             :   /// Calls the [onComplete] callback if it is defined and sets the effect back
     125             :   /// to its original state so that it can be re-added.
     126           6 :   void onRemove() {
     127          12 :     onComplete?.call();
     128           6 :     if (!skipEffectReset) {
     129           0 :       resetEffect();
     130             :     }
     131             :   }
     132             : 
     133             :   void setComponentToOriginalState();
     134             :   void setComponentToEndState();
     135             : }
     136             : 
     137             : abstract class PositionComponentEffect
     138             :     extends ComponentEffect<PositionComponent> {
     139             :   /// Used to be able to determine the start state of the component
     140             :   Vector2? originalPosition;
     141             :   double? originalAngle;
     142             :   Vector2? originalSize;
     143             :   Vector2? originalScale;
     144             : 
     145             :   /// Used to be able to determine the end state of a sequence of effects
     146             :   Vector2? endPosition;
     147             :   double? endAngle;
     148             :   Vector2? endSize;
     149             :   Vector2? endScale;
     150             : 
     151             :   /// Whether the state of a certain field was modified by the effect
     152             :   final bool modifiesPosition;
     153             :   final bool modifiesAngle;
     154             :   final bool modifiesSize;
     155             :   final bool modifiesScale;
     156             : 
     157           6 :   PositionComponentEffect(
     158             :     bool initialIsInfinite,
     159             :     bool initialIsAlternating, {
     160             :     bool isRelative = false,
     161             :     Curve? curve,
     162             :     this.modifiesPosition = false,
     163             :     this.modifiesAngle = false,
     164             :     this.modifiesSize = false,
     165             :     this.modifiesScale = false,
     166             :     VoidCallback? onComplete,
     167           6 :   }) : super(
     168             :           initialIsInfinite,
     169             :           initialIsAlternating,
     170             :           isRelative: isRelative,
     171             :           curve: curve,
     172             :           onComplete: onComplete,
     173             :         );
     174             : 
     175           6 :   @mustCallSuper
     176             :   @override
     177             :   void initialize(PositionComponent component) {
     178           6 :     super.initialize(component);
     179           6 :     this.component = component;
     180          18 :     originalPosition = component.position.clone();
     181          12 :     originalAngle = component.angle;
     182          18 :     originalSize = component.size.clone();
     183          18 :     originalScale = component.scale.clone();
     184             : 
     185             :     /// If these aren't modified by the extending effect it is assumed that the
     186             :     /// effect didn't bring the component to another state than the one it
     187             :     /// started in
     188          18 :     endPosition = component.position.clone();
     189          12 :     endAngle = component.angle;
     190          18 :     endSize = component.size.clone();
     191          18 :     endScale = component.scale.clone();
     192             :   }
     193             : 
     194             :   /// Only change the parts of the component that is affected by the
     195             :   /// effect, and only set the state if it is the root effect (not part of
     196             :   /// another effect, like children of a CombinedEffect or SequenceEffect).
     197           6 :   void _setComponentState(
     198             :     Vector2? position,
     199             :     double? angle,
     200             :     Vector2? size,
     201             :     Vector2? scale,
     202             :   ) {
     203           6 :     if (isRootEffect()) {
     204           6 :       if (modifiesPosition) {
     205             :         assert(
     206           0 :           position != null,
     207             :           '`position` must not be `null` for an effect which modifies `position`',
     208             :         );
     209           9 :         component?.position.setFrom(position!);
     210             :       }
     211           6 :       if (modifiesAngle) {
     212             :         assert(
     213           0 :           angle != null,
     214             :           '`angle` must not be `null` for an effect which modifies `angle`',
     215             :         );
     216           6 :         component?.angle = angle!;
     217             :       }
     218           6 :       if (modifiesSize) {
     219             :         assert(
     220           0 :           size != null,
     221             :           '`size` must not be `null` for an effect which modifies `size`',
     222             :         );
     223           9 :         component?.size.setFrom(size!);
     224             :       }
     225           6 :       if (modifiesScale) {
     226             :         assert(
     227           0 :           scale != null,
     228             :           '`scale` must not be `null` for an effect which modifies `scale`',
     229             :         );
     230           3 :         component?.scale.setFrom(scale!);
     231             :       }
     232             :     }
     233             :   }
     234             : 
     235           6 :   @override
     236             :   void setComponentToOriginalState() {
     237           6 :     _setComponentState(
     238           6 :       originalPosition,
     239           6 :       originalAngle,
     240           6 :       originalSize,
     241           6 :       originalScale,
     242             :     );
     243             :   }
     244             : 
     245           6 :   @override
     246             :   void setComponentToEndState() {
     247          30 :     _setComponentState(endPosition, endAngle, endSize, endScale);
     248             :   }
     249             : }
     250             : 
     251             : abstract class SimplePositionComponentEffect extends PositionComponentEffect {
     252             :   double? duration;
     253             :   double? speed;
     254             : 
     255           6 :   SimplePositionComponentEffect(
     256             :     bool initialIsInfinite,
     257             :     bool initialIsAlternating, {
     258             :     this.duration,
     259             :     this.speed,
     260             :     Curve? curve,
     261             :     bool isRelative = false,
     262             :     bool modifiesPosition = false,
     263             :     bool modifiesAngle = false,
     264             :     bool modifiesSize = false,
     265             :     bool modifiesScale = false,
     266             :     VoidCallback? onComplete,
     267             :   })  : assert(
     268           6 :           (duration != null) ^ (speed != null),
     269             :           'Either speed or duration necessary',
     270             :         ),
     271           6 :         super(
     272             :           initialIsInfinite,
     273             :           initialIsAlternating,
     274             :           isRelative: isRelative,
     275             :           curve: curve,
     276             :           modifiesPosition: modifiesPosition,
     277             :           modifiesAngle: modifiesAngle,
     278             :           modifiesSize: modifiesSize,
     279             :           modifiesScale: modifiesScale,
     280             :           onComplete: onComplete,
     281             :         );
     282             : }

Generated by: LCOV version 1.15