Commit 3f58d9b7 authored by Hans Muller's avatar Hans Muller

Merge pull request #310 from HansMuller/snack_bar

showSnackBar() returns a Future, clears its placeholder

The returned Future completes after the snack bar has been dismissed.

Revised BottomSheet to ensure that its Future only runs after the bottom sheet has been dismissed.
parents 145b53f1 1aac53a5
......@@ -77,10 +77,14 @@ class _BottomSheetRoute extends OverlayRoute {
}
void didPop(dynamic result) {
completer.complete(result);
performance.reverse().then((_) {
void finish() {
super.didPop(result); // clear the overlay entries
});
completer.complete(result);
}
if (performance.isDismissed)
finish();
else
performance.reverse().then((_) { finish(); });
}
String get debugLabel => '$runtimeType';
......
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:flutter/animation.dart';
import 'package:flutter/widgets.dart';
......@@ -92,12 +94,15 @@ class _SnackBar extends StatelessComponent {
}
class _SnackBarRoute extends TransitionRoute {
_SnackBarRoute({ Completer completer }) : super(completer: completer);
bool get opaque => false;
Duration get transitionDuration => const Duration(milliseconds: 200);
}
void showSnackBar({ BuildContext context, GlobalKey<PlaceholderState> placeholderKey, Widget content, List<SnackBarAction> actions }) {
_SnackBarRoute route = new _SnackBarRoute();
Future showSnackBar({ BuildContext context, GlobalKey<PlaceholderState> placeholderKey, Widget content, List<SnackBarAction> actions }) {
final Completer completer = new Completer();
_SnackBarRoute route = new _SnackBarRoute(completer: completer);
_SnackBar snackBar = new _SnackBar(
route: route,
content: content,
......@@ -105,4 +110,7 @@ void showSnackBar({ BuildContext context, GlobalKey<PlaceholderState> placeholde
);
placeholderKey.currentState.child = snackBar;
Navigator.of(context).pushEphemeral(route);
return completer.future.then((_) {
placeholderKey.currentState.child = null;
});
}
......@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:flutter/animation.dart';
import 'basic.dart';
......@@ -46,6 +48,10 @@ class OverlayRoute extends Route {
// TODO(abarth): Should we add a type for the result?
abstract class TransitionRoute extends OverlayRoute {
TransitionRoute({ this.completer });
final Completer completer;
Duration get transitionDuration;
bool get opaque;
......@@ -86,6 +92,9 @@ abstract class TransitionRoute extends OverlayRoute {
void didPop(dynamic result) {
_result = result;
if (completer != null)
_performance.reverse().then((_) { completer.complete(_result); });
else
_performance.reverse();
}
......
......@@ -8,6 +8,8 @@ void main() {
test('Verify that a tap dismisses a modal BottomSheet', () {
testWidgets((WidgetTester tester) {
BuildContext context;
bool showBottomSheetThenCalled = false;
tester.pumpWidget(new MaterialApp(
routes: <String, RouteBuilder>{
'/': (RouteArguments args) {
......@@ -20,7 +22,10 @@ void main() {
tester.pump();
expect(tester.findText('BottomSheet'), isNull);
showModalBottomSheet(context: context, child: new Text('BottomSheet'));
showModalBottomSheet(context: context, child: new Text('BottomSheet')).then((_) {
showBottomSheetThenCalled = true;
});
tester.pump(); // bottom sheet show animation starts
tester.pump(new Duration(seconds: 1)); // animation done
expect(tester.findText('BottomSheet'), isNotNull);
......@@ -29,7 +34,8 @@ void main() {
tester.tap(tester.findText('BottomSheet'));
tester.pump(); // bottom sheet dismiss animation starts
tester.pump(new Duration(seconds: 1)); // animation done
tester.pump(new Duration(seconds: 2)); // rebuild frame
tester.pump(new Duration(seconds: 1)); // rebuild frame
expect(showBottomSheetThenCalled, isTrue);
expect(tester.findText('BottomSheet'), isNull);
showModalBottomSheet(context: context, child: new Text('BottomSheet'));
......@@ -41,7 +47,7 @@ void main() {
tester.tapAt(new Point(20.0, 20.0));
tester.pump(); // bottom sheet dismiss animation starts
tester.pump(new Duration(seconds: 1)); // animation done
tester.pump(new Duration(seconds: 2)); // rebuild frame
tester.pump(new Duration(seconds: 1)); // rebuild frame
expect(tester.findText('BottomSheet'), isNull);
});
});
......@@ -50,6 +56,8 @@ void main() {
testWidgets((WidgetTester tester) {
GlobalKey<PlaceholderState> _bottomSheetPlaceholderKey = new GlobalKey<PlaceholderState>();
BuildContext context;
bool showBottomSheetThenCalled = false;
tester.pumpWidget(new MaterialApp(
routes: <String, RouteBuilder>{
'/': (RouteArguments args) {
......@@ -69,7 +77,9 @@ void main() {
context: context,
child: new Container(child: new Text('BottomSheet'), margin: new EdgeDims.all(40.0)),
placeholderKey: _bottomSheetPlaceholderKey
);
).then((_) {
showBottomSheetThenCalled = true;
});
expect(_bottomSheetPlaceholderKey.currentState.child, isNotNull);
tester.pump(); // bottom sheet show animation starts
......@@ -79,7 +89,8 @@ void main() {
tester.fling(tester.findText('BottomSheet'), const Offset(0.0, 20.0), 1000.0);
tester.pump(); // bottom sheet dismiss animation starts
tester.pump(new Duration(seconds: 1)); // animation done
tester.pump(new Duration(seconds: 2)); // rebuild frame without the bottom sheet
tester.pump(new Duration(seconds: 1)); // rebuild frame without the bottom sheet
expect(showBottomSheetThenCalled, isTrue);
expect(tester.findText('BottomSheet'), isNull);
expect(_bottomSheetPlaceholderKey.currentState.child, isNull);
});
......
......@@ -9,17 +9,22 @@ void main() {
String helloSnackBar = 'Hello SnackBar';
GlobalKey<PlaceholderState> placeholderKey = new GlobalKey<PlaceholderState>();
Key tapTarget = new Key('tap-target');
BuildContext context;
bool showSnackBarThenCalled = false;
tester.pumpWidget(new MaterialApp(
routes: <String, RouteBuilder>{
'/': (RouteArguments args) {
context = args.context;
return new GestureDetector(
onTap: () {
showSnackBar(
context: args.context,
placeholderKey: placeholderKey,
content: new Text(helloSnackBar)
);
).then((_) {
showSnackBarThenCalled = true;
});
},
child: new Container(
decoration: const BoxDecoration(
......@@ -36,10 +41,16 @@ void main() {
));
tester.tap(tester.findElementByKey(tapTarget));
expect(tester.findText(helloSnackBar), isNull);
tester.pump();
expect(tester.findText(helloSnackBar), isNotNull);
Navigator.of(context).pop();
expect(tester.findText(helloSnackBar), isNotNull);
tester.pump(new Duration(seconds: 1));
expect(showSnackBarThenCalled, isTrue);
expect(tester.findText(helloSnackBar), isNull);
expect(placeholderKey.currentState.child, isNull);
});
});
}
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