blob: 15cff58ad11b4bc3bb52842347b9e67f58844dd1 [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 'package:vector_math/vector_math.dart';
import 'package:sky/animation/animation_performance.dart';
import 'package:sky/animation/curves.dart';
import 'package:sky/base/lerp.dart';
import 'package:sky/painting/box_painter.dart';
import 'package:sky/theme/shadows.dart';
import 'package:sky/widgets/basic.dart';
// This class builds a Container object from a collection of optionally-
// animated properties. Use syncFields to update the Container's properties,
// which will optionally animate them using an AnimationPerformance.
class AnimationBuilder {
AnimationBuilder();
AnimatedType<double> opacity;
AnimatedType<Point> position;
AnimatedType<double> shadow;
AnimatedColor backgroundColor;
// These don't animate, but are used to build the AnimationBuilder anyway.
double borderRadius;
Shape shape;
Map<AnimatedVariable, AnimationPerformance> _variableToPerformance =
new Map<AnimatedVariable, AnimationPerformance>();
AnimationPerformance createPerformance(List<AnimatedType> variables,
{ Duration duration }) {
AnimationPerformance performance = new AnimationPerformance()
..duration = duration
..variable = new AnimatedList(variables);
for (AnimatedVariable variable in variables)
_variableToPerformance[variable] = performance;
return performance;
}
Widget build(Widget child) {
Widget current = child;
if (shadow != null || backgroundColor != null ||
borderRadius != null || shape != null) {
current = new DecoratedBox(
decoration: new BoxDecoration(
borderRadius: borderRadius,
shape: shape,
boxShadow: shadow != null ? _computeShadow(shadow.value) : null,
backgroundColor: backgroundColor != null ? backgroundColor.value : null),
child: current);
}
if (position != null) {
Matrix4 transform = new Matrix4.identity();
transform.translate(position.value.x, position.value.y);
current = new Transform(transform: transform, child: current);
}
if (opacity != null) {
current = new Opacity(opacity: opacity.value, child: current);
}
return current;
}
void updateFields({
AnimatedType<double> shadow,
AnimatedColor backgroundColor,
double borderRadius,
Shape shape
}) {
_updateField(this.shadow, shadow);
_updateField(this.backgroundColor, backgroundColor);
this.borderRadius = borderRadius;
this.shape = shape;
}
void _updateField(AnimatedType variable, AnimatedType sourceVariable) {
if (variable == null)
return; // TODO(mpcomplete): Should we handle transition from null?
AnimationPerformance performance = _variableToPerformance[variable];
if (performance == null) {
// If there's no performance, no need to animate.
if (sourceVariable != null)
variable.value = sourceVariable.value;
return;
}
if (variable.value != sourceVariable.value) {
variable
..begin = variable.value
..end = sourceVariable.value;
performance
..progress = 0.0
..play();
}
}
}
class AnimatedColor extends AnimatedType<Color> {
AnimatedColor(Color begin, { Color end, Curve curve: linear })
: super(begin, end: end, curve: curve);
void setFraction(double t) {
value = lerpColor(begin, end, t);
}
}
List<BoxShadow> _computeShadow(double level) {
if (level < 1.0) // shadows[1] is the first shadow
return null;
int level1 = level.floor();
int level2 = level.ceil();
double t = level - level1.toDouble();
List<BoxShadow> shadow = new List<BoxShadow>();
for (int i = 0; i < shadows[level1].length; ++i)
shadow.add(lerpBoxShadow(shadows[level1][i], shadows[level2][i], t));
return shadow;
}