advance method

bool advance(
  1. double elapsedSeconds,
  2. {KeyedCallbackReporter? callbackReporter}
)

Implementation

bool advance(double elapsedSeconds,
    {KeyedCallbackReporter? callbackReporter}) {
  var deltaSeconds = elapsedSeconds * animation.speed * _direction;
  _spilledTime = 0;

  if (deltaSeconds == 0) {
    _didLoop = false;
    return true;
  }
  _lastTotalTime = _totalTime;
  _totalTime += deltaSeconds.abs();

  // NOTE:
  // do not track spilled time, if our one shot loop is already completed.
  // stop gap before we move spilled tracking into state machine logic.
  var killSpilledTime = !keepGoing;

  var lastTime = _time;
  _time += deltaSeconds;

  if (callbackReporter != null) {
    animation.reportKeyedCallbacks(
      lastTime,
      _time,
      reporter: callbackReporter,
    );
  }

  var fps = animation.fps;
  double frames = _time * fps;

  var start = animation.enableWorkArea ? animation.workStart : 0;
  var end = animation.enableWorkArea ? animation.workEnd : animation.duration;
  var range = end - start;

  bool didLoop = false;

  int direction = deltaSeconds < 0 ? -1 : 1;
  switch (animation.loop) {
    case Loop.oneShot:
      if (direction == 1 && frames > end) {
        _spilledTime = (frames - end) / fps;
        frames = end.toDouble();
        _time = frames / fps;
        didLoop = true;
      } else if (direction == -1 && frames < start) {
        _spilledTime = (start - frames) / fps;
        frames = start.toDouble();
        _time = frames / fps;
        didLoop = true;
      }
      break;
    case Loop.loop:
      if (direction == 1 && frames >= end) {
        _spilledTime = (frames - end) / fps;
        frames = _time * fps;
        frames = start + (frames - start) % range;
        lastTime = 0;
        _time = frames / fps;
        if (callbackReporter != null) {
          animation.reportKeyedCallbacks(
            lastTime,
            _time,
            reporter: callbackReporter,
          );
        }
        didLoop = true;
      } else if (direction == -1 && frames <= start) {
        _spilledTime = (start - frames) / fps;
        frames = _time * fps;
        frames = end - (start - frames) % range;
        lastTime = end / fps;
        _time = frames / fps;
        if (callbackReporter != null) {
          animation.reportKeyedCallbacks(
            lastTime,
            _time,
            reporter: callbackReporter,
          );
        }
        didLoop = true;
      }
      break;
    case Loop.pingPong:
      // ignore: literal_only_boolean_expressions
      while (true) {
        if (direction == 1 && frames >= end) {
          _spilledTime = (frames - end) / animation.fps;
          lastTime = end / fps;
          frames = end + (end - frames);
        } else if (direction == -1 && frames < start) {
          _spilledTime = (start - frames) / animation.fps;
          lastTime = start / fps;
          frames = start + (start - frames);
        } else {
          // we're within the range, we can stop fixing. We do this in a
          // loop to fix conditions when time has advanced so far that we've
          // ping-ponged back and forth a few times in a single frame. We
          // want to accomodate for this in cases where animations are not
          // advanced on regular intervals.
          break;
        }
        _time = frames / animation.fps;
        _direction *= -1;
        direction *= -1;
        didLoop = true;
        if (callbackReporter != null) {
          animation.reportKeyedCallbacks(
            lastTime,
            _time,
            reporter: callbackReporter,
          );
        }
      }
      break;
  }

  if (killSpilledTime) {
    _spilledTime = 0;
  }

  _didLoop = didLoop;
  return keepGoing;
}