Commit 9b5599a4 authored by Adam Barth's avatar Adam Barth Committed by Ian Hickson

Add RTL support to Drawer (#11872)

Fixes #5215
parent 9cdfb95b
......@@ -69,7 +69,7 @@ class Drawer extends StatelessWidget {
const Drawer({
Key key,
this.elevation: 16.0,
this.child
this.child,
}) : super(key: key);
/// The z-coordinate at which to place this drawer. This controls the size of
......@@ -89,8 +89,8 @@ class Drawer extends StatelessWidget {
constraints: const BoxConstraints.expand(width: _kWidth),
child: new Material(
elevation: elevation,
child: child
)
child: child,
),
);
}
}
......@@ -117,7 +117,7 @@ class DrawerController extends StatefulWidget {
/// The [child] argument must not be null and is typically a [Drawer].
const DrawerController({
GlobalKey key,
@required this.child
@required this.child,
}) : assert(child != null),
super(key: key);
......@@ -217,14 +217,31 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro
}
void _move(DragUpdateDetails details) {
_controller.value += details.primaryDelta / _width;
final double delta = details.primaryDelta / _width;
switch (Directionality.of(context)) {
case TextDirection.rtl:
_controller.value -= delta;
break;
case TextDirection.ltr:
_controller.value += delta;
break;
}
}
void _settle(DragEndDetails details) {
if (_controller.isDismissed)
return;
if (details.velocity.pixelsPerSecond.dx.abs() >= _kMinFlingVelocity) {
_controller.fling(velocity: details.velocity.pixelsPerSecond.dx / _width);
final double visualVelocity = details.velocity.pixelsPerSecond.dx / _width;
switch (Directionality.of(context)) {
case TextDirection.rtl:
_controller.fling(velocity: -visualVelocity);
break;
case TextDirection.ltr:
_controller.fling(velocity: visualVelocity);
break;
}
} else if (_controller.value < 0.5) {
close();
} else {
......@@ -250,7 +267,7 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro
Widget _buildDrawer(BuildContext context) {
if (_controller.status == AnimationStatus.dismissed) {
return new Align(
alignment: FractionalOffset.centerLeft,
alignment: FractionalOffsetDirectional.centerStart,
child: new GestureDetector(
key: _gestureDetectorKey,
onHorizontalDragUpdate: _move,
......@@ -282,9 +299,9 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro
),
),
new Align(
alignment: FractionalOffset.centerLeft,
alignment: FractionalOffsetDirectional.centerStart,
child: new Align(
alignment: FractionalOffset.centerRight,
alignment: FractionalOffsetDirectional.centerEnd,
widthFactor: _controller.value,
child: new RepaintBoundary(
child: new FocusScope(
......
......@@ -23,11 +23,11 @@ void main() {
return new Scaffold(
key: scaffoldKey,
drawer: const Text('drawer'),
body: new Container()
body: new Container(),
);
}
)
)
},
),
),
);
await tester.pump(); // no effect
expect(find.text('drawer'), findsNothing);
......@@ -50,9 +50,9 @@ void main() {
home: new Scaffold(
key: scaffoldKey,
drawer: const Text('drawer'),
body: new Container()
)
)
body: new Container(),
),
),
);
await tester.pump(); // no effect
expect(find.text('drawer'), findsNothing);
......@@ -75,7 +75,7 @@ void main() {
expect(find.text('drawer'), findsNothing);
});
testWidgets('Drawer drag cancel resume', (WidgetTester tester) async {
testWidgets('Drawer drag cancel resume (LTR)', (WidgetTester tester) async {
final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
await tester.pumpWidget(
new MaterialApp(
......@@ -89,12 +89,12 @@ void main() {
height: 1000.0,
color: Colors.blue[500],
),
]
)
],
),
),
body: new Container()
)
)
body: new Container(),
),
),
);
expect(find.text('drawer'), findsNothing);
scaffoldKey.currentState.openDrawer();
......@@ -107,21 +107,73 @@ void main() {
await tester.pump();
await tester.pump(const Duration(milliseconds: 10));
// drawer should be starting to animate away
final RenderBox textBox = tester.renderObject(find.text('drawer'));
final double textLeft = textBox.localToGlobal(Offset.zero).dx;
final double textLeft = tester.getTopLeft(find.text('drawer')).dx;
expect(textLeft, lessThan(0.0));
final TestGesture gesture = await tester.startGesture(const Offset(100.0, 100.0));
// drawer should be stopped.
await tester.pump();
await tester.pump(const Duration(milliseconds: 10));
expect(textBox.localToGlobal(Offset.zero).dx, equals(textLeft));
expect(tester.getTopLeft(find.text('drawer')).dx, equals(textLeft));
await gesture.moveBy(const Offset(0.0, 50.0));
await gesture.moveBy(const Offset(50.0, 0.0));
// drawer should be returning to visible
await tester.pump();
await tester.pump(const Duration(seconds: 1));
expect(textBox.localToGlobal(Offset.zero).dx, equals(0.0));
expect(tester.getTopLeft(find.text('drawer')).dx, equals(0.0));
await gesture.up();
});
testWidgets('Drawer drag cancel resume (RTL)', (WidgetTester tester) async {
final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
await tester.pumpWidget(
new MaterialApp(
home: new Directionality(
textDirection: TextDirection.rtl,
child: new Scaffold(
key: scaffoldKey,
drawer: new Drawer(
child: new ListView(
children: <Widget>[
const Text('drawer'),
new Container(
height: 1000.0,
color: Colors.blue[500],
),
],
),
),
body: new Container(),
),
),
),
);
expect(find.text('drawer'), findsNothing);
scaffoldKey.currentState.openDrawer();
await tester.pump(); // drawer should be starting to animate in
expect(find.text('drawer'), findsOneWidget);
await tester.pump(const Duration(seconds: 1)); // animation done
expect(find.text('drawer'), findsOneWidget);
await tester.tapAt(const Offset(50.0, 100.0)); // on the mask
await tester.pump();
await tester.pump(const Duration(milliseconds: 10));
// drawer should be starting to animate away
final double textRight = tester.getTopRight(find.text('drawer')).dx;
expect(textRight, greaterThan(800.0));
final TestGesture gesture = await tester.startGesture(const Offset(700.0, 100.0));
// drawer should be stopped.
await tester.pump();
await tester.pump(const Duration(milliseconds: 10));
expect(tester.getTopRight(find.text('drawer')).dx, equals(textRight));
await gesture.moveBy(const Offset(-50.0, 0.0));
// drawer should be returning to visible
await tester.pump();
await tester.pump(const Duration(seconds: 1));
expect(tester.getTopRight(find.text('drawer')).dx, equals(800.0));
await gesture.up();
});
......@@ -142,21 +194,21 @@ void main() {
const Text('drawer'),
new FlatButton(
child: const Text('close'),
onPressed: () => Navigator.pop(context)
onPressed: () => Navigator.pop(context),
),
]
)
],
),
),
body: new Container(
child: new FlatButton(
child: const Text('button'),
onPressed: () { buttonPressed = true; }
)
)
onPressed: () { buttonPressed = true; },
),
),
);
}
)
)
},
),
),
);
// Open the drawer.
......@@ -183,16 +235,16 @@ void main() {
final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
await tester.pumpWidget(
new MaterialApp(
home: new Builder(
builder: (BuildContext context) {
return new Scaffold(
key: scaffoldKey,
drawer: const Drawer(),
);
}
)
)
new MaterialApp(
home: new Builder(
builder: (BuildContext context) {
return new Scaffold(
key: scaffoldKey,
drawer: const Drawer(),
);
},
),
),
);
// Open the drawer.
......@@ -211,17 +263,17 @@ void main() {
final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>();
await tester.pumpWidget(
new MaterialApp(
home: new Builder(
builder: (BuildContext context) {
return new Scaffold(
key: scaffoldKey,
drawer: const Drawer(),
body: new Container()
);
}
)
)
new MaterialApp(
home: new Builder(
builder: (BuildContext context) {
return new Scaffold(
key: scaffoldKey,
drawer: const Drawer(),
body: new Container(),
);
},
),
),
);
// Open the drawer.
......
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