From 0d91c0343bdcb950c9ffadda8051fe44446ec291 Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Thu, 12 Jan 2023 16:22:53 +0200 Subject: [PATCH] Fix M3 `Drawer` default shape in RTL (#118185) --- .../gen_defaults/lib/drawer_template.dart | 23 ++- packages/flutter/lib/src/material/drawer.dart | 23 ++- .../flutter/test/material/drawer_test.dart | 166 ++++++++++++++++++ 3 files changed, 194 insertions(+), 18 deletions(-) diff --git a/dev/tools/gen_defaults/lib/drawer_template.dart b/dev/tools/gen_defaults/lib/drawer_template.dart index cacf1871a9ecf..6a21403c8016f 100644 --- a/dev/tools/gen_defaults/lib/drawer_template.dart +++ b/dev/tools/gen_defaults/lib/drawer_template.dart @@ -10,10 +10,11 @@ class DrawerTemplate extends TokenTemplate { @override String generate() => ''' class _${blockName}DefaultsM3 extends DrawerThemeData { - const _${blockName}DefaultsM3(this.context) + _${blockName}DefaultsM3(this.context) : super(elevation: ${elevation("md.comp.navigation-drawer.modal.container")}); final BuildContext context; + late final TextDirection direction = Directionality.of(context); @override Color? get backgroundColor => ${componentColor("md.comp.navigation-drawer.container")}; @@ -24,18 +25,22 @@ class _${blockName}DefaultsM3 extends DrawerThemeData { @override Color? get shadowColor => ${colorOrTransparent("md.comp.navigation-drawer.container.shadow-color")}; - // This don't appear to be tokens for this value, but it is - // shown in the spec. + // There isn't currently a token for this value, but it is shown in the spec, + // so hard coding here for now. @override - ShapeBorder? get shape => const RoundedRectangleBorder( - borderRadius: BorderRadius.horizontal(right: Radius.circular(16.0)), + ShapeBorder? get shape => RoundedRectangleBorder( + borderRadius: const BorderRadiusDirectional.horizontal( + end: Radius.circular(16.0), + ).resolve(direction), ); - // This don't appear to be tokens for this value, but it is - // shown in the spec. + // There isn't currently a token for this value, but it is shown in the spec, + // so hard coding here for now. @override - ShapeBorder? get endShape => const RoundedRectangleBorder( - borderRadius: BorderRadius.horizontal(left: Radius.circular(16.0)), + ShapeBorder? get endShape => RoundedRectangleBorder( + borderRadius: const BorderRadiusDirectional.horizontal( + start: Radius.circular(16.0), + ).resolve(direction), ); } '''; diff --git a/packages/flutter/lib/src/material/drawer.dart b/packages/flutter/lib/src/material/drawer.dart index 622d4893d1958..ef160c5a9fe1d 100644 --- a/packages/flutter/lib/src/material/drawer.dart +++ b/packages/flutter/lib/src/material/drawer.dart @@ -830,10 +830,11 @@ class _DrawerDefaultsM2 extends DrawerThemeData { // Token database version: v0_150 class _DrawerDefaultsM3 extends DrawerThemeData { - const _DrawerDefaultsM3(this.context) + _DrawerDefaultsM3(this.context) : super(elevation: 1.0); final BuildContext context; + late final TextDirection direction = Directionality.of(context); @override Color? get backgroundColor => Theme.of(context).colorScheme.surface; @@ -844,18 +845,22 @@ class _DrawerDefaultsM3 extends DrawerThemeData { @override Color? get shadowColor => Colors.transparent; - // This don't appear to be tokens for this value, but it is - // shown in the spec. + // There isn't currently a token for this value, but it is shown in the spec, + // so hard coding here for now. @override - ShapeBorder? get shape => const RoundedRectangleBorder( - borderRadius: BorderRadius.horizontal(right: Radius.circular(16.0)), + ShapeBorder? get shape => RoundedRectangleBorder( + borderRadius: const BorderRadiusDirectional.horizontal( + end: Radius.circular(16.0), + ).resolve(direction), ); - // This don't appear to be tokens for this value, but it is - // shown in the spec. + // There isn't currently a token for this value, but it is shown in the spec, + // so hard coding here for now. @override - ShapeBorder? get endShape => const RoundedRectangleBorder( - borderRadius: BorderRadius.horizontal(left: Radius.circular(16.0)), + ShapeBorder? get endShape => RoundedRectangleBorder( + borderRadius: const BorderRadiusDirectional.horizontal( + start: Radius.circular(16.0), + ).resolve(direction), ); } diff --git a/packages/flutter/test/material/drawer_test.dart b/packages/flutter/test/material/drawer_test.dart index 4c9aa6db94ece..6c80e53625c5c 100644 --- a/packages/flutter/test/material/drawer_test.dart +++ b/packages/flutter/test/material/drawer_test.dart @@ -567,4 +567,170 @@ void main() { final RenderBox box = tester.renderObject(find.byType(Drawer)); expect(box.size.width, equals(smallWidth)); }); + + testWidgets('Drawer default shape (ltr)', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: true), + home: const Directionality( + textDirection: TextDirection.ltr, + child: Scaffold( + drawer: Drawer(), + endDrawer: Drawer(), + ), + ), + ), + ); + + final Finder drawerMaterial = find.descendant( + of: find.byType(Drawer), + matching: find.byType(Material), + ); + + final ScaffoldState state = tester.firstState(find.byType(Scaffold)); + + // Open the drawer. + state.openDrawer(); + await tester.pump(); + await tester.pump(const Duration(seconds: 1)); + + // Test the drawer shape. + Material material = tester.widget(drawerMaterial); + expect( + material.shape, + const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topRight: Radius.circular(16.0), + bottomRight: Radius.circular(16.0), + ), + ), + ); + + // Close the opened drawer. + await tester.tapAt(const Offset(750, 300)); + await tester.pumpAndSettle(); + + // Open the end drawer. + state.openEndDrawer(); + await tester.pump(); + await tester.pump(const Duration(seconds: 1)); + + // Test the end drawer shape. + material = tester.widget(drawerMaterial); + expect( + material.shape, + const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16.0), + bottomLeft: Radius.circular(16.0), + ), + ), + ); + }); + + testWidgets('Drawer default shape (rtl)', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: true), + home: const Directionality( + textDirection: TextDirection.rtl, + child: Scaffold( + drawer: Drawer(), + endDrawer: Drawer(), + ), + ), + ), + ); + + final Finder drawerMaterial = find.descendant( + of: find.byType(Drawer), + matching: find.byType(Material), + ); + + final ScaffoldState state = tester.firstState(find.byType(Scaffold)); + + // Open the drawer. + state.openDrawer(); + await tester.pump(); + await tester.pump(const Duration(seconds: 1)); + + // Test the drawer shape. + Material material = tester.widget(drawerMaterial); + expect( + material.shape, + const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(16.0), + bottomLeft: Radius.circular(16.0), + ), + ), + ); + + // Close the opened drawer. + await tester.tapAt(const Offset(750, 300)); + await tester.pumpAndSettle(); + + // Open the end drawer. + state.openEndDrawer(); + await tester.pump(); + await tester.pump(const Duration(seconds: 1)); + + // Test the end drawer shape. + material = tester.widget(drawerMaterial); + expect( + material.shape, + const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topRight: Radius.circular(16.0), + bottomRight: Radius.circular(16.0), + ), + ), + ); + }); + + group('Material 2', () { + // Tests that are only relevant for Material 2. Once ThemeData.useMaterial3 + // is turned on by default, these tests can be removed. + + testWidgets('Drawer default shape', (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + theme: ThemeData(useMaterial3: false), + home: const Scaffold( + drawer: Drawer(), + endDrawer: Drawer(), + ), + ), + ); + + final Finder drawerMaterial = find.descendant( + of: find.byType(Drawer), + matching: find.byType(Material), + ); + + final ScaffoldState state = tester.firstState(find.byType(Scaffold)); + + // Open the drawer. + state.openDrawer(); + await tester.pump(); + await tester.pump(const Duration(seconds: 1)); + + // Test the drawer shape. + Material material = tester.widget(drawerMaterial); + expect(material.shape, null); + + // Close the opened drawer. + await tester.tapAt(const Offset(750, 300)); + await tester.pumpAndSettle(); + + // Open the end drawer. + state.openEndDrawer(); + await tester.pump(); + await tester.pump(const Duration(seconds: 1)); + + // Test the end drawer shape. + material = tester.widget(drawerMaterial); + expect(material.shape, null); + }); + }); }