Skip to content

Commit 3f58d9b

Browse files
author
Hans Muller
committed
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.
2 parents 145b53f + 1aac53a commit 3f58d9b

File tree

5 files changed

+56
-13
lines changed

5 files changed

+56
-13
lines changed

packages/flutter/lib/src/material/bottom_sheet.dart

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,14 @@ class _BottomSheetRoute extends OverlayRoute {
7777
}
7878

7979
void didPop(dynamic result) {
80-
completer.complete(result);
81-
performance.reverse().then((_) {
80+
void finish() {
8281
super.didPop(result); // clear the overlay entries
83-
});
82+
completer.complete(result);
83+
}
84+
if (performance.isDismissed)
85+
finish();
86+
else
87+
performance.reverse().then((_) { finish(); });
8488
}
8589

8690
String get debugLabel => '$runtimeType';

packages/flutter/lib/src/material/snack_bar.dart

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
import 'dart:async';
6+
57
import 'package:flutter/animation.dart';
68
import 'package:flutter/widgets.dart';
79

@@ -92,17 +94,23 @@ class _SnackBar extends StatelessComponent {
9294
}
9395

9496
class _SnackBarRoute extends TransitionRoute {
97+
_SnackBarRoute({ Completer completer }) : super(completer: completer);
98+
9599
bool get opaque => false;
96100
Duration get transitionDuration => const Duration(milliseconds: 200);
97101
}
98102

99-
void showSnackBar({ BuildContext context, GlobalKey<PlaceholderState> placeholderKey, Widget content, List<SnackBarAction> actions }) {
100-
_SnackBarRoute route = new _SnackBarRoute();
103+
Future showSnackBar({ BuildContext context, GlobalKey<PlaceholderState> placeholderKey, Widget content, List<SnackBarAction> actions }) {
104+
final Completer completer = new Completer();
105+
_SnackBarRoute route = new _SnackBarRoute(completer: completer);
101106
_SnackBar snackBar = new _SnackBar(
102107
route: route,
103108
content: content,
104109
actions: actions
105110
);
106111
placeholderKey.currentState.child = snackBar;
107112
Navigator.of(context).pushEphemeral(route);
113+
return completer.future.then((_) {
114+
placeholderKey.currentState.child = null;
115+
});
108116
}

packages/flutter/lib/src/widgets/routes.dart

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
import 'dart:async';
6+
57
import 'package:flutter/animation.dart';
68

79
import 'basic.dart';
@@ -46,6 +48,10 @@ class OverlayRoute extends Route {
4648

4749
// TODO(abarth): Should we add a type for the result?
4850
abstract class TransitionRoute extends OverlayRoute {
51+
TransitionRoute({ this.completer });
52+
53+
final Completer completer;
54+
4955
Duration get transitionDuration;
5056
bool get opaque;
5157

@@ -86,7 +92,10 @@ abstract class TransitionRoute extends OverlayRoute {
8692

8793
void didPop(dynamic result) {
8894
_result = result;
89-
_performance.reverse();
95+
if (completer != null)
96+
_performance.reverse().then((_) { completer.complete(_result); });
97+
else
98+
_performance.reverse();
9099
}
91100

92101
String get debugLabel => '$runtimeType';

packages/unit/test/widget/bottom_sheet_test.dart

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ void main() {
88
test('Verify that a tap dismisses a modal BottomSheet', () {
99
testWidgets((WidgetTester tester) {
1010
BuildContext context;
11+
bool showBottomSheetThenCalled = false;
12+
1113
tester.pumpWidget(new MaterialApp(
1214
routes: <String, RouteBuilder>{
1315
'/': (RouteArguments args) {
@@ -20,7 +22,10 @@ void main() {
2022
tester.pump();
2123
expect(tester.findText('BottomSheet'), isNull);
2224

23-
showModalBottomSheet(context: context, child: new Text('BottomSheet'));
25+
showModalBottomSheet(context: context, child: new Text('BottomSheet')).then((_) {
26+
showBottomSheetThenCalled = true;
27+
});
28+
2429
tester.pump(); // bottom sheet show animation starts
2530
tester.pump(new Duration(seconds: 1)); // animation done
2631
expect(tester.findText('BottomSheet'), isNotNull);
@@ -29,7 +34,8 @@ void main() {
2934
tester.tap(tester.findText('BottomSheet'));
3035
tester.pump(); // bottom sheet dismiss animation starts
3136
tester.pump(new Duration(seconds: 1)); // animation done
32-
tester.pump(new Duration(seconds: 2)); // rebuild frame
37+
tester.pump(new Duration(seconds: 1)); // rebuild frame
38+
expect(showBottomSheetThenCalled, isTrue);
3339
expect(tester.findText('BottomSheet'), isNull);
3440

3541
showModalBottomSheet(context: context, child: new Text('BottomSheet'));
@@ -41,7 +47,7 @@ void main() {
4147
tester.tapAt(new Point(20.0, 20.0));
4248
tester.pump(); // bottom sheet dismiss animation starts
4349
tester.pump(new Duration(seconds: 1)); // animation done
44-
tester.pump(new Duration(seconds: 2)); // rebuild frame
50+
tester.pump(new Duration(seconds: 1)); // rebuild frame
4551
expect(tester.findText('BottomSheet'), isNull);
4652
});
4753
});
@@ -50,6 +56,8 @@ void main() {
5056
testWidgets((WidgetTester tester) {
5157
GlobalKey<PlaceholderState> _bottomSheetPlaceholderKey = new GlobalKey<PlaceholderState>();
5258
BuildContext context;
59+
bool showBottomSheetThenCalled = false;
60+
5361
tester.pumpWidget(new MaterialApp(
5462
routes: <String, RouteBuilder>{
5563
'/': (RouteArguments args) {
@@ -69,7 +77,9 @@ void main() {
6977
context: context,
7078
child: new Container(child: new Text('BottomSheet'), margin: new EdgeDims.all(40.0)),
7179
placeholderKey: _bottomSheetPlaceholderKey
72-
);
80+
).then((_) {
81+
showBottomSheetThenCalled = true;
82+
});
7383

7484
expect(_bottomSheetPlaceholderKey.currentState.child, isNotNull);
7585
tester.pump(); // bottom sheet show animation starts
@@ -79,7 +89,8 @@ void main() {
7989
tester.fling(tester.findText('BottomSheet'), const Offset(0.0, 20.0), 1000.0);
8090
tester.pump(); // bottom sheet dismiss animation starts
8191
tester.pump(new Duration(seconds: 1)); // animation done
82-
tester.pump(new Duration(seconds: 2)); // rebuild frame without the bottom sheet
92+
tester.pump(new Duration(seconds: 1)); // rebuild frame without the bottom sheet
93+
expect(showBottomSheetThenCalled, isTrue);
8394
expect(tester.findText('BottomSheet'), isNull);
8495
expect(_bottomSheetPlaceholderKey.currentState.child, isNull);
8596
});

packages/unit/test/widget/snack_bar_test.dart

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,22 @@ void main() {
99
String helloSnackBar = 'Hello SnackBar';
1010
GlobalKey<PlaceholderState> placeholderKey = new GlobalKey<PlaceholderState>();
1111
Key tapTarget = new Key('tap-target');
12+
BuildContext context;
13+
bool showSnackBarThenCalled = false;
1214

1315
tester.pumpWidget(new MaterialApp(
1416
routes: <String, RouteBuilder>{
1517
'/': (RouteArguments args) {
18+
context = args.context;
1619
return new GestureDetector(
1720
onTap: () {
1821
showSnackBar(
1922
context: args.context,
2023
placeholderKey: placeholderKey,
2124
content: new Text(helloSnackBar)
22-
);
25+
).then((_) {
26+
showSnackBarThenCalled = true;
27+
});
2328
},
2429
child: new Container(
2530
decoration: const BoxDecoration(
@@ -36,10 +41,16 @@ void main() {
3641
));
3742

3843
tester.tap(tester.findElementByKey(tapTarget));
39-
4044
expect(tester.findText(helloSnackBar), isNull);
4145
tester.pump();
4246
expect(tester.findText(helloSnackBar), isNotNull);
47+
48+
Navigator.of(context).pop();
49+
expect(tester.findText(helloSnackBar), isNotNull);
50+
tester.pump(new Duration(seconds: 1));
51+
expect(showSnackBarThenCalled, isTrue);
52+
expect(tester.findText(helloSnackBar), isNull);
53+
expect(placeholderKey.currentState.child, isNull);
4354
});
4455
});
4556
}

0 commit comments

Comments
 (0)