Unverified Commit 069699eb authored by Rami's avatar Rami Committed by GitHub

Add ability to customize drawer shape and color as well as theme drawer properties (#89237)

parent 947034ed
...@@ -65,6 +65,7 @@ export 'src/material/divider.dart'; ...@@ -65,6 +65,7 @@ export 'src/material/divider.dart';
export 'src/material/divider_theme.dart'; export 'src/material/divider_theme.dart';
export 'src/material/drawer.dart'; export 'src/material/drawer.dart';
export 'src/material/drawer_header.dart'; export 'src/material/drawer_header.dart';
export 'src/material/drawer_theme.dart';
export 'src/material/dropdown.dart'; export 'src/material/dropdown.dart';
export 'src/material/elevated_button.dart'; export 'src/material/elevated_button.dart';
export 'src/material/elevated_button_theme.dart'; export 'src/material/elevated_button_theme.dart';
......
...@@ -7,6 +7,7 @@ import 'package:flutter/widgets.dart'; ...@@ -7,6 +7,7 @@ import 'package:flutter/widgets.dart';
import 'colors.dart'; import 'colors.dart';
import 'debug.dart'; import 'debug.dart';
import 'drawer_theme.dart';
import 'list_tile.dart'; import 'list_tile.dart';
import 'material.dart'; import 'material.dart';
import 'material_localizations.dart'; import 'material_localizations.dart';
...@@ -139,19 +140,36 @@ class Drawer extends StatelessWidget { ...@@ -139,19 +140,36 @@ class Drawer extends StatelessWidget {
/// The [elevation] must be non-negative. /// The [elevation] must be non-negative.
const Drawer({ const Drawer({
Key? key, Key? key,
this.elevation = 16.0, this.backgroundColor,
this.elevation,
this.shape,
this.child, this.child,
this.semanticLabel, this.semanticLabel,
}) : assert(elevation != null && elevation >= 0.0), }) : assert(elevation == null || elevation >= 0.0),
super(key: key); 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. /// The z-coordinate at which to place this drawer relative to its parent.
/// ///
/// This controls the size of the shadow below the drawer. /// This controls the size of the shadow below the drawer.
/// ///
/// Defaults to 16, the appropriate elevation for drawers. The value is /// If this is null, then [DrawerThemeData.elevation] is used. If that
/// always non-negative. /// is also null, then it defaults to 16.0.
final double elevation; 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. /// The widget below this widget in the tree.
/// ///
...@@ -175,6 +193,7 @@ class Drawer extends StatelessWidget { ...@@ -175,6 +193,7 @@ class Drawer extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
assert(debugCheckHasMaterialLocalizations(context)); assert(debugCheckHasMaterialLocalizations(context));
final DrawerThemeData drawerTheme = DrawerTheme.of(context);
String? label = semanticLabel; String? label = semanticLabel;
switch (Theme.of(context).platform) { switch (Theme.of(context).platform) {
case TargetPlatform.iOS: case TargetPlatform.iOS:
...@@ -194,7 +213,9 @@ class Drawer extends StatelessWidget { ...@@ -194,7 +213,9 @@ class Drawer extends StatelessWidget {
child: ConstrainedBox( child: ConstrainedBox(
constraints: const BoxConstraints.expand(width: _kWidth), constraints: const BoxConstraints.expand(width: _kWidth),
child: Material( child: Material(
elevation: elevation, color: backgroundColor ?? drawerTheme.backgroundColor,
elevation: elevation ?? drawerTheme.elevation ?? 16.0,
shape: shape ?? drawerTheme.shape,
child: child, child: child,
), ),
), ),
...@@ -277,9 +298,11 @@ class DrawerController extends StatefulWidget { ...@@ -277,9 +298,11 @@ class DrawerController extends StatefulWidget {
/// {@endtemplate} /// {@endtemplate}
final DragStartBehavior dragStartBehavior; 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; final Color? scrimColor;
/// Determines if the [Drawer] can be opened with a drag gesture. /// Determines if the [Drawer] can be opened with a drag gesture.
...@@ -317,7 +340,6 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro ...@@ -317,7 +340,6 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_scrimColorTween = _buildScrimColorTween();
_controller = AnimationController( _controller = AnimationController(
value: widget.isDrawerOpen ? 1.0 : 0.0, value: widget.isDrawerOpen ? 1.0 : 0.0,
duration: _kBaseSettleDuration, duration: _kBaseSettleDuration,
...@@ -335,6 +357,12 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro ...@@ -335,6 +357,12 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro
super.dispose(); super.dispose();
} }
@override
void didChangeDependencies() {
super.didChangeDependencies();
_scrimColorTween = _buildScrimColorTween();
}
@override @override
void didUpdateWidget(DrawerController oldWidget) { void didUpdateWidget(DrawerController oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
...@@ -492,7 +520,12 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro ...@@ -492,7 +520,12 @@ class DrawerControllerState extends State<DrawerController> with SingleTickerPro
final GlobalKey _gestureDetectorKey = GlobalKey(); final GlobalKey _gestureDetectorKey = GlobalKey();
ColorTween _buildScrimColorTween() { 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 { AlignmentDirectional get _drawerOuterAlignment {
......
// 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<ShapeBorder>('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<DrawerTheme>();
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;
}
...@@ -1619,7 +1619,8 @@ class Scaffold extends StatefulWidget { ...@@ -1619,7 +1619,8 @@ class Scaffold extends StatefulWidget {
/// 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 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; final Color? drawerScrimColor;
/// The color of the [Material] widget that underlies the entire Scaffold. /// The color of the [Material] widget that underlies the entire Scaffold.
......
...@@ -22,6 +22,7 @@ import 'colors.dart'; ...@@ -22,6 +22,7 @@ import 'colors.dart';
import 'data_table_theme.dart'; import 'data_table_theme.dart';
import 'dialog_theme.dart'; import 'dialog_theme.dart';
import 'divider_theme.dart'; import 'divider_theme.dart';
import 'drawer_theme.dart';
import 'elevated_button_theme.dart'; import 'elevated_button_theme.dart';
import 'floating_action_button_theme.dart'; import 'floating_action_button_theme.dart';
import 'ink_splash.dart'; import 'ink_splash.dart';
...@@ -336,6 +337,7 @@ class ThemeData with Diagnosticable { ...@@ -336,6 +337,7 @@ class ThemeData with Diagnosticable {
RadioThemeData? radioTheme, RadioThemeData? radioTheme,
SwitchThemeData? switchTheme, SwitchThemeData? switchTheme,
ProgressIndicatorThemeData? progressIndicatorTheme, ProgressIndicatorThemeData? progressIndicatorTheme,
DrawerThemeData? drawerTheme,
@Deprecated( @Deprecated(
'This "fix" is now enabled by default. ' 'This "fix" is now enabled by default. '
'This feature was deprecated after v2.5.0-1.0.pre.', 'This feature was deprecated after v2.5.0-1.0.pre.',
...@@ -479,6 +481,7 @@ class ThemeData with Diagnosticable { ...@@ -479,6 +481,7 @@ class ThemeData with Diagnosticable {
radioTheme ??= const RadioThemeData(); radioTheme ??= const RadioThemeData();
switchTheme ??= const SwitchThemeData(); switchTheme ??= const SwitchThemeData();
progressIndicatorTheme ??= const ProgressIndicatorThemeData(); progressIndicatorTheme ??= const ProgressIndicatorThemeData();
drawerTheme ??= const DrawerThemeData();
fixTextFieldOutlineLabel ??= true; fixTextFieldOutlineLabel ??= true;
useTextSelectionTheme ??= true; useTextSelectionTheme ??= true;
...@@ -560,6 +563,7 @@ class ThemeData with Diagnosticable { ...@@ -560,6 +563,7 @@ class ThemeData with Diagnosticable {
radioTheme: radioTheme, radioTheme: radioTheme,
switchTheme: switchTheme, switchTheme: switchTheme,
progressIndicatorTheme: progressIndicatorTheme, progressIndicatorTheme: progressIndicatorTheme,
drawerTheme: drawerTheme,
fixTextFieldOutlineLabel: fixTextFieldOutlineLabel, fixTextFieldOutlineLabel: fixTextFieldOutlineLabel,
useTextSelectionTheme: useTextSelectionTheme, useTextSelectionTheme: useTextSelectionTheme,
androidOverscrollIndicator: androidOverscrollIndicator, androidOverscrollIndicator: androidOverscrollIndicator,
...@@ -693,6 +697,7 @@ class ThemeData with Diagnosticable { ...@@ -693,6 +697,7 @@ class ThemeData with Diagnosticable {
required this.radioTheme, required this.radioTheme,
required this.switchTheme, required this.switchTheme,
required this.progressIndicatorTheme, required this.progressIndicatorTheme,
required this.drawerTheme,
@Deprecated( @Deprecated(
'This "fix" is now enabled by default. ' 'This "fix" is now enabled by default. '
'This feature was deprecated after v2.5.0-1.0.pre.', 'This feature was deprecated after v2.5.0-1.0.pre.',
...@@ -777,6 +782,7 @@ class ThemeData with Diagnosticable { ...@@ -777,6 +782,7 @@ class ThemeData with Diagnosticable {
assert(radioTheme != null), assert(radioTheme != null),
assert(switchTheme != null), assert(switchTheme != null),
assert(progressIndicatorTheme != null), assert(progressIndicatorTheme != null),
assert(drawerTheme != null),
assert(fixTextFieldOutlineLabel != null), assert(fixTextFieldOutlineLabel != null),
assert(useTextSelectionTheme != null); assert(useTextSelectionTheme != null);
...@@ -1337,6 +1343,9 @@ class ThemeData with Diagnosticable { ...@@ -1337,6 +1343,9 @@ class ThemeData with Diagnosticable {
/// A theme for customizing the appearance and layout of [ProgressIndicator] widgets. /// A theme for customizing the appearance and layout of [ProgressIndicator] widgets.
final ProgressIndicatorThemeData progressIndicatorTheme; 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 /// An obsolete flag to allow apps to opt-out of a
/// [small fix](https://github.com/flutter/flutter/issues/54028) for the Y /// [small fix](https://github.com/flutter/flutter/issues/54028) for the Y
/// coordinate of the floating label in a [TextField] [OutlineInputBorder]. /// coordinate of the floating label in a [TextField] [OutlineInputBorder].
...@@ -1496,6 +1505,7 @@ class ThemeData with Diagnosticable { ...@@ -1496,6 +1505,7 @@ class ThemeData with Diagnosticable {
RadioThemeData? radioTheme, RadioThemeData? radioTheme,
SwitchThemeData? switchTheme, SwitchThemeData? switchTheme,
ProgressIndicatorThemeData? progressIndicatorTheme, ProgressIndicatorThemeData? progressIndicatorTheme,
DrawerThemeData? drawerTheme,
@Deprecated( @Deprecated(
'This "fix" is now enabled by default. ' 'This "fix" is now enabled by default. '
'This feature was deprecated after v2.5.0-1.0.pre.', 'This feature was deprecated after v2.5.0-1.0.pre.',
...@@ -1586,6 +1596,7 @@ class ThemeData with Diagnosticable { ...@@ -1586,6 +1596,7 @@ class ThemeData with Diagnosticable {
radioTheme: radioTheme ?? this.radioTheme, radioTheme: radioTheme ?? this.radioTheme,
switchTheme: switchTheme ?? this.switchTheme, switchTheme: switchTheme ?? this.switchTheme,
progressIndicatorTheme: progressIndicatorTheme ?? this.progressIndicatorTheme, progressIndicatorTheme: progressIndicatorTheme ?? this.progressIndicatorTheme,
drawerTheme: drawerTheme ?? this.drawerTheme,
fixTextFieldOutlineLabel: fixTextFieldOutlineLabel ?? this.fixTextFieldOutlineLabel, fixTextFieldOutlineLabel: fixTextFieldOutlineLabel ?? this.fixTextFieldOutlineLabel,
useTextSelectionTheme: useTextSelectionTheme ?? this.useTextSelectionTheme, useTextSelectionTheme: useTextSelectionTheme ?? this.useTextSelectionTheme,
androidOverscrollIndicator: androidOverscrollIndicator ?? this.androidOverscrollIndicator, androidOverscrollIndicator: androidOverscrollIndicator ?? this.androidOverscrollIndicator,
...@@ -1746,6 +1757,7 @@ class ThemeData with Diagnosticable { ...@@ -1746,6 +1757,7 @@ class ThemeData with Diagnosticable {
radioTheme: RadioThemeData.lerp(a.radioTheme, b.radioTheme, t), radioTheme: RadioThemeData.lerp(a.radioTheme, b.radioTheme, t),
switchTheme: SwitchThemeData.lerp(a.switchTheme, b.switchTheme, t), switchTheme: SwitchThemeData.lerp(a.switchTheme, b.switchTheme, t),
progressIndicatorTheme: ProgressIndicatorThemeData.lerp(a.progressIndicatorTheme, b.progressIndicatorTheme, 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, fixTextFieldOutlineLabel: t < 0.5 ? a.fixTextFieldOutlineLabel : b.fixTextFieldOutlineLabel,
useTextSelectionTheme: t < 0.5 ? a.useTextSelectionTheme : b.useTextSelectionTheme, useTextSelectionTheme: t < 0.5 ? a.useTextSelectionTheme : b.useTextSelectionTheme,
androidOverscrollIndicator: t < 0.5 ? a.androidOverscrollIndicator : b.androidOverscrollIndicator, androidOverscrollIndicator: t < 0.5 ? a.androidOverscrollIndicator : b.androidOverscrollIndicator,
...@@ -1834,6 +1846,7 @@ class ThemeData with Diagnosticable { ...@@ -1834,6 +1846,7 @@ class ThemeData with Diagnosticable {
&& other.radioTheme == radioTheme && other.radioTheme == radioTheme
&& other.switchTheme == switchTheme && other.switchTheme == switchTheme
&& other.progressIndicatorTheme == progressIndicatorTheme && other.progressIndicatorTheme == progressIndicatorTheme
&& other.drawerTheme == drawerTheme
&& other.fixTextFieldOutlineLabel == fixTextFieldOutlineLabel && other.fixTextFieldOutlineLabel == fixTextFieldOutlineLabel
&& other.useTextSelectionTheme == useTextSelectionTheme && other.useTextSelectionTheme == useTextSelectionTheme
&& other.androidOverscrollIndicator == androidOverscrollIndicator; && other.androidOverscrollIndicator == androidOverscrollIndicator;
...@@ -1921,6 +1934,7 @@ class ThemeData with Diagnosticable { ...@@ -1921,6 +1934,7 @@ class ThemeData with Diagnosticable {
radioTheme, radioTheme,
switchTheme, switchTheme,
progressIndicatorTheme, progressIndicatorTheme,
drawerTheme,
fixTextFieldOutlineLabel, fixTextFieldOutlineLabel,
useTextSelectionTheme, useTextSelectionTheme,
androidOverscrollIndicator, androidOverscrollIndicator,
...@@ -2006,6 +2020,7 @@ class ThemeData with Diagnosticable { ...@@ -2006,6 +2020,7 @@ class ThemeData with Diagnosticable {
properties.add(DiagnosticsProperty<RadioThemeData>('radioTheme', radioTheme, defaultValue: defaultData.radioTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty<RadioThemeData>('radioTheme', radioTheme, defaultValue: defaultData.radioTheme, level: DiagnosticLevel.debug));
properties.add(DiagnosticsProperty<SwitchThemeData>('switchTheme', switchTheme, defaultValue: defaultData.switchTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty<SwitchThemeData>('switchTheme', switchTheme, defaultValue: defaultData.switchTheme, level: DiagnosticLevel.debug));
properties.add(DiagnosticsProperty<ProgressIndicatorThemeData>('progressIndicatorTheme', progressIndicatorTheme, defaultValue: defaultData.progressIndicatorTheme, level: DiagnosticLevel.debug)); properties.add(DiagnosticsProperty<ProgressIndicatorThemeData>('progressIndicatorTheme', progressIndicatorTheme, defaultValue: defaultData.progressIndicatorTheme, level: DiagnosticLevel.debug));
properties.add(DiagnosticsProperty<DrawerThemeData>('drawerTheme', drawerTheme, defaultValue: defaultData.drawerTheme, level: DiagnosticLevel.debug));
properties.add(EnumProperty<AndroidOverscrollIndicator>('androidOverscrollIndicator', androidOverscrollIndicator, defaultValue: null, level: DiagnosticLevel.debug)); properties.add(EnumProperty<AndroidOverscrollIndicator>('androidOverscrollIndicator', androidOverscrollIndicator, defaultValue: null, level: DiagnosticLevel.debug));
} }
} }
......
// 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<String> description = builder.properties
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
.map((DiagnosticsNode node) => node.toString())
.toList();
expect(description, <String>[]);
});
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<String> description = builder.properties
.where((DiagnosticsNode node) => !node.isFiltered(DiagnosticLevel.info))
.map((DiagnosticsNode node) => node.toString())
.toList();
expect(description, <String>[
'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<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
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<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
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<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
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<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
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<Material>(
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<Container>(
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),
),
);
}
...@@ -344,6 +344,7 @@ void main() { ...@@ -344,6 +344,7 @@ void main() {
radioTheme: const RadioThemeData(), radioTheme: const RadioThemeData(),
switchTheme: const SwitchThemeData(), switchTheme: const SwitchThemeData(),
progressIndicatorTheme: const ProgressIndicatorThemeData(), progressIndicatorTheme: const ProgressIndicatorThemeData(),
drawerTheme: const DrawerThemeData(),
fixTextFieldOutlineLabel: false, fixTextFieldOutlineLabel: false,
useTextSelectionTheme: false, useTextSelectionTheme: false,
androidOverscrollIndicator: null, androidOverscrollIndicator: null,
...@@ -439,6 +440,7 @@ void main() { ...@@ -439,6 +440,7 @@ void main() {
radioTheme: const RadioThemeData(), radioTheme: const RadioThemeData(),
switchTheme: const SwitchThemeData(), switchTheme: const SwitchThemeData(),
progressIndicatorTheme: const ProgressIndicatorThemeData(), progressIndicatorTheme: const ProgressIndicatorThemeData(),
drawerTheme: const DrawerThemeData(),
fixTextFieldOutlineLabel: true, fixTextFieldOutlineLabel: true,
useTextSelectionTheme: true, useTextSelectionTheme: true,
androidOverscrollIndicator: AndroidOverscrollIndicator.stretch, androidOverscrollIndicator: AndroidOverscrollIndicator.stretch,
...@@ -510,6 +512,12 @@ void main() { ...@@ -510,6 +512,12 @@ void main() {
elevatedButtonTheme: otherTheme.elevatedButtonTheme, elevatedButtonTheme: otherTheme.elevatedButtonTheme,
outlinedButtonTheme: otherTheme.outlinedButtonTheme, outlinedButtonTheme: otherTheme.outlinedButtonTheme,
textSelectionTheme: otherTheme.textSelectionTheme, textSelectionTheme: otherTheme.textSelectionTheme,
dataTableTheme: otherTheme.dataTableTheme,
checkboxTheme: otherTheme.checkboxTheme,
radioTheme: otherTheme.radioTheme,
switchTheme: otherTheme.switchTheme,
progressIndicatorTheme: otherTheme.progressIndicatorTheme,
drawerTheme: otherTheme.drawerTheme,
fixTextFieldOutlineLabel: otherTheme.fixTextFieldOutlineLabel, fixTextFieldOutlineLabel: otherTheme.fixTextFieldOutlineLabel,
); );
...@@ -578,6 +586,12 @@ void main() { ...@@ -578,6 +586,12 @@ void main() {
expect(themeDataCopy.elevatedButtonTheme, equals(otherTheme.elevatedButtonTheme)); expect(themeDataCopy.elevatedButtonTheme, equals(otherTheme.elevatedButtonTheme));
expect(themeDataCopy.outlinedButtonTheme, equals(otherTheme.outlinedButtonTheme)); expect(themeDataCopy.outlinedButtonTheme, equals(otherTheme.outlinedButtonTheme));
expect(themeDataCopy.textSelectionTheme, equals(otherTheme.textSelectionTheme)); 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)); expect(themeDataCopy.fixTextFieldOutlineLabel, equals(otherTheme.fixTextFieldOutlineLabel));
}); });
......
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