blob: f4179e95ac770b515ba3487261be9e1cefff3b19 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'animated_value.dart';
import 'curves.dart';
// TODO(mpcomplete): merge this stuff with AnimatedValue somehow. We shouldn't
// have 2 different ways to animate values.
abstract class AnimatedVariable {
void setFraction(double t);
}
class AnimatedType<T extends dynamic> extends AnimatedVariable {
T value;
final T begin, end;
final Curve curve;
AnimatedType(this.begin, this.end, {this.curve: linear}) {
value = begin;
}
void setFraction(double t) {
// TODO(mpcomplete): Reverse the timeline and curve.
value = begin + (end - begin) * curve.transform(t);
}
}
// This class manages a "performance" - a collection of values that change
// based on a timeline. For example, a performance may handle an animation
// of a menu opening by sliding and fading in (changing Y value and opacity)
// over .5 seconds. The performance can move forwards (present) or backwards
// (dismiss). A consumer may also take direct control of the timeline by
// manipulating |progress|, or |fling| the timeline causing a physics-based
// simulation to take over the progression.
class AnimationPerformance {
// TODO(mpcomplete): make this a list, or composable somehow.
AnimatedVariable variable;
// Advances from 0 to 1. On each tick, we'll update our variable's values.
AnimatedValue timeline = new AnimatedValue(0.0);
// TODO(mpcomplete): duration should be on a director.
Duration duration;
AnimationPerformance() {
timeline.onValueChanged.listen((double t) {
variable.setFraction(t);
});
}
double get progress => timeline.value;
void set progress(double t) {
stop();
timeline.value = t.clamp(0.0, 1.0);
}
bool get isDismissed => progress == 0.0;
bool get isCompleted => progress == 1.0;
bool get isAnimating => timeline.isAnimating;
void play() {
_animateTo(1.0);
}
void reverse() {
_animateTo(0.0);
}
void _animateTo(double target) {
double remainingDistance = (target - timeline.value).abs();
timeline.stop();
if (remainingDistance != 0.0)
timeline.animateTo(target, remainingDistance * duration.inMilliseconds);
}
void stop() {
timeline.stop();
}
// Resume animating in a direction, with the given velocity.
// TODO(mpcomplete): this should be a force with friction so it slows over
// time.
void fling({double velocity: 1.0}) {
double target = velocity.sign < 0.0 ? 0.0 : 1.0;
double distance = (target - timeline.value).abs();
double duration = distance / velocity.abs();
if (distance > 0.0)
timeline.animateTo(target, duration, curve: linear);
}
}