Commit 7570495b authored by Adam Barth's avatar Adam Barth

SnackBarActions shouldn't be tappable twice

They should automagically disable after the first tap.
parent 1e207c01
...@@ -36,11 +36,13 @@ const Curve _snackBarFadeCurve = const Interval(0.72, 1.0, curve: Curves.fastOut ...@@ -36,11 +36,13 @@ const Curve _snackBarFadeCurve = const Interval(0.72, 1.0, curve: Curves.fastOut
/// Snack bar actions are always enabled. If you want to disable a snack bar /// Snack bar actions are always enabled. If you want to disable a snack bar
/// action, simply don't include it in the snack bar. /// action, simply don't include it in the snack bar.
/// ///
/// Snack bar actions can only be pressed once. Subsequent presses are ignored.
///
/// See also: /// See also:
/// ///
/// * [SnackBar] /// * [SnackBar]
/// * <https://www.google.com/design/spec/components/snackbars-toasts.html> /// * <https://www.google.com/design/spec/components/snackbars-toasts.html>
class SnackBarAction extends StatelessWidget { class SnackBarAction extends StatefulWidget {
SnackBarAction({Key key, this.label, this.onPressed }) : super(key: key) { SnackBarAction({Key key, this.label, this.onPressed }) : super(key: key) {
assert(label != null); assert(label != null);
assert(onPressed != null); assert(onPressed != null);
...@@ -50,16 +52,35 @@ class SnackBarAction extends StatelessWidget { ...@@ -50,16 +52,35 @@ class SnackBarAction extends StatelessWidget {
final String label; final String label;
/// The callback to be invoked when the button is pressed. Must be non-null. /// The callback to be invoked when the button is pressed. Must be non-null.
///
/// This callback will be invoked at most once each time this action is
/// displayed in a [SnackBar].
final VoidCallback onPressed; final VoidCallback onPressed;
@override
_SnackBarActionState createState() => new _SnackBarActionState();
}
class _SnackBarActionState extends State<SnackBarAction> {
bool _haveTriggeredAction = false;
void _handlePressed() {
if (_haveTriggeredAction)
return;
setState(() {
_haveTriggeredAction = true;
});
config.onPressed();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new Container( return new Container(
margin: const EdgeInsets.only(left: _kSideMargins), margin: const EdgeInsets.only(left: _kSideMargins),
child: new FlatButton( child: new FlatButton(
onPressed: onPressed, onPressed: _haveTriggeredAction ? null : _handlePressed,
textTheme: ButtonColor.accent, textTheme: ButtonColor.accent,
child: new Text(label) child: new Text(config.label)
) )
); );
} }
......
...@@ -282,4 +282,48 @@ void main() { ...@@ -282,4 +282,48 @@ void main() {
}); });
}); });
test('SnackBar cannot be tapped twice', () {
testWidgets((WidgetTester tester) {
int tapCount = 0;
tester.pumpWidget(new MaterialApp(
routes: <String, WidgetBuilder>{
'/': (BuildContext context) {
return new Scaffold(
body: new Builder(
builder: (BuildContext context) {
return new GestureDetector(
onTap: () {
Scaffold.of(context).showSnackBar(new SnackBar(
content: new Text('I am a snack bar.'),
duration: new Duration(seconds: 2),
action: new SnackBarAction(
label: 'ACTION',
onPressed: () {
++tapCount;
}
)
));
},
child: new Text('X')
);
}
)
);
}
}
));
tester.tap(tester.findText('X'));
tester.pump(); // start animation
tester.pump(const Duration(milliseconds: 750));
expect(tapCount, equals(0));
tester.tap(tester.findText('ACTION'));
expect(tapCount, equals(1));
tester.tap(tester.findText('ACTION'));
expect(tapCount, equals(1));
tester.pump();
tester.tap(tester.findText('ACTION'));
expect(tapCount, equals(1));
});
});
} }
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