// 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:flutter/widgets.dart'; import 'button.dart'; import 'flat_button.dart'; import 'material.dart'; import 'theme_data.dart'; import 'theme.dart'; import 'typography.dart'; // https://www.google.com/design/spec/components/snackbars-toasts.html#snackbars-toasts-specs const double _kSideMargins = 24.0; const double _kSingleLineVerticalPadding = 14.0; const double _kMultiLineVerticalTopPadding = 24.0; const double _kMultiLineVerticalSpaceBetweenTextAndButtons = 10.0; const Color _kSnackBackground = const Color(0xFF323232); // TODO(ianh): We should check if the given text and actions are going to fit on // one line or not, and if they are, use the single-line layout, and if not, use // the multiline layout. See link above. // TODO(ianh): Implement the Tablet version of snackbar if we're "on a tablet". const Duration _kSnackBarTransitionDuration = const Duration(milliseconds: 250); const Duration kSnackBarShortDisplayDuration = const Duration(milliseconds: 1500); const Duration kSnackBarMediumDisplayDuration = const Duration(milliseconds: 2750); const Curve _snackBarHeightCurve = Curves.fastOutSlowIn; const Curve _snackBarFadeCurve = const Interval(0.72, 1.0, curve: Curves.fastOutSlowIn); /// A button for a [SnackBar], known as an "action". /// /// Snack bar actions are always enabled. If you want to disable a snack bar /// action, simply don't include it in the snack bar. /// /// See also: /// * https://www.google.com/design/spec/components/snackbars-toasts.html class SnackBarAction extends StatelessWidget { SnackBarAction({Key key, this.label, this.onPressed }) : super(key: key) { assert(label != null); assert(onPressed != null); } /// The button label. final String label; /// The callback to be invoked when the button is pressed. Must be non-null. final VoidCallback onPressed; @override Widget build(BuildContext context) { return new Container( margin: const EdgeInsets.only(left: _kSideMargins), child: new FlatButton( onPressed: onPressed, textTheme: ButtonColor.accent, child: new Text(label) ) ); } } /// A lightweight message with an optional action which briefly displays at the /// bottom of the screen. /// /// Displayed with the Scaffold.of().showSnackBar() API. /// /// See also: /// * [Scaffold.of] and [ScaffoldState.showSnackBar] /// * [SnackBarAction] /// * https://www.google.com/design/spec/components/snackbars-toasts.html class SnackBar extends StatelessWidget { SnackBar({ Key key, this.content, this.action, this.duration: kSnackBarShortDisplayDuration, this.animation }) : super(key: key) { assert(content != null); } final Widget content; final SnackBarAction action; final Duration duration; final Animation<double> animation; @override Widget build(BuildContext context) { assert(animation != null); List<Widget> children = <Widget>[ new Flexible( child: new Container( margin: const EdgeInsets.symmetric(vertical: _kSingleLineVerticalPadding), child: new DefaultTextStyle( style: Typography.white.subhead, child: content ) ) ) ]; if (action != null) children.add(action); CurvedAnimation heightAnimation = new CurvedAnimation(parent: animation, curve: _snackBarHeightCurve); CurvedAnimation fadeAnimation = new CurvedAnimation(parent: animation, curve: _snackBarFadeCurve); ThemeData theme = Theme.of(context); return new ClipRect( child: new AnimatedBuilder( animation: heightAnimation, builder: (BuildContext context, Widget child) { return new Align( alignment: const FractionalOffset(0.0, 0.0), heightFactor: heightAnimation.value, child: child ); }, child: new Semantics( container: true, child: new Material( elevation: 6, color: _kSnackBackground, child: new Container( margin: const EdgeInsets.symmetric(horizontal: _kSideMargins), child: new Theme( data: new ThemeData( brightness: ThemeBrightness.dark, accentColor: theme.accentColor, accentColorBrightness: theme.accentColorBrightness, textTheme: Typography.white ), child: new FadeTransition( opacity: fadeAnimation, child: new Row( children: children, crossAxisAlignment: CrossAxisAlignment.center ) ) ) ) ) ) ) ); } // API for Scaffold.addSnackBar(): static AnimationController createAnimationController() { return new AnimationController( duration: _kSnackBarTransitionDuration, debugLabel: 'SnackBar' ); } SnackBar withAnimation(Animation<double> newAnimation, { Key fallbackKey }) { return new SnackBar( key: key ?? fallbackKey, content: content, action: action, duration: duration, animation: newAnimation ); } }