Commit 85a60a16 authored by Adam Barth's avatar Adam Barth

Merge pull request #696 from abarth/fix_drawer

Fix a large number of Drawer bugs
parents 17533e1d 1d195cb9
......@@ -55,6 +55,7 @@ class FeedFragment extends StatefulComponent {
class FeedFragmentState extends State<FeedFragment> {
FitnessMode _fitnessMode = FitnessMode.feed;
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
void _handleFitnessModeChange(FitnessMode value) {
setState(() {
......@@ -63,9 +64,8 @@ class FeedFragmentState extends State<FeedFragment> {
Navigator.pop(context);
}
void _showDrawer() {
showDrawer(
context: context,
Widget _buildDrawer() {
return new Drawer(
child: new Block(<Widget>[
new DrawerHeader(child: new Text('Fitness')),
new DrawerItem(
......@@ -106,7 +106,7 @@ class FeedFragmentState extends State<FeedFragment> {
return new ToolBar(
left: new IconButton(
icon: "navigation/menu",
onPressed: _showDrawer),
onPressed: () => _scaffoldKey.currentState?.openDrawer()),
center: new Text(fitnessModeTitle)
);
}
......@@ -207,9 +207,11 @@ class FeedFragmentState extends State<FeedFragment> {
Widget build(BuildContext context) {
return new Scaffold(
key: _scaffoldKey,
toolBar: buildToolBar(),
body: buildBody(),
floatingActionButton: buildFloatingActionButton()
floatingActionButton: buildFloatingActionButton(),
drawer: _buildDrawer()
);
}
}
......
......@@ -6,19 +6,25 @@ import 'package:flutter/material.dart';
import 'demo/widget_demo.dart';
class GalleryPage extends StatelessComponent {
class GalleryPage extends StatefulComponent {
GalleryPage({ this.demos, this.active, this.onThemeChanged });
final List<WidgetDemo> demos;
final WidgetDemo active;
final ValueChanged<ThemeData> onThemeChanged;
void _showDrawer(BuildContext context) {
_GalleryPageState createState() => new _GalleryPageState();
}
class _GalleryPageState extends State<GalleryPage> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
Widget _buildDrawer() {
List<Widget> items = <Widget>[
new DrawerHeader(child: new Text('Material demos')),
];
for (WidgetDemo demo in demos) {
for (WidgetDemo demo in config.demos) {
items.add(new DrawerItem(
onPressed: () {
Navigator.pushNamed(context, demo.routeName);
......@@ -27,12 +33,12 @@ class GalleryPage extends StatelessComponent {
));
}
showDrawer(context: context, child: new Block(items));
return new Drawer(child: new Block(items));
}
Widget _body(BuildContext context) {
if (active != null)
return active.builder(context);
Widget _buildBody() {
if (config.active != null)
return config.active.builder(context);
return new Material(
child: new Center(
child: new Text('Select a demo from the drawer')
......@@ -40,22 +46,24 @@ class GalleryPage extends StatelessComponent {
);
}
Widget _tabBar(BuildContext context) {
final WidgetBuilder builder = active?.tabBarBuilder;
Widget _buildTabBar() {
final WidgetBuilder builder = config.active?.tabBarBuilder;
return builder != null ? builder(context) : null;
}
Widget build(BuildContext context) {
return new Scaffold(
key: _scaffoldKey,
toolBar: new ToolBar(
left: new IconButton(
icon: 'navigation/menu',
onPressed: () { _showDrawer(context); }
onPressed: () { _scaffoldKey.currentState?.openDrawer(); }
),
center: new Text(active?.title ?? 'Material gallery'),
tabBar: _tabBar(context)
center: new Text(config.active?.title ?? 'Material gallery'),
tabBar: _buildTabBar()
),
body: _body(context)
drawer: _buildDrawer(),
body: _buildBody()
);
}
}
......@@ -21,7 +21,7 @@ class StockHome extends StatefulComponent {
class StockHomeState extends State<StockHome> {
final GlobalKey scaffoldKey = new GlobalKey();
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
final TabBarSelection _tabBarSelection = new TabBarSelection();
bool _isSearching = false;
String _searchQuery;
......@@ -70,9 +70,8 @@ class StockHomeState extends State<StockHome> {
);
}
void _showDrawer() {
showDrawer(
context: context,
Widget _buildDrawer(BuildContext context) {
return new Drawer(
child: new Block(<Widget>[
new DrawerHeader(child: new Text('Stocks')),
new DrawerItem(
......@@ -151,7 +150,7 @@ class StockHomeState extends State<StockHome> {
elevation: 0,
left: new IconButton(
icon: "navigation/menu",
onPressed: _showDrawer
onPressed: () => _scaffoldKey.currentState?.openDrawer()
),
center: new FadeTransition(
opacity: new AnimatedValue<double>(
......@@ -200,7 +199,7 @@ class StockHomeState extends State<StockHome> {
stock.percentChange = 100.0 * (1.0 / stock.lastSale);
stock.lastSale += 1.0;
});
scaffoldKey.currentState.showSnackBar(new SnackBar(
_scaffoldKey.currentState.showSnackBar(new SnackBar(
content: new Text("Purchased ${stock.symbol} for ${stock.lastSale}"),
actions: <SnackBarAction>[
new SnackBarAction(label: "BUY MORE", onPressed: () { _buyStock(stock, arrowKey); })
......@@ -219,7 +218,7 @@ class StockHomeState extends State<StockHome> {
Navigator.pushNamed(context, '/stock/${stock.symbol}', mostValuableKeys: mostValuableKeys);
},
onShow: (Stock stock, Key arrowKey) {
scaffoldKey.currentState.showBottomSheet((BuildContext context) => new StockSymbolBottomSheet(stock: stock));
_scaffoldKey.currentState.showBottomSheet((BuildContext context) => new StockSymbolBottomSheet(stock: stock));
}
);
}
......@@ -285,9 +284,10 @@ class StockHomeState extends State<StockHome> {
Widget build(BuildContext context) {
return new Scaffold(
key: scaffoldKey,
key: _scaffoldKey,
toolBar: _isSearching ? buildSearchBar() : buildToolBar(),
floatingActionButton: buildFloatingActionButton(),
drawer: _buildDrawer(context),
body: new SizeObserver(
onSizeChanged: _handleSizeChanged,
child: new TabBarView<StockHomeTab>(
......
......@@ -46,6 +46,8 @@ class CardCollectionState extends State<CardCollection> {
InvalidatorCallback _invalidator;
Size _cardCollectionSize = new Size(200.0, 200.0);
GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
void _initVariableSizedCardModels() {
List<double> cardHeights = <double>[
48.0, 63.0, 82.0, 146.0, 60.0, 55.0, 84.0, 96.0, 50.0,
......@@ -117,9 +119,8 @@ class CardCollectionState extends State<CardCollection> {
}
}
void _showDrawer() {
showDrawer(
context: context,
Widget _buildDrawer() {
return new Drawer(
child: new IconTheme(
data: const IconThemeData(color: IconThemeColor.black),
child: new Block(<Widget>[
......@@ -265,9 +266,9 @@ class CardCollectionState extends State<CardCollection> {
);
}
Widget buildToolBar() {
Widget _buildToolBar() {
return new ToolBar(
left: new IconButton(icon: "navigation/menu", onPressed: _showDrawer),
left: new IconButton(icon: "navigation/menu", onPressed: () => _scaffoldKey.currentState?.openDrawer()),
right: <Widget>[
new Text(_dismissDirectionText(_dismissDirection))
],
......@@ -281,7 +282,7 @@ class CardCollectionState extends State<CardCollection> {
);
}
Widget buildCard(BuildContext context, int index) {
Widget _buildCard(BuildContext context, int index) {
if (index >= _cardModels.length)
return null;
......@@ -393,19 +394,18 @@ class CardCollectionState extends State<CardCollection> {
}
Widget build(BuildContext context) {
Widget cardCollection;
if (_fixedSizeCards) {
cardCollection = new ScrollableList<CardModel> (
snapOffsetCallback: _snapToCenter ? _toSnapOffset : null,
snapAlignmentOffset: _cardCollectionSize.height / 2.0,
items: _cardModels,
itemBuilder: (BuildContext context, CardModel card, int index) => buildCard(context, card.value),
itemBuilder: (BuildContext context, CardModel card, int index) => _buildCard(context, card.value),
itemExtent: _cardModels[0].height
);
} else {
cardCollection = new ScrollableMixedWidgetList(
builder: buildCard,
builder: _buildCard,
token: _cardModels.length,
snapOffsetCallback: _snapToCenter ? _toSnapOffset : null,
snapAlignmentOffset: _cardCollectionSize.height / 2.0,
......@@ -446,7 +446,8 @@ class CardCollectionState extends State<CardCollection> {
primarySwatch: _primaryColor
),
child: new Scaffold(
toolBar: buildToolBar(),
toolBar: _buildToolBar(),
drawer: _buildDrawer(),
body: body
)
);
......
......@@ -41,6 +41,8 @@ class PageableListAppState extends State<PageableListApp> {
ScrollDirection scrollDirection = ScrollDirection.horizontal;
bool itemsWrap = false;
GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
void updatePageSize(Size newSize) {
setState(() {
pageSize = newSize;
......@@ -83,9 +85,8 @@ class PageableListAppState extends State<PageableListApp> {
});
}
void _showDrawer() {
showDrawer(
context: context,
Widget _buildDrawer() {
return new Drawer(
child: new Block(<Widget>[
new DrawerHeader(child: new Text('Options')),
new DrawerItem(
......@@ -111,9 +112,9 @@ class PageableListAppState extends State<PageableListApp> {
);
}
Widget buildToolBar() {
Widget _buildToolBar() {
return new ToolBar(
left: new IconButton(icon: "navigation/menu", onPressed: _showDrawer),
left: new IconButton(icon: "navigation/menu", onPressed: () => _scaffoldKey.currentState?.openDrawer()),
center: new Text('PageableList'),
right: <Widget>[
new Text(scrollDirection == ScrollDirection.horizontal ? "horizontal" : "vertical")
......@@ -121,7 +122,7 @@ class PageableListAppState extends State<PageableListApp> {
);
}
Widget buildBody(BuildContext context) {
Widget _buildBody(BuildContext context) {
Widget list = new PageableList<CardModel>(
items: cardModels,
itemsWrap: itemsWrap,
......@@ -141,8 +142,9 @@ class PageableListAppState extends State<PageableListApp> {
return new IconTheme(
data: const IconThemeData(color: IconThemeColor.white),
child: new Scaffold(
toolBar: buildToolBar(),
body: buildBody(context)
toolBar: _buildToolBar(),
drawer: _buildDrawer(),
body: _buildBody(context)
)
);
}
......
......@@ -22,111 +22,48 @@ import 'material.dart';
// The right nav can vary depending on content.
const double _kWidth = 304.0;
const double _kEdgeDragWidth = 20.0;
const double _kMinFlingVelocity = 365.0;
const Duration _kBaseSettleDuration = const Duration(milliseconds: 246);
class _Drawer extends StatelessComponent {
_Drawer({ Key key, this.route }) : super(key: key);
final _DrawerRoute route;
Widget build(BuildContext context) {
return new Focus(
key: new GlobalObjectKey(route),
child: new ConstrainedBox(
constraints: const BoxConstraints.expand(width: _kWidth),
child: new Material(
elevation: route.elevation,
child: route.child
)
)
);
}
}
enum _DrawerState {
showing,
popped,
closed,
}
class _DrawerRoute extends OverlayRoute {
_DrawerRoute({ this.child, this.elevation });
class Drawer extends StatelessComponent {
Drawer({
Key key,
this.elevation: 16,
this.child
}) : super(key: key);
final Widget child;
final int elevation;
final Widget child;
List<WidgetBuilder> get builders => <WidgetBuilder>[ _build ];
final GlobalKey<_DrawerControllerState> _drawerKey = new GlobalKey<_DrawerControllerState>();
_DrawerState _state = _DrawerState.showing;
Widget _build(BuildContext context) {
return new RepaintBoundary(
child: new _DrawerController(
key: _drawerKey,
settleDuration: _kBaseSettleDuration,
onClosed: () {
_DrawerState previousState = _state;
_state = _DrawerState.closed;
switch (previousState) {
case _DrawerState.showing:
Navigator.pop(context);
break;
case _DrawerState.popped:
finished();
break;
case _DrawerState.closed:
assert(false);
break;
}
},
child: new _Drawer(route: this)
Widget build(BuildContext context) {
return new ConstrainedBox(
constraints: const BoxConstraints.expand(width: _kWidth),
child: new Material(
elevation: elevation,
child: child
)
);
}
bool didPop(dynamic result) {
// we don't call the superclass because we want to control the timing of the
// call to finished().
switch (_state) {
case _DrawerState.showing:
_drawerKey.currentState?._close();
_state = _DrawerState.popped;
break;
case _DrawerState.popped:
assert(false);
break;
case _DrawerState.closed:
finished();
break;
}
return true;
}
}
class _DrawerController extends StatefulComponent {
_DrawerController({
Key key,
this.settleDuration,
this.onClosed,
class DrawerController extends StatefulComponent {
DrawerController({
GlobalKey key,
this.child
}) : super(key: key);
final Duration settleDuration;
final Widget child;
final VoidCallback onClosed;
_DrawerControllerState createState() => new _DrawerControllerState();
DrawerControllerState createState() => new DrawerControllerState();
}
class _DrawerControllerState extends State<_DrawerController> {
class DrawerControllerState extends State<DrawerController> {
void initState() {
super.initState();
_performance = new Performance(duration: config.settleDuration)
_performance = new Performance(duration: _kBaseSettleDuration)
..addListener(_performanceChanged)
..addStatusListener(_performanceStatusChanged)
..play();
..addStatusListener(_performanceStatusChanged);
}
void dispose() {
......@@ -143,15 +80,41 @@ class _DrawerControllerState extends State<_DrawerController> {
});
}
LocalHistoryEntry _historyEntry;
void _ensureHistoryEntry() {
if (_historyEntry == null) {
ModalRoute route = ModalRoute.of(context);
if (route != null) {
_historyEntry = new LocalHistoryEntry(onRemove: _handleHistoryEntryRemoved);
route.addLocalHistoryEntry(_historyEntry);
}
}
}
void _performanceStatusChanged(PerformanceStatus status) {
if (status == PerformanceStatus.dismissed && config.onClosed != null)
config.onClosed();
switch (status) {
case PerformanceStatus.forward:
_ensureHistoryEntry();
break;
case PerformanceStatus.reverse:
_historyEntry?.remove();
_historyEntry = null;
break;
case PerformanceStatus.dismissed:
break;
case PerformanceStatus.completed:
break;
}
}
Performance _performance;
double _width;
void _handleHistoryEntryRemoved() {
_historyEntry = null;
close();
}
final AnimatedColorValue _color = new AnimatedColorValue(Colors.transparent, end: Colors.black54);
Performance _performance;
double _width = _kEdgeDragWidth;
void _handleSizeChanged(Size newSize) {
setState(() {
......@@ -161,6 +124,7 @@ class _DrawerControllerState extends State<_DrawerController> {
void _handlePointerDown(_) {
_performance.stop();
_ensureHistoryEntry();
}
void _move(double delta) {
......@@ -168,57 +132,77 @@ class _DrawerControllerState extends State<_DrawerController> {
}
void _settle(Offset velocity) {
if (_performance.isDismissed)
return;
if (velocity.dx.abs() >= _kMinFlingVelocity) {
_performance.fling(velocity: velocity.dx / _width);
} else if (_performance.progress < 0.5) {
_close();
close();
} else {
_performance.fling(velocity: 1.0);
open();
}
}
void _close() {
void open() {
_performance.fling(velocity: 1.0);
}
void close() {
_performance.fling(velocity: -1.0);
}
final AnimatedColorValue _color = new AnimatedColorValue(Colors.transparent, end: Colors.black54);
Widget build(BuildContext context) {
_performance.updateVariable(_color);
return new GestureDetector(
onHorizontalDragUpdate: _move,
onHorizontalDragEnd: _settle,
child: new Stack(<Widget>[
new GestureDetector(
onTap: _close,
child: new DecoratedBox(
decoration: new BoxDecoration(
backgroundColor: _color.value
),
child: new Container()
)
),
new Positioned(
top: 0.0,
left: 0.0,
bottom: 0.0,
child: new Listener(
onPointerDown: _handlePointerDown,
child: new Align(
alignment: const FractionalOffset(1.0, 0.5),
widthFactor: _performance.progress,
child: new SizeObserver(
onSizeChanged: _handleSizeChanged,
child: new RepaintBoundary(
child: config.child
HitTestBehavior behavior;
Widget child;
if (_performance.status == PerformanceStatus.dismissed) {
behavior = HitTestBehavior.translucent;
child = new Align(
alignment: const FractionalOffset(0.0, 0.5),
widthFactor: 1.0,
child: new Container(width: _kEdgeDragWidth)
);
} else {
_performance.updateVariable(_color);
child = new RepaintBoundary(
child: new Stack(<Widget>[
new GestureDetector(
onTap: close,
child: new DecoratedBox(
decoration: new BoxDecoration(
backgroundColor: _color.value
),
child: new Container()
)
),
new Align(
alignment: const FractionalOffset(0.0, 0.5),
child: new Listener(
onPointerDown: _handlePointerDown,
child: new Align(
alignment: const FractionalOffset(1.0, 0.5),
widthFactor: _performance.progress,
child: new SizeObserver(
onSizeChanged: _handleSizeChanged,
child: new RepaintBoundary(
child: new Focus(
key: new GlobalObjectKey(config.key),
child: config.child
)
)
)
)
)
)
)
])
])
);
}
return new GestureDetector(
onHorizontalDragUpdate: _move,
onHorizontalDragEnd: _settle,
behavior: behavior,
child: child
);
}
}
void showDrawer({ BuildContext context, Widget child, int elevation: 16 }) {
Navigator.push(context, new _DrawerRoute(child: child, elevation: elevation));
}
......@@ -15,20 +15,30 @@ import 'bottom_sheet.dart';
import 'material.dart';
import 'snack_bar.dart';
import 'tool_bar.dart';
import 'drawer.dart';
const double _kFloatingActionButtonMargin = 16.0; // TODO(hmuller): should be device dependent
enum _Child { body, toolBar, bottomSheet, snackBar, floatingActionButton }
enum _Child {
body,
toolBar,
bottomSheet,
snackBar,
floatingActionButton,
drawer,
}
class _ScaffoldLayout extends MultiChildLayoutDelegate {
void performLayout(Size size, BoxConstraints constraints) {
BoxConstraints looseConstraints = constraints.loosen();
// This part of the layout has the same effect as putting the toolbar and
// body in a column and making the body flexible. What's different is that
// in this case the toolbar appears -after- the body in the stacking order,
// so the toolbar's shadow is drawn on top of the body.
final BoxConstraints toolBarConstraints = constraints.loosen().tightenWidth(size.width);
final BoxConstraints toolBarConstraints = looseConstraints.tightenWidth(size.width);
Size toolBarSize = Size.zero;
if (isChild(_Child.toolBar)) {
......@@ -52,7 +62,7 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate {
// non-zero height then it's inset from the parent's right and bottom edges
// by _kFloatingActionButtonMargin.
final BoxConstraints fullWidthConstraints = constraints.loosen().tightenWidth(size.width);
final BoxConstraints fullWidthConstraints = looseConstraints.tightenWidth(size.width);
Size bottomSheetSize = Size.zero;
Size snackBarSize = Size.zero;
......@@ -67,7 +77,7 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate {
}
if (isChild(_Child.floatingActionButton)) {
final Size fabSize = layoutChild(_Child.floatingActionButton, constraints.loosen());
final Size fabSize = layoutChild(_Child.floatingActionButton, looseConstraints);
final double fabX = size.width - fabSize.width - _kFloatingActionButtonMargin;
double fabY = size.height - fabSize.height - _kFloatingActionButtonMargin;
if (snackBarSize.height > 0.0)
......@@ -76,6 +86,11 @@ class _ScaffoldLayout extends MultiChildLayoutDelegate {
fabY = math.min(fabY, size.height - bottomSheetSize.height - fabSize.height / 2.0);
positionChild(_Child.floatingActionButton, new Point(fabX, fabY));
}
if (isChild(_Child.drawer)) {
layoutChild(_Child.drawer, looseConstraints);
positionChild(_Child.drawer, Point.origin);
}
}
}
......@@ -86,12 +101,14 @@ class Scaffold extends StatefulComponent {
Key key,
this.toolBar,
this.body,
this.floatingActionButton
this.floatingActionButton,
this.drawer
}) : super(key: key);
final ToolBar toolBar;
final Widget body;
final Widget floatingActionButton;
final Widget drawer;
static ScaffoldState of(BuildContext context) => context.ancestorStateOfType(ScaffoldState);
......@@ -100,6 +117,14 @@ class Scaffold extends StatefulComponent {
class ScaffoldState extends State<Scaffold> {
// DRAWER API
final GlobalKey<DrawerControllerState> _drawerKey = new GlobalKey<DrawerControllerState>();
void openDrawer() {
_drawerKey.currentState.open();
}
// SNACKBAR API
Queue<ScaffoldFeatureController<SnackBar>> _snackBars = new Queue<ScaffoldFeatureController<SnackBar>>();
......@@ -270,6 +295,16 @@ class ScaffoldState extends State<Scaffold> {
_addIfNonNull(children, config.floatingActionButton, _Child.floatingActionButton);
if (config.drawer != null) {
children.add(new LayoutId(
id: _Child.drawer,
child: new DrawerController(
key: _drawerKey,
child: config.drawer
)
));
}
return new CustomMultiChildLayout(children, delegate: _scaffoldLayout);
}
......
......@@ -146,7 +146,7 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
super.dispose();
}
final ProxyPerformance forwardPerformance = new ProxyPerformance();
void didPushNext(Route nextRoute) {
......@@ -183,7 +183,7 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
forwardPerformance,
buildTransition(
context,
performance,
performance,
child
)
);
......@@ -202,6 +202,7 @@ class LocalHistoryEntry {
LocalHistoryRoute _owner;
void remove() {
_owner.removeLocalHistoryEntry(this);
assert(_owner == null);
}
void _notifyRemoved() {
if (onRemove != null)
......@@ -432,4 +433,4 @@ abstract class PageRoute<T> extends ModalRoute<T> {
NamedRouteSettings settings: const NamedRouteSettings()
}) : super(completer: completer, settings: settings);
bool get opaque => true;
}
\ No newline at end of file
}
......@@ -11,20 +11,25 @@ void main() {
test('Drawer control test', () {
testWidgets((WidgetTester tester) {
GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
BuildContext context;
tester.pumpWidget(
new MaterialApp(
routes: <String, RouteBuilder>{
'/': (RouteArguments args) {
context = args.context;
return new Container();
return new Scaffold(
key: scaffoldKey,
drawer: new Text('drawer'),
body: new Container()
);
}
}
)
);
tester.pump(); // no effect
expect(tester.findText('drawer'), isNull);
showDrawer(context: context, child: new Text('drawer'));
scaffoldKey.currentState.openDrawer();
tester.pump(); // drawer should be starting to animate in
expect(tester.findText('drawer'), isNotNull);
tester.pump(new Duration(seconds: 1)); // animation done
......@@ -39,21 +44,24 @@ void main() {
test('Drawer tap test', () {
testWidgets((WidgetTester tester) {
BuildContext context;
GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
tester.pumpWidget(new Container()); // throw away the old App and its Navigator
tester.pumpWidget(
new MaterialApp(
routes: <String, RouteBuilder>{
'/': (RouteArguments args) {
context = args.context;
return new Container();
return new Scaffold(
key: scaffoldKey,
drawer: new Text('drawer'),
body: new Container()
);
}
}
)
);
tester.pump(); // no effect
expect(tester.findText('drawer'), isNull);
showDrawer(context: context, child: new Text('drawer'));
scaffoldKey.currentState.openDrawer();
tester.pump(); // drawer should be starting to animate in
expect(tester.findText('drawer'), isNotNull);
tester.pump(new Duration(seconds: 1)); // animation done
......@@ -64,7 +72,9 @@ void main() {
tester.pump(new Duration(seconds: 1)); // ditto
expect(tester.findText('drawer'), isNotNull);
tester.tapAt(const Point(750.0, 100.0)); // on the mask
tester.pump(); // drawer should be starting to animate away
tester.pump();
tester.pump(new Duration(milliseconds: 10));
// drawer should be starting to animate away
expect(tester.findText('drawer'), isNotNull);
tester.pump(new Duration(seconds: 1)); // animation done
expect(tester.findText('drawer'), 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