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