diff --git a/sky/sdk/BUILD.gn b/sky/sdk/BUILD.gn index 2577abfcc1bd5..ea77307a144b5 100644 --- a/sky/sdk/BUILD.gn +++ b/sky/sdk/BUILD.gn @@ -51,7 +51,6 @@ dart_pkg("sky") { "lib/theme/view_configuration.dart", "lib/widgets/animated_component.dart", "lib/widgets/animated_container.dart", - "lib/widgets/animation_builder.dart", "lib/widgets/basic.dart", "lib/widgets/block_viewport.dart", "lib/widgets/button_base.dart", diff --git a/sky/sdk/example/stocks/lib/stock_home.dart b/sky/sdk/example/stocks/lib/stock_home.dart index b7a314c160ac9..a6a857e97da76 100644 --- a/sky/sdk/example/stocks/lib/stock_home.dart +++ b/sky/sdk/example/stocks/lib/stock_home.dart @@ -3,9 +3,6 @@ // found in the LICENSE file. import 'package:sky/editing/input.dart'; -import 'package:sky/animation/animation_performance.dart'; -import 'package:sky/widgets/animated_component.dart'; -import 'package:sky/widgets/animation_builder.dart'; import 'package:sky/theme/colors.dart' as colors; import 'package:sky/widgets/basic.dart'; import 'package:sky/widgets/drawer.dart'; @@ -35,7 +32,7 @@ typedef void ModeUpdater(StockMode mode); const Duration _kSnackbarSlideDuration = const Duration(milliseconds: 200); -class StockHome extends AnimatedComponent { +class StockHome extends StatefulComponent { StockHome(this.navigator, this.stocks, this.stockMode, this.modeUpdater); @@ -54,7 +51,8 @@ class StockHome extends AnimatedComponent { bool _isSearching = false; String _searchQuery; - AnimationBuilder _snackbarTransform; + SnackBarStatus _snackBarStatus; + bool _isSnackBarShowing = false; // Should it be showing? void _handleSearchBegin() { navigator.pushState(this, (_) { @@ -139,6 +137,7 @@ class StockHome extends AnimatedComponent { Drawer buildDrawer() { if (_drawerStatus == DrawerStatus.inactive) return null; + assert(_drawerShowing); // TODO(mpcomplete): this is always true return new Drawer( level: 3, showing: _drawerShowing, @@ -263,40 +262,34 @@ class StockHome extends AnimatedComponent { void _handleUndo() { setState(() { - _snackbarTransform = null; + _isSnackBarShowing = false; }); } Widget buildSnackBar() { - if (_snackbarTransform == null) + if (_snackBarStatus == SnackBarStatus.inactive) return null; - return _snackbarTransform.build( - new SnackBar( - content: new Text("Stock purchased!"), - actions: [new SnackBarAction(label: "UNDO", onPressed: _handleUndo)] - )); + return new SnackBar( + showing: _isSnackBarShowing, + content: new Text("Stock purchased!"), + actions: [new SnackBarAction(label: "UNDO", onPressed: _handleUndo)], + onStatusChanged: (status) { setState(() { _snackBarStatus = status; }); } + ); } void _handleStockPurchased() { setState(() { - _snackbarTransform = new AnimationBuilder() - ..position = new AnimatedType(const Point(0.0, 45.0), end: Point.origin); - var performance = _snackbarTransform.createPerformance( - [_snackbarTransform.position], duration: _kSnackbarSlideDuration); - watch(performance); - performance.play(); + _isSnackBarShowing = true; + _snackBarStatus = SnackBarStatus.active; }); } Widget buildFloatingActionButton() { - var widget = new FloatingActionButton( + return new FloatingActionButton( child: new Icon(type: 'content/add', size: 24), backgroundColor: colors.RedAccent[200], onPressed: _handleStockPurchased ); - if (_snackbarTransform != null) - widget = _snackbarTransform.build(widget); - return widget; } void addMenuToOverlays(List overlays) { diff --git a/sky/sdk/lib/widgets/animation_builder.dart b/sky/sdk/lib/widgets/animation_builder.dart deleted file mode 100644 index 15cff58ad11b4..0000000000000 --- a/sky/sdk/lib/widgets/animation_builder.dart +++ /dev/null @@ -1,125 +0,0 @@ -// 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 opacity; - AnimatedType position; - AnimatedType shadow; - AnimatedColor backgroundColor; - - // These don't animate, but are used to build the AnimationBuilder anyway. - double borderRadius; - Shape shape; - - Map _variableToPerformance = - new Map(); - - AnimationPerformance createPerformance(List 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 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 { - AnimatedColor(Color begin, { Color end, Curve curve: linear }) - : super(begin, end: end, curve: curve); - - void setFraction(double t) { - value = lerpColor(begin, end, t); - } -} - -List _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 shadow = new List(); - for (int i = 0; i < shadows[level1].length; ++i) - shadow.add(lerpBoxShadow(shadows[level1][i], shadows[level2][i], t)); - return shadow; -} diff --git a/sky/sdk/lib/widgets/drawer.dart b/sky/sdk/lib/widgets/drawer.dart index 60f3682e8263a..d5370a3e89cee 100644 --- a/sky/sdk/lib/widgets/drawer.dart +++ b/sky/sdk/lib/widgets/drawer.dart @@ -5,10 +5,11 @@ import 'dart:sky' as sky; import 'package:sky/animation/animation_performance.dart'; +import 'package:sky/animation/curves.dart'; +import 'package:sky/base/lerp.dart'; import 'package:sky/theme/shadows.dart'; import 'package:sky/theme/colors.dart' as colors; import 'package:sky/widgets/animated_component.dart'; -import 'package:sky/widgets/animation_builder.dart'; import 'package:sky/widgets/basic.dart'; import 'package:sky/widgets/navigator.dart'; import 'package:sky/widgets/scrollable_viewport.dart'; @@ -44,6 +45,16 @@ enum DrawerStatus { typedef void DrawerStatusChangedCallback(DrawerStatus status); +// TODO(mpcomplete): find a better place for this. +class AnimatedColor extends AnimatedType { + AnimatedColor(Color begin, { Color end, Curve curve: linear }) + : super(begin, end: end, curve: curve); + + void setFraction(double t) { + value = lerpColor(begin, end, t); + } +} + class Drawer extends AnimatedComponent { Drawer({ String key, diff --git a/sky/sdk/lib/widgets/snack_bar.dart b/sky/sdk/lib/widgets/snack_bar.dart index 074816db908d1..ada76ebca2248 100644 --- a/sky/sdk/lib/widgets/snack_bar.dart +++ b/sky/sdk/lib/widgets/snack_bar.dart @@ -2,13 +2,26 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import 'package:sky/animation/animation_performance.dart'; import 'package:sky/painting/text_style.dart'; import 'package:sky/theme/typography.dart' as typography; +import 'package:sky/widgets/animated_component.dart'; import 'package:sky/widgets/basic.dart'; import 'package:sky/widgets/default_text_style.dart'; import 'package:sky/widgets/material.dart'; import 'package:sky/widgets/theme.dart'; +import 'package:vector_math/vector_math.dart'; + +enum SnackBarStatus { + active, + inactive, +} + +typedef void SnackBarStatusChangedCallback(SnackBarStatus status); + +const Duration _kSlideInDuration = const Duration(milliseconds: 200); + class SnackBarAction extends Component { SnackBarAction({String key, this.label, this.onPressed }) : super(key: key) { assert(label != null); @@ -29,18 +42,64 @@ class SnackBarAction extends Component { } } -class SnackBar extends Component { +class SnackBar extends AnimatedComponent { SnackBar({ String key, this.content, - this.actions + this.actions, + this.showing, + this.onStatusChanged }) : super(key: key) { assert(content != null); } - final Widget content; - final List actions; + Widget content; + List actions; + bool showing; + SnackBarStatusChangedCallback onStatusChanged; + + void syncFields(SnackBar source) { + content = source.content; + actions = source.actions; + onStatusChanged = source.onStatusChanged; + if (showing != source.showing) { + showing = source.showing; + showing ? _show() : _hide(); + } + } + + AnimatedType _position; + AnimationPerformance _performance; + + void initState() { + _position = new AnimatedType(new Point(0.0, 50.0), end: Point.origin); + _performance = new AnimationPerformance() + ..duration = _kSlideInDuration + ..variable = _position + ..addListener(_checkStatusChanged); + watch(_performance); + if (showing) + _show(); + } + + void _show() { + _performance.play(); + } + + void _hide() { + _performance.reverse(); + } + + SnackBarStatus _lastStatus; + void _checkStatusChanged() { + SnackBarStatus status = _status; + if (_lastStatus != null && status != _lastStatus && onStatusChanged != null) + onStatusChanged(status); + _lastStatus = status; + } + + SnackBarStatus get _status => _performance.isDismissed ? SnackBarStatus.inactive : SnackBarStatus.active; Widget build() { List children = [ @@ -54,15 +113,21 @@ class SnackBar extends Component { ) ) ]..addAll(actions); - return new Material( - level: 2, - color: const Color(0xFF323232), - type: MaterialType.canvas, - child: new Container( - margin: const EdgeDims.symmetric(horizontal: 24.0), - child: new DefaultTextStyle( - style: new TextStyle(color: Theme.of(this).accentColor), - child: new Flex(children) + + Matrix4 transform = new Matrix4.identity(); + transform.translate(_position.value.x, _position.value.y); + return new Transform( + transform: transform, + child: new Material( + level: 2, + color: const Color(0xFF323232), + type: MaterialType.canvas, + child: new Container( + margin: const EdgeDims.symmetric(horizontal: 24.0), + child: new DefaultTextStyle( + style: new TextStyle(color: Theme.of(this).accentColor), + child: new Flex(children) + ) ) ) );