Commit b6cf053e authored by Ian Hickson's avatar Ian Hickson

Merge pull request #752 from Hixie/yak3-remove-timing

Replace AnimationTiming with CurvedPerformance
parents 88fbf76e 379b6a50
...@@ -20,16 +20,28 @@ enum AnimationDirection { ...@@ -20,16 +20,28 @@ enum AnimationDirection {
/// Animatable objects, by convention, must be cheap to create. This allows them /// Animatable objects, by convention, must be cheap to create. This allows them
/// to be used in build functions in Widgets. /// to be used in build functions in Widgets.
abstract class Animatable { abstract class Animatable {
// TODO(ianh): replace mentions of this class with just mentioning AnimatedValue directly
/// Update the variable to a given time in an animation that is running in the given direction /// Update the variable to a given time in an animation that is running in the given direction
void setProgress(double t, AnimationDirection direction); void setProgress(double t, AnimationDirection direction);
String toString();
} }
/// Used by [Performance] to convert the timing of a performance to a different timescale. /// An animated variable with a concrete type.
/// For example, by setting different values for the interval and reverseInterval, a performance class AnimatedValue<T extends dynamic> implements Animatable {
/// can be made to take longer in one direction that the other. AnimatedValue(this.begin, { this.end, this.curve, this.reverseCurve }) {
class AnimationTiming { value = begin;
AnimationTiming({ this.curve, this.reverseCurve }); }
/// The current value of this variable.
T value;
/// The value this variable has at the beginning of the animation.
T begin;
/// The value this variable has at the end of the animation.
T end;
/// Returns the value this variable has at the given animation clock value.
T lerp(double t) => begin + (end - begin) * t;
/// The curve to use in the forward direction /// The curve to use in the forward direction
Curve curve; Curve curve;
...@@ -39,6 +51,12 @@ class AnimationTiming { ...@@ -39,6 +51,12 @@ class AnimationTiming {
/// If this field is null, use [curve] in both directions. /// If this field is null, use [curve] in both directions.
Curve reverseCurve; Curve reverseCurve;
Curve _getActiveCurve(AnimationDirection direction) {
if (direction == AnimationDirection.forward || reverseCurve == null)
return curve;
return reverseCurve;
}
/// Applies this timing to the given animation clock value in the given direction /// Applies this timing to the given animation clock value in the given direction
double transform(double t, AnimationDirection direction) { double transform(double t, AnimationDirection direction) {
Curve activeCurve = _getActiveCurve(direction); Curve activeCurve = _getActiveCurve(direction);
...@@ -51,32 +69,6 @@ class AnimationTiming { ...@@ -51,32 +69,6 @@ class AnimationTiming {
return activeCurve.transform(t); return activeCurve.transform(t);
} }
Curve _getActiveCurve(AnimationDirection direction) {
if (direction == AnimationDirection.forward || reverseCurve == null)
return curve;
return reverseCurve;
}
}
/// An animated variable with a concrete type.
class AnimatedValue<T extends dynamic> extends AnimationTiming implements Animatable {
AnimatedValue(this.begin, { this.end, Curve curve, Curve reverseCurve })
: super(curve: curve, reverseCurve: reverseCurve) {
value = begin;
}
/// The current value of this variable.
T value;
/// The value this variable has at the beginning of the animation.
T begin;
/// The value this variable has at the end of the animation.
T end;
/// Returns the value this variable has at the given animation clock value.
T lerp(double t) => begin + (end - begin) * t;
/// Updates the value of this variable according to the given animation clock /// Updates the value of this variable according to the given animation clock
/// value and direction. /// value and direction.
void setProgress(double t, AnimationDirection direction) { void setProgress(double t, AnimationDirection direction) {
......
...@@ -8,9 +8,10 @@ import 'dart:ui' show VoidCallback, lerpDouble; ...@@ -8,9 +8,10 @@ import 'dart:ui' show VoidCallback, lerpDouble;
import 'package:newton/newton.dart'; import 'package:newton/newton.dart';
import 'animated_value.dart'; import 'animated_value.dart';
import 'curves.dart';
import 'forces.dart'; import 'forces.dart';
import 'simulation_stepper.dart';
import 'listener_helpers.dart'; import 'listener_helpers.dart';
import 'simulation_stepper.dart';
/// An interface that is implemented by [Performance] that exposes a /// An interface that is implemented by [Performance] that exposes a
/// read-only view of the underlying performance. This is used by classes that /// read-only view of the underlying performance. This is used by classes that
...@@ -425,6 +426,62 @@ class ProxyPerformance extends PerformanceView ...@@ -425,6 +426,62 @@ class ProxyPerformance extends PerformanceView
double get progress => _masterPerformance != null ? _masterPerformance.progress : _progress; double get progress => _masterPerformance != null ? _masterPerformance.progress : _progress;
} }
class CurvedPerformance extends PerformanceView {
CurvedPerformance(this._performance, { this.curve, this.reverseCurve });
final PerformanceView _performance;
/// The curve to use in the forward direction
Curve curve;
/// The curve to use in the reverse direction
///
/// If this field is null, use [curve] in both directions.
Curve reverseCurve;
void addListener(VoidCallback listener) {
_performance.addListener(listener);
}
void removeListener(VoidCallback listener) {
_performance.removeListener(listener);
}
void addStatusListener(PerformanceStatusListener listener) {
_performance.addStatusListener(listener);
}
void removeStatusListener(PerformanceStatusListener listener) {
_performance.removeStatusListener(listener);
}
void updateVariable(Animatable variable) {
variable.setProgress(progress, curveDirection);
}
PerformanceStatus get status => _performance.status;
AnimationDirection get direction => _performance.direction;
AnimationDirection get curveDirection => _performance.curveDirection;
double get progress {
Curve activeCurve;
if (curveDirection == AnimationDirection.forward || reverseCurve == null)
activeCurve = curve;
else
activeCurve = reverseCurve;
if (activeCurve == null)
return _performance.progress;
if (_performance.status == PerformanceStatus.dismissed) {
assert(_performance.progress == 0.0);
assert(activeCurve.transform(0.0).roundToDouble() == 0.0);
return 0.0;
}
if (_performance.status == PerformanceStatus.completed) {
assert(_performance.progress == 1.0);
assert(activeCurve.transform(1.0).roundToDouble() == 1.0);
return 1.0;
}
return activeCurve.transform(_performance.progress);
}
}
/// A timeline that can be reversed and used to update [Animatable]s. /// A timeline that can be reversed and used to update [Animatable]s.
/// ///
/// For example, a performance may handle an animation of a menu opening by /// For example, a performance may handle an animation of a menu opening by
...@@ -459,9 +516,6 @@ class Performance extends PerformanceView ...@@ -459,9 +516,6 @@ class Performance extends PerformanceView
AnimationDirection get curveDirection => _curveDirection; AnimationDirection get curveDirection => _curveDirection;
AnimationDirection _curveDirection; AnimationDirection _curveDirection;
/// If non-null, animate with this timing instead of a linear timing
AnimationTiming timing;
/// The progress of this performance along the timeline /// The progress of this performance along the timeline
/// ///
/// Note: Setting this value stops the current animation. /// Note: Setting this value stops the current animation.
...@@ -472,10 +526,6 @@ class Performance extends PerformanceView ...@@ -472,10 +526,6 @@ class Performance extends PerformanceView
_checkStatusChanged(); _checkStatusChanged();
} }
double get _curvedProgress {
return timing != null ? timing.transform(progress, _curveDirection) : progress;
}
/// Whether this animation is currently animating in either the forward or reverse direction /// Whether this animation is currently animating in either the forward or reverse direction
bool get isAnimating => _timeline.isAnimating; bool get isAnimating => _timeline.isAnimating;
...@@ -491,7 +541,7 @@ class Performance extends PerformanceView ...@@ -491,7 +541,7 @@ class Performance extends PerformanceView
/// Update the given varaible according to the current progress of this performance /// Update the given varaible according to the current progress of this performance
void updateVariable(Animatable variable) { void updateVariable(Animatable variable) {
variable.setProgress(_curvedProgress, _curveDirection); variable.setProgress(progress, _curveDirection);
} }
/// Start running this animation forwards (towards the end) /// Start running this animation forwards (towards the end)
...@@ -591,7 +641,7 @@ class ValuePerformance<T> extends Performance { ...@@ -591,7 +641,7 @@ class ValuePerformance<T> extends Performance {
void didTick(double t) { void didTick(double t) {
if (variable != null) if (variable != null)
variable.setProgress(_curvedProgress, _curveDirection); variable.setProgress(progress, _curveDirection);
super.didTick(t); super.didTick(t);
} }
} }
......
...@@ -37,7 +37,7 @@ class BottomSheet extends StatelessComponent { ...@@ -37,7 +37,7 @@ class BottomSheet extends StatelessComponent {
final double childHeight; final double childHeight;
final WidgetBuilder builder; final WidgetBuilder builder;
static Performance createPerformance() { static Performance createPerformanceController() {
return new Performance( return new Performance(
duration: _kBottomSheetDuration, duration: _kBottomSheetDuration,
debugLabel: 'BottomSheet' debugLabel: 'BottomSheet'
...@@ -154,8 +154,8 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> { ...@@ -154,8 +154,8 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
bool get barrierDismissable => true; bool get barrierDismissable => true;
Color get barrierColor => Colors.black54; Color get barrierColor => Colors.black54;
Performance createPerformance() { Performance createPerformanceController() {
return BottomSheet.createPerformance(); return BottomSheet.createPerformanceController();
} }
Widget buildPage(BuildContext context, PerformanceView performance, PerformanceView forwardPerformance) { Widget buildPage(BuildContext context, PerformanceView performance, PerformanceView forwardPerformance) {
......
...@@ -97,12 +97,11 @@ class _PopupMenuRoute<T> extends PopupRoute<T> { ...@@ -97,12 +97,11 @@ class _PopupMenuRoute<T> extends PopupRoute<T> {
final List<PopupMenuItem<T>> items; final List<PopupMenuItem<T>> items;
final int elevation; final int elevation;
Performance createPerformance() { PerformanceView createPerformance() {
Performance result = super.createPerformance(); return new CurvedPerformance(
AnimationTiming timing = new AnimationTiming(); super.createPerformance(),
timing.reverseCurve = new Interval(0.0, _kMenuCloseIntervalEnd); reverseCurve: new Interval(0.0, _kMenuCloseIntervalEnd)
result.timing = timing; );
return result;
} }
Duration get transitionDuration => _kMenuDuration; Duration get transitionDuration => _kMenuDuration;
......
...@@ -133,7 +133,7 @@ class ScaffoldState extends State<Scaffold> { ...@@ -133,7 +133,7 @@ class ScaffoldState extends State<Scaffold> {
Timer _snackBarTimer; Timer _snackBarTimer;
ScaffoldFeatureController showSnackBar(SnackBar snackbar) { ScaffoldFeatureController showSnackBar(SnackBar snackbar) {
_snackBarPerformance ??= SnackBar.createPerformance() _snackBarPerformance ??= SnackBar.createPerformanceController()
..addStatusListener(_handleSnackBarStatusChange); ..addStatusListener(_handleSnackBarStatusChange);
if (_snackBars.isEmpty) { if (_snackBars.isEmpty) {
assert(_snackBarPerformance.isDismissed); assert(_snackBarPerformance.isDismissed);
...@@ -201,7 +201,7 @@ class ScaffoldState extends State<Scaffold> { ...@@ -201,7 +201,7 @@ class ScaffoldState extends State<Scaffold> {
} }
Completer completer = new Completer(); Completer completer = new Completer();
GlobalKey<_PersistentBottomSheetState> bottomSheetKey = new GlobalKey<_PersistentBottomSheetState>(); GlobalKey<_PersistentBottomSheetState> bottomSheetKey = new GlobalKey<_PersistentBottomSheetState>();
Performance performance = BottomSheet.createPerformance() Performance performance = BottomSheet.createPerformanceController()
..forward(); ..forward();
_PersistentBottomSheet bottomSheet; _PersistentBottomSheet bottomSheet;
LocalHistoryEntry entry = new LocalHistoryEntry( LocalHistoryEntry entry = new LocalHistoryEntry(
......
...@@ -116,7 +116,7 @@ class SnackBar extends StatelessComponent { ...@@ -116,7 +116,7 @@ class SnackBar extends StatelessComponent {
// API for Scaffold.addSnackBar(): // API for Scaffold.addSnackBar():
static Performance createPerformance() { static Performance createPerformanceController() {
return new Performance( return new Performance(
duration: _kSnackBarTransitionDuration, duration: _kSnackBarTransitionDuration,
debugLabel: 'SnackBar' debugLabel: 'SnackBar'
......
...@@ -92,28 +92,40 @@ class _AnimatedContainerState extends State<AnimatedContainer> { ...@@ -92,28 +92,40 @@ class _AnimatedContainerState extends State<AnimatedContainer> {
AnimatedValue<double> _width; AnimatedValue<double> _width;
AnimatedValue<double> _height; AnimatedValue<double> _height;
Performance _performance; Performance _performanceController;
PerformanceView _performance;
void initState() { void initState() {
super.initState(); super.initState();
_performance = new Performance(duration: config.duration, debugLabel: '${config.toStringShort()}') _performanceController = new Performance(
..timing = new AnimationTiming(curve: config.curve) duration: config.duration,
..addListener(_updateAllVariables); debugLabel: '${config.toStringShort()}'
);
_updateCurve();
_configAllVariables(); _configAllVariables();
} }
void didUpdateConfig(AnimatedContainer oldConfig) { void didUpdateConfig(AnimatedContainer oldConfig) {
_performance if (config.curve != oldConfig.curve)
..duration = config.duration _updateCurve();
..timing.curve = config.curve; _performanceController.duration = config.duration;
if (_configAllVariables()) { if (_configAllVariables()) {
_performance.progress = 0.0; _performanceController.progress = 0.0;
_performance.play(); _performanceController.play();
} }
} }
void _updateCurve() {
_performance?.removeListener(_updateAllVariables);
if (config.curve != null)
_performance = new CurvedPerformance(_performanceController, curve: config.curve);
else
_performance = _performanceController;
_performance.addListener(_updateAllVariables);
}
void dispose() { void dispose() {
_performance.stop(); _performanceController.stop();
super.dispose(); super.dispose();
} }
......
...@@ -81,15 +81,27 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> { ...@@ -81,15 +81,27 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
Duration get transitionDuration; Duration get transitionDuration;
bool get opaque; bool get opaque;
PerformanceView get performance => _performance?.view; PerformanceView get performance => _performance;
Performance _performance; Performance _performanceController;
PerformanceView _performance;
Performance createPerformance() {
/// Called to create the Performance object that will drive the transitions to
/// this route from the previous one, and back to the previous route from this
/// one.
Performance createPerformanceController() {
Duration duration = transitionDuration; Duration duration = transitionDuration;
assert(duration != null && duration >= Duration.ZERO); assert(duration != null && duration >= Duration.ZERO);
return new Performance(duration: duration, debugLabel: debugLabel); return new Performance(duration: duration, debugLabel: debugLabel);
} }
/// Called to create the PerformanceView that exposes the current progress of
/// the transition controlled by the Performance object created by
/// [createPerformanceController()].
PerformanceView createPerformance() {
assert(_performanceController != null);
return _performanceController.view;
}
T _result; T _result;
void handleStatusChanged(PerformanceStatus status) { void handleStatusChanged(PerformanceStatus status) {
...@@ -112,26 +124,29 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> { ...@@ -112,26 +124,29 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
} }
void install(OverlayEntry insertionPoint) { void install(OverlayEntry insertionPoint) {
_performanceController = createPerformanceController();
assert(_performanceController != null);
_performance = createPerformance(); _performance = createPerformance();
assert(_performance != null);
super.install(insertionPoint); super.install(insertionPoint);
} }
void didPush() { void didPush() {
_performance.addStatusListener(handleStatusChanged); _performance.addStatusListener(handleStatusChanged);
_performance.forward(); _performanceController.forward();
super.didPush(); super.didPush();
} }
void didReplace(Route oldRoute) { void didReplace(Route oldRoute) {
if (oldRoute is TransitionRoute) if (oldRoute is TransitionRoute)
_performance.progress = oldRoute._performance.progress; _performanceController.progress = oldRoute._performanceController.progress;
_performance.addStatusListener(handleStatusChanged); _performance.addStatusListener(handleStatusChanged);
super.didReplace(oldRoute); super.didReplace(oldRoute);
} }
bool didPop(T result) { bool didPop(T result) {
_result = result; _result = result;
_performance.reverse(); _performanceController.reverse();
_popCompleter?.complete(_result); _popCompleter?.complete(_result);
return true; return true;
} }
...@@ -142,7 +157,7 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> { ...@@ -142,7 +157,7 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
} }
void dispose() { void dispose() {
_performance.stop(); _performanceController.stop();
super.dispose(); super.dispose();
} }
...@@ -182,7 +197,7 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> { ...@@ -182,7 +197,7 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
bool canTransitionFrom(TransitionRoute nextRoute) => true; bool canTransitionFrom(TransitionRoute nextRoute) => true;
String get debugLabel => '$runtimeType'; String get debugLabel => '$runtimeType';
String toString() => '$runtimeType(performance: $_performance)'; String toString() => '$runtimeType(performance: $_performanceController)';
} }
class LocalHistoryEntry { class LocalHistoryEntry {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment