From 069699ebde074c49f8eaa147f8e025ccaa2056f2 Mon Sep 17 00:00:00 2001 From: Rami <2364772+rami-a@users.noreply.github.com> Date: Wed, 1 Sep 2021 16:41:53 -0400 Subject: [PATCH] Add ability to customize drawer shape and color as well as theme drawer properties (#89237) --- packages/flutter/lib/material.dart | 1 + packages/flutter/lib/src/material/drawer.dart | 53 ++++- .../lib/src/material/drawer_theme.dart | 161 ++++++++++++++ .../flutter/lib/src/material/scaffold.dart | 3 +- .../flutter/lib/src/material/theme_data.dart | 15 ++ .../test/material/drawer_theme_test.dart | 202 ++++++++++++++++++ .../test/material/theme_data_test.dart | 14 ++ 7 files changed, 438 insertions(+), 11 deletions(-) create mode 100644 packages/flutter/lib/src/material/drawer_theme.dart create mode 100644 packages/flutter/test/material/drawer_theme_test.dart diff --git a/packages/flutter/lib/material.dart b/packages/flutter/lib/material.dart index 9f6363a15fc2b..c301410376d51 100644 --- a/packages/flutter/lib/material.dart +++ b/packages/flutter/lib/material.dart @@ -65,6 +65,7 @@ export 'src/material/divider.dart'; export 'src/material/divider_theme.dart'; export 'src/material/drawer.dart'; export 'src/material/drawer_header.dart'; +export 'src/material/drawer_theme.dart'; export 'src/material/dropdown.dart'; export 'src/material/elevated_button.dart'; export 'src/material/elevated_button_theme.dart'; diff --git a/packages/flutter/lib/src/material/drawer.dart b/packages/flutter/lib/src/material/drawer.dart index ca99185d61dce..727221bed1049 100644 --- a/packages/flutter/lib/src/material/drawer.dart +++ b/packages/flutter/lib/src/material/drawer.dart @@ -7,6 +7,7 @@ import 'package:flutter/widgets.dart'; import 'colors.dart'; import 'debug.dart'; +import 'drawer_theme.dart'; import 'list_tile.dart'; import 'material.dart'; import 'material_localizations.dart'; @@ -139,19 +140,36 @@ class Drawer extends StatelessWidget { /// The [elevation] must be non-negative. const Drawer({ Key? key, - this.elevation = 16.0, + this.backgroundColor, + this.elevation, + this.shape, this.child, this.semanticLabel, - }) : assert(elevation != null && elevation >= 0.0), + }) : assert(elevation == null || elevation >= 0.0), super(key: key); + /// Sets the color of the [Material] that holds all of the [Drawer]'s + /// contents. + /// + /// If this is null, then [DrawerThemeData.backgroundColor] is used. If that + /// is also null, then it falls back to [Material]'s default. + final Color? backgroundColor; + /// The z-coordinate at which to place this drawer relative to its parent. /// /// This controls the size of the shadow below the drawer. /// - /// Defaults to 16, the appropriate elevation for drawers. The value is - /// always non-negative. - final double elevation; + /// If this is null, then [DrawerThemeData.elevation] is used. If that + /// is also null, then it defaults to 16.0. + final double? elevation; + + /// The shape of the drawer. + /// + /// Defines the drawer's [Material.shape]. + /// + /// If this is null, then [DrawerThemeData.shape] is used. If that + /// is also null, then it falls back to [Material]'s default. + final ShapeBorder? shape; /// The widget below this widget in the tree. /// @@ -175,6 +193,7 @@ class Drawer extends StatelessWidget { @override Widget build(BuildContext context) { assert(debugCheckHasMaterialLocalizations(context)); + final DrawerThemeData drawerTheme = DrawerTheme.of(context); String? label = semanticLabel; switch (Theme.of(context).platform) { case TargetPlatform.iOS: @@ -194,7 +213,9 @@ class Drawer extends StatelessWidget { child: ConstrainedBox( constraints: const BoxConstraints.expand(width: _kWidth), child: Material( - elevation: elevation, + color: backgroundColor ?? drawerTheme.backgroundColor, + elevation: elevation ?? drawerTheme.elevation ?? 16.0, + shape: shape ?? drawerTheme.shape, child: child, ), ), @@ -277,9 +298,11 @@ class DrawerController extends StatefulWidget { /// {@endtemplate} final DragStartBehavior dragStartBehavior; - /// The color to use for the scrim that obscures primary content while a drawer is open. + /// The color to use for the scrim that obscures the underlying content while + /// a drawer is open. /// - /// By default, the color used is [Colors.black54] + /// If this is null, then [DrawerThemeData.scrimColor] is used. If that + /// is also null, then it defaults to [Colors.black54]. final Color? scrimColor; /// Determines if the [Drawer] can be opened with a drag gesture. @@ -317,7 +340,6 @@ class DrawerControllerState extends State with SingleTickerPro @override void initState() { super.initState(); - _scrimColorTween = _buildScrimColorTween(); _controller = AnimationController( value: widget.isDrawerOpen ? 1.0 : 0.0, duration: _kBaseSettleDuration, @@ -335,6 +357,12 @@ class DrawerControllerState extends State with SingleTickerPro super.dispose(); } + @override + void didChangeDependencies() { + super.didChangeDependencies(); + _scrimColorTween = _buildScrimColorTween(); + } + @override void didUpdateWidget(DrawerController oldWidget) { super.didUpdateWidget(oldWidget); @@ -492,7 +520,12 @@ class DrawerControllerState extends State with SingleTickerPro final GlobalKey _gestureDetectorKey = GlobalKey(); ColorTween _buildScrimColorTween() { - return ColorTween(begin: Colors.transparent, end: widget.scrimColor ?? Colors.black54); + return ColorTween( + begin: Colors.transparent, + end: widget.scrimColor + ?? DrawerTheme.of(context).scrimColor + ?? Colors.black54, + ); } AlignmentDirectional get _drawerOuterAlignment { diff --git a/packages/flutter/lib/src/material/drawer_theme.dart b/packages/flutter/lib/src/material/drawer_theme.dart new file mode 100644 index 0000000000000..fb87279195c51 --- /dev/null +++ b/packages/flutter/lib/src/material/drawer_theme.dart @@ -0,0 +1,161 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ui' show lerpDouble; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/widgets.dart'; + +import 'theme.dart'; + +/// Defines default property values for descendant [Drawer] widgets. +/// +/// Descendant widgets obtain the current [DrawerThemeData] object +/// using `DrawerTheme.of(context)`. Instances of [DrawerThemeData] can be +/// customized with [DrawerThemeData.copyWith]. +/// +/// Typically a [DrawerThemeData] is specified as part of the +/// overall [Theme] with [ThemeData.drawerTheme]. +/// +/// All [DrawerThemeData] properties are `null` by default. +/// +/// See also: +/// +/// * [DrawerTheme], an [InheritedWidget] that propagates the theme down its +/// subtree. +/// * [ThemeData], which describes the overall theme information for the +/// application and can customize a drawer using [ThemeData.drawerTheme]. +@immutable +class DrawerThemeData with Diagnosticable { + /// Creates a theme that can be used for [ThemeData.drawerTheme] and + /// [DrawerTheme]. + const DrawerThemeData({ + this.backgroundColor, + this.scrimColor, + this.elevation, + this.shape, + }); + + /// Overrides the default value of [Drawer.backgroundColor]. + final Color? backgroundColor; + + /// Overrides the default value of [DrawerController.scrimColor]. + final Color? scrimColor; + + /// Overrides the default value of [Drawer.elevation]. + final double? elevation; + + /// Overrides the default value of [Drawer.shape]. + final ShapeBorder? shape; + + /// Creates a copy of this object with the given fields replaced with the + /// new values. + DrawerThemeData copyWith({ + Color? backgroundColor, + Color? scrimColor, + double? elevation, + ShapeBorder? shape, + }) { + return DrawerThemeData( + backgroundColor: backgroundColor ?? this.backgroundColor, + scrimColor: scrimColor ?? this.scrimColor, + elevation: elevation ?? this.elevation, + shape: shape ?? this.shape, + ); + } + + /// Linearly interpolate between two drawer themes. + /// + /// If both arguments are null then null is returned. + /// + /// {@macro dart.ui.shadow.lerp} + static DrawerThemeData? lerp(DrawerThemeData? a, DrawerThemeData? b, double t) { + assert(t != null); + if (a == null && b == null) + return null; + return DrawerThemeData( + backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t), + scrimColor: Color.lerp(a?.scrimColor, b?.scrimColor, t), + elevation: lerpDouble(a?.elevation, b?.elevation, t), + shape: ShapeBorder.lerp(a?.shape, b?.shape, t), + ); + } + + @override + int get hashCode { + return hashValues( + backgroundColor, + scrimColor, + elevation, + shape, + ); + } + + @override + bool operator ==(Object other) { + if (identical(this, other)) + return true; + if (other.runtimeType != runtimeType) + return false; + return other is DrawerThemeData + && other.backgroundColor == backgroundColor + && other.scrimColor == scrimColor + && other.elevation == elevation + && other.shape == shape; + } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: null)); + properties.add(ColorProperty('scrimColor', scrimColor, defaultValue: null)); + properties.add(DoubleProperty('elevation', elevation, defaultValue: null)); + properties.add(DiagnosticsProperty('shape', shape, defaultValue: null)); + } +} + +/// An inherited widget that defines visual properties for [Drawer]s in this +/// widget's subtree. +/// +/// Values specified here are used for [Drawer] properties that are not +/// given an explicit non-null value. +/// +/// Using this would allow you to override the [ThemeData.drawerTheme]. +class DrawerTheme extends InheritedTheme { + /// Creates a theme that defines the [DrawerThemeData] properties for a + /// [Drawer]. + const DrawerTheme({ + Key? key, + required this.data, + required Widget child, + }) : assert(data != null), super(key: key, child: child); + + /// Specifies the background color, scrim color, elevation, and shape for + /// descendant [Drawer] widgets. + final DrawerThemeData data; + + /// The closest instance of this class that encloses the given context. + /// + /// If there is no enclosing [DrawerTheme] widget, then + /// [ThemeData.drawerTheme] is used. + /// + /// Typical usage is as follows: + /// + /// ```dart + /// DrawerTheme theme = DrawerTheme.of(context); + /// ``` + static DrawerThemeData of(BuildContext context) { + final DrawerTheme? drawerTheme = context.dependOnInheritedWidgetOfExactType(); + return drawerTheme?.data ?? Theme.of(context).drawerTheme; + } + + @override + Widget wrap(BuildContext context, Widget child) { + return DrawerTheme(data: data, child: child); + } + + @override + bool updateShouldNotify(DrawerTheme oldWidget) => data != oldWidget.data; +} diff --git a/packages/flutter/lib/src/material/scaffold.dart b/packages/flutter/lib/src/material/scaffold.dart index ddf398eaf6624..750f92a11cac8 100644 --- a/packages/flutter/lib/src/material/scaffold.dart +++ b/packages/flutter/lib/src/material/scaffold.dart @@ -1619,7 +1619,8 @@ class Scaffold extends StatefulWidget { /// The color to use for the scrim that obscures primary content while a drawer is open. /// - /// By default, the color is [Colors.black54] + /// If this is null, then [DrawerThemeData.scrimColor] is used. If that + /// is also null, then it defaults to [Colors.black54]. final Color? drawerScrimColor; /// The color of the [Material] widget that underlies the entire Scaffold. diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart index e064881764636..6fcdc588d21be 100644 --- a/packages/flutter/lib/src/material/theme_data.dart +++ b/packages/flutter/lib/src/material/theme_data.dart @@ -22,6 +22,7 @@ import 'colors.dart'; import 'data_table_theme.dart'; import 'dialog_theme.dart'; import 'divider_theme.dart'; +import 'drawer_theme.dart'; import 'elevated_button_theme.dart'; import 'floating_action_button_theme.dart'; import 'ink_splash.dart'; @@ -336,6 +337,7 @@ class ThemeData with Diagnosticable { RadioThemeData? radioTheme, SwitchThemeData? switchTheme, ProgressIndicatorThemeData? progressIndicatorTheme, + DrawerThemeData? drawerTheme, @Deprecated( 'This "fix" is now enabled by default. ' 'This feature was deprecated after v2.5.0-1.0.pre.', @@ -479,6 +481,7 @@ class ThemeData with Diagnosticable { radioTheme ??= const RadioThemeData(); switchTheme ??= const SwitchThemeData(); progressIndicatorTheme ??= const ProgressIndicatorThemeData(); + drawerTheme ??= const DrawerThemeData(); fixTextFieldOutlineLabel ??= true; useTextSelectionTheme ??= true; @@ -560,6 +563,7 @@ class ThemeData with Diagnosticable { radioTheme: radioTheme, switchTheme: switchTheme, progressIndicatorTheme: progressIndicatorTheme, + drawerTheme: drawerTheme, fixTextFieldOutlineLabel: fixTextFieldOutlineLabel, useTextSelectionTheme: useTextSelectionTheme, androidOverscrollIndicator: androidOverscrollIndicator, @@ -693,6 +697,7 @@ class ThemeData with Diagnosticable { required this.radioTheme, required this.switchTheme, required this.progressIndicatorTheme, + required this.drawerTheme, @Deprecated( 'This "fix" is now enabled by default. ' 'This feature was deprecated after v2.5.0-1.0.pre.', @@ -777,6 +782,7 @@ class ThemeData with Diagnosticable { assert(radioTheme != null), assert(switchTheme != null), assert(progressIndicatorTheme != null), + assert(drawerTheme != null), assert(fixTextFieldOutlineLabel != null), assert(useTextSelectionTheme != null); @@ -1337,6 +1343,9 @@ class ThemeData with Diagnosticable { /// A theme for customizing the appearance and layout of [ProgressIndicator] widgets. final ProgressIndicatorThemeData progressIndicatorTheme; + /// A theme for customizing the appearance and layout of [Drawer] widgets. + final DrawerThemeData drawerTheme; + /// An obsolete flag to allow apps to opt-out of a /// [small fix](https://github.com/flutter/flutter/issues/54028) for the Y /// coordinate of the floating label in a [TextField] [OutlineInputBorder]. @@ -1496,6 +1505,7 @@ class ThemeData with Diagnosticable { RadioThemeData? radioTheme, SwitchThemeData? switchTheme, ProgressIndicatorThemeData? progressIndicatorTheme, + DrawerThemeData? drawerTheme, @Deprecated( 'This "fix" is now enabled by default. ' 'This feature was deprecated after v2.5.0-1.0.pre.', @@ -1586,6 +1596,7 @@ class ThemeData with Diagnosticable { radioTheme: radioTheme ?? this.radioTheme, switchTheme: switchTheme ?? this.switchTheme, progressIndicatorTheme: progressIndicatorTheme ?? this.progressIndicatorTheme, + drawerTheme: drawerTheme ?? this.drawerTheme, fixTextFieldOutlineLabel: fixTextFieldOutlineLabel ?? this.fixTextFieldOutlineLabel, useTextSelectionTheme: useTextSelectionTheme ?? this.useTextSelectionTheme, androidOverscrollIndicator: androidOverscrollIndicator ?? this.androidOverscrollIndicator, @@ -1746,6 +1757,7 @@ class ThemeData with Diagnosticable { radioTheme: RadioThemeData.lerp(a.radioTheme, b.radioTheme, t), switchTheme: SwitchThemeData.lerp(a.switchTheme, b.switchTheme, t), progressIndicatorTheme: ProgressIndicatorThemeData.lerp(a.progressIndicatorTheme, b.progressIndicatorTheme, t)!, + drawerTheme: DrawerThemeData.lerp(a.drawerTheme, b.drawerTheme, t)!, fixTextFieldOutlineLabel: t < 0.5 ? a.fixTextFieldOutlineLabel : b.fixTextFieldOutlineLabel, useTextSelectionTheme: t < 0.5 ? a.useTextSelectionTheme : b.useTextSelectionTheme, androidOverscrollIndicator: t < 0.5 ? a.androidOverscrollIndicator : b.androidOverscrollIndicator, @@ -1834,6 +1846,7 @@ class ThemeData with Diagnosticable { && other.radioTheme == radioTheme && other.switchTheme == switchTheme && other.progressIndicatorTheme == progressIndicatorTheme + && other.drawerTheme == drawerTheme && other.fixTextFieldOutlineLabel == fixTextFieldOutlineLabel && other.useTextSelectionTheme == useTextSelectionTheme && other.androidOverscrollIndicator == androidOverscrollIndicator; @@ -1921,6 +1934,7 @@ class ThemeData with Diagnosticable { radioTheme, switchTheme, progressIndicatorTheme, + drawerTheme, fixTextFieldOutlineLabel, useTextSelectionTheme, androidOverscrollIndicator, @@ -2006,6 +2020,7 @@ class ThemeData with Diagnosticable { properties.add(DiagnosticsProperty('radioTheme', radioTheme, defaultValue: defaultData.radioTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty('switchTheme', switchTheme, defaultValue: defaultData.switchTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty('progressIndicatorTheme', progressIndicatorTheme, defaultValue: defaultData.progressIndicatorTheme, level: DiagnosticLevel.debug)); + properties.add(DiagnosticsProperty('drawerTheme', drawerTheme, defaultValue: defaultData.drawerTheme, level: DiagnosticLevel.debug)); properties.add(EnumProperty('androidOverscrollIndicator', androidOverscrollIndicator, defaultValue: null, level: DiagnosticLevel.debug)); } } diff --git a/packages/flutter/test/material/drawer_theme_test.dart b/packages/flutter/test/material/drawer_theme_test.dart new file mode 100644 index 0000000000000..8185d155cccdb --- /dev/null +++ b/packages/flutter/test/material/drawer_theme_test.dart @@ -0,0 +1,202 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + test('copyWith, ==, hashCode basics', () { + expect(const DrawerThemeData(), const DrawerThemeData().copyWith()); + expect(const DrawerThemeData().hashCode, const DrawerThemeData().copyWith().hashCode); + }); + + testWidgets('Default debugFillProperties', (WidgetTester tester) async { + final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); + const DrawerThemeData().debugFillProperties(builder); + + final List description = builder.properties + .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) + .map((DiagnosticsNode node) => node.toString()) + .toList(); + + expect(description, []); + }); + + testWidgets('Custom debugFillProperties', (WidgetTester tester) async { + final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); + DrawerThemeData( + backgroundColor: const Color(0x00000099), + scrimColor: const Color(0x00000098), + elevation: 5.0, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(2.0)), + ).debugFillProperties(builder); + + final List description = builder.properties + .where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info)) + .map((DiagnosticsNode node) => node.toString()) + .toList(); + + expect(description, [ + 'backgroundColor: Color(0x00000099)', + 'scrimColor: Color(0x00000098)', + 'elevation: 5.0', + 'shape: RoundedRectangleBorder(BorderSide(Color(0xff000000), 0.0, BorderStyle.none), BorderRadius.circular(2.0))', + ]); + }); + + testWidgets('Default values are used when no Drawer or DrawerThemeData properties are specified', (WidgetTester tester) async { + final GlobalKey scaffoldKey = GlobalKey(); + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + key: scaffoldKey, + drawer: const Drawer(), + ), + ), + ); + scaffoldKey.currentState!.openDrawer(); + await tester.pumpAndSettle(); + + expect(_drawerMaterial(tester).color, null); + expect(_drawerMaterial(tester).elevation, 16.0); + expect(_drawerMaterial(tester).shape, null); + expect(_scrim(tester).color, Colors.black54); + }); + + testWidgets('DrawerThemeData values are used when no Drawer properties are specified', (WidgetTester tester) async { + const Color backgroundColor = Color(0x00000001); + const Color scrimColor = Color(0x00000002); + const double elevation = 7.0; + const RoundedRectangleBorder shape = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); + + final GlobalKey scaffoldKey = GlobalKey(); + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + drawerTheme: const DrawerThemeData( + backgroundColor: backgroundColor, + scrimColor: scrimColor, + elevation: elevation, + shape: shape, + ), + ), + home: Scaffold( + key: scaffoldKey, + drawer: const Drawer(), + ), + ), + ); + scaffoldKey.currentState!.openDrawer(); + await tester.pumpAndSettle(); + + expect(_drawerMaterial(tester).color, backgroundColor); + expect(_drawerMaterial(tester).elevation, elevation); + expect(_drawerMaterial(tester).shape, shape); + expect(_scrim(tester).color, scrimColor); + }); + + testWidgets('Drawer values take priority over DrawerThemeData values when both properties are specified', (WidgetTester tester) async { + const Color backgroundColor = Color(0x00000001); + const Color scrimColor = Color(0x00000002); + const double elevation = 7.0; + const RoundedRectangleBorder shape = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); + + final GlobalKey scaffoldKey = GlobalKey(); + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + drawerTheme: const DrawerThemeData( + backgroundColor: Color(0x00000003), + scrimColor: Color(0x00000004), + elevation: 13.0, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(29.0))), + ), + ), + home: Scaffold( + key: scaffoldKey, + drawerScrimColor: scrimColor, + drawer: const Drawer( + backgroundColor: backgroundColor, + elevation: elevation, + shape: shape, + ), + ), + ), + ); + scaffoldKey.currentState!.openDrawer(); + await tester.pumpAndSettle(); + + expect(_drawerMaterial(tester).color, backgroundColor); + expect(_drawerMaterial(tester).elevation, elevation); + expect(_drawerMaterial(tester).shape, shape); + expect(_scrim(tester).color, scrimColor); + }); + + testWidgets('DrawerTheme values take priority over ThemeData.drawerTheme values when both properties are specified', (WidgetTester tester) async { + const Color backgroundColor = Color(0x00000001); + const Color scrimColor = Color(0x00000002); + const double elevation = 7.0; + const RoundedRectangleBorder shape = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); + + final GlobalKey scaffoldKey = GlobalKey(); + await tester.pumpWidget( + MaterialApp( + theme: ThemeData( + drawerTheme: const DrawerThemeData( + backgroundColor: Color(0x00000003), + scrimColor: Color(0x00000004), + elevation: 13.0, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(29.0))), + ), + ), + home: DrawerTheme( + data: const DrawerThemeData( + backgroundColor: backgroundColor, + scrimColor: scrimColor, + elevation: elevation, + shape: shape, + ), + child: Scaffold( + key: scaffoldKey, + drawer: const Drawer(), + ), + ), + ), + ); + scaffoldKey.currentState!.openDrawer(); + await tester.pumpAndSettle(); + + expect(_drawerMaterial(tester).color, backgroundColor); + expect(_drawerMaterial(tester).elevation, elevation); + expect(_drawerMaterial(tester).shape, shape); + expect(_scrim(tester).color, scrimColor); + }); +} + +Material _drawerMaterial(WidgetTester tester) { + return tester.firstWidget( + find.descendant( + of: find.byType(Drawer), + matching: find.byType(Material), + ), + ); +} + +// The scrim is a Container within a Semantics node labeled "Dismiss", +// within a DrawerController. +Container _scrim(WidgetTester tester) { + return tester.widget( + find.descendant( + of: find.descendant( + of: find.byType(DrawerController), + matching: find.byWidgetPredicate((Widget widget) { + return widget is Semantics + && widget.properties.label == 'Dismiss'; + }), + ), + matching: find.byType(Container), + ), + ); +} diff --git a/packages/flutter/test/material/theme_data_test.dart b/packages/flutter/test/material/theme_data_test.dart index b26686c2d41d8..a8d236167d235 100644 --- a/packages/flutter/test/material/theme_data_test.dart +++ b/packages/flutter/test/material/theme_data_test.dart @@ -344,6 +344,7 @@ void main() { radioTheme: const RadioThemeData(), switchTheme: const SwitchThemeData(), progressIndicatorTheme: const ProgressIndicatorThemeData(), + drawerTheme: const DrawerThemeData(), fixTextFieldOutlineLabel: false, useTextSelectionTheme: false, androidOverscrollIndicator: null, @@ -439,6 +440,7 @@ void main() { radioTheme: const RadioThemeData(), switchTheme: const SwitchThemeData(), progressIndicatorTheme: const ProgressIndicatorThemeData(), + drawerTheme: const DrawerThemeData(), fixTextFieldOutlineLabel: true, useTextSelectionTheme: true, androidOverscrollIndicator: AndroidOverscrollIndicator.stretch, @@ -510,6 +512,12 @@ void main() { elevatedButtonTheme: otherTheme.elevatedButtonTheme, outlinedButtonTheme: otherTheme.outlinedButtonTheme, textSelectionTheme: otherTheme.textSelectionTheme, + dataTableTheme: otherTheme.dataTableTheme, + checkboxTheme: otherTheme.checkboxTheme, + radioTheme: otherTheme.radioTheme, + switchTheme: otherTheme.switchTheme, + progressIndicatorTheme: otherTheme.progressIndicatorTheme, + drawerTheme: otherTheme.drawerTheme, fixTextFieldOutlineLabel: otherTheme.fixTextFieldOutlineLabel, ); @@ -578,6 +586,12 @@ void main() { expect(themeDataCopy.elevatedButtonTheme, equals(otherTheme.elevatedButtonTheme)); expect(themeDataCopy.outlinedButtonTheme, equals(otherTheme.outlinedButtonTheme)); expect(themeDataCopy.textSelectionTheme, equals(otherTheme.textSelectionTheme)); + expect(themeDataCopy.dataTableTheme, equals(otherTheme.dataTableTheme)); + expect(themeDataCopy.checkboxTheme, equals(otherTheme.checkboxTheme)); + expect(themeDataCopy.radioTheme, equals(otherTheme.radioTheme)); + expect(themeDataCopy.switchTheme, equals(otherTheme.switchTheme)); + expect(themeDataCopy.progressIndicatorTheme, equals(otherTheme.progressIndicatorTheme)); + expect(themeDataCopy.drawerTheme, equals(otherTheme.drawerTheme)); expect(themeDataCopy.fixTextFieldOutlineLabel, equals(otherTheme.fixTextFieldOutlineLabel)); });