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