Unverified Commit cb988c7b authored by Taha Tesser's avatar Taha Tesser Committed by GitHub

Add `indicatorColor` & `indicatorShape` to `NavigationRail`,...

Add `indicatorColor` & `indicatorShape` to `NavigationRail`, `NavigationDrawer` and move these properties from destination to `NavigationBar` (#117049)
parent 32da2505
...@@ -93,6 +93,8 @@ class NavigationBar extends StatelessWidget { ...@@ -93,6 +93,8 @@ class NavigationBar extends StatelessWidget {
this.elevation, this.elevation,
this.shadowColor, this.shadowColor,
this.surfaceTintColor, this.surfaceTintColor,
this.indicatorColor,
this.indicatorShape,
this.height, this.height,
this.labelBehavior, this.labelBehavior,
}) : assert(destinations != null && destinations.length >= 2), }) : assert(destinations != null && destinations.length >= 2),
...@@ -158,6 +160,20 @@ class NavigationBar extends StatelessWidget { ...@@ -158,6 +160,20 @@ class NavigationBar extends StatelessWidget {
/// overlay is applied. /// overlay is applied.
final Color? surfaceTintColor; final Color? surfaceTintColor;
/// The color of the [indicatorShape] when this destination is selected.
///
/// If null, [NavigationBarThemeData.indicatorColor] is used. If that
/// is also null and [ThemeData.useMaterial3] is true, [ColorScheme.secondaryContainer]
/// is used. Otherwise, [ColorScheme.secondary] with an opacity of 0.24 is used.
final Color? indicatorColor;
/// The shape of the selected inidicator.
///
/// If null, [NavigationBarThemeData.indicatorShape] is used. If that
/// is also null and [ThemeData.useMaterial3] is true, [StadiumBorder] is used.
/// Otherwise, [RoundedRectangleBorder] with a circular border radius of 16 is used.
final ShapeBorder? indicatorShape;
/// The height of the [NavigationBar] itself. /// The height of the [NavigationBar] itself.
/// ///
/// If this is used in [Scaffold.bottomNavigationBar] and the scaffold is /// If this is used in [Scaffold.bottomNavigationBar] and the scaffold is
...@@ -224,6 +240,8 @@ class NavigationBar extends StatelessWidget { ...@@ -224,6 +240,8 @@ class NavigationBar extends StatelessWidget {
totalNumberOfDestinations: destinations.length, totalNumberOfDestinations: destinations.length,
selectedAnimation: animation, selectedAnimation: animation,
labelBehavior: effectiveLabelBehavior, labelBehavior: effectiveLabelBehavior,
indicatorColor: indicatorColor,
indicatorShape: indicatorShape,
onTap: _handleTap(i), onTap: _handleTap(i),
child: destinations[i], child: destinations[i],
); );
...@@ -274,8 +292,6 @@ class NavigationDestination extends StatelessWidget { ...@@ -274,8 +292,6 @@ class NavigationDestination extends StatelessWidget {
super.key, super.key,
required this.icon, required this.icon,
this.selectedIcon, this.selectedIcon,
this.indicatorColor,
this.indicatorShape,
required this.label, required this.label,
this.tooltip, this.tooltip,
}); });
...@@ -300,12 +316,6 @@ class NavigationDestination extends StatelessWidget { ...@@ -300,12 +316,6 @@ class NavigationDestination extends StatelessWidget {
/// would use a size of 24.0 and [ColorScheme.onSurface]. /// would use a size of 24.0 and [ColorScheme.onSurface].
final Widget? selectedIcon; final Widget? selectedIcon;
/// The color of the [indicatorShape] when this destination is selected.
final Color? indicatorColor;
/// The shape of the selected inidicator.
final ShapeBorder? indicatorShape;
/// The text label that appears below the icon of this /// The text label that appears below the icon of this
/// [NavigationDestination]. /// [NavigationDestination].
/// ///
...@@ -324,12 +334,13 @@ class NavigationDestination extends StatelessWidget { ...@@ -324,12 +334,13 @@ class NavigationDestination extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final _NavigationDestinationInfo info = _NavigationDestinationInfo.of(context);
const Set<MaterialState> selectedState = <MaterialState>{MaterialState.selected}; const Set<MaterialState> selectedState = <MaterialState>{MaterialState.selected};
const Set<MaterialState> unselectedState = <MaterialState>{}; const Set<MaterialState> unselectedState = <MaterialState>{};
final NavigationBarThemeData navigationBarTheme = NavigationBarTheme.of(context); final NavigationBarThemeData navigationBarTheme = NavigationBarTheme.of(context);
final NavigationBarThemeData defaults = _defaultsFor(context); final NavigationBarThemeData defaults = _defaultsFor(context);
final Animation<double> animation = _NavigationDestinationInfo.of(context).selectedAnimation; final Animation<double> animation = info.selectedAnimation;
return _NavigationDestinationBuilder( return _NavigationDestinationBuilder(
label: label, label: label,
...@@ -351,8 +362,8 @@ class NavigationDestination extends StatelessWidget { ...@@ -351,8 +362,8 @@ class NavigationDestination extends StatelessWidget {
children: <Widget>[ children: <Widget>[
NavigationIndicator( NavigationIndicator(
animation: animation, animation: animation,
color: indicatorColor ?? navigationBarTheme.indicatorColor ?? defaults.indicatorColor!, color: info.indicatorColor ?? navigationBarTheme.indicatorColor ?? defaults.indicatorColor!,
shape: indicatorShape ?? navigationBarTheme.indicatorShape ?? defaults.indicatorShape! shape: info.indicatorShape ?? navigationBarTheme.indicatorShape ?? defaults.indicatorShape!
), ),
_StatusTransitionWidgetBuilder( _StatusTransitionWidgetBuilder(
animation: animation, animation: animation,
...@@ -532,6 +543,8 @@ class _NavigationDestinationInfo extends InheritedWidget { ...@@ -532,6 +543,8 @@ class _NavigationDestinationInfo extends InheritedWidget {
required this.totalNumberOfDestinations, required this.totalNumberOfDestinations,
required this.selectedAnimation, required this.selectedAnimation,
required this.labelBehavior, required this.labelBehavior,
required this.indicatorColor,
required this.indicatorShape,
required this.onTap, required this.onTap,
required super.child, required super.child,
}); });
...@@ -588,6 +601,16 @@ class _NavigationDestinationInfo extends InheritedWidget { ...@@ -588,6 +601,16 @@ class _NavigationDestinationInfo extends InheritedWidget {
/// label, or hide all labels. /// label, or hide all labels.
final NavigationDestinationLabelBehavior labelBehavior; final NavigationDestinationLabelBehavior labelBehavior;
/// The color of the selection indicator.
///
/// This is used by destinations to override the indicator color.
final Color? indicatorColor;
/// The shape of the selection indicator.
///
/// This is used by destinations to override the indicator shape.
final ShapeBorder? indicatorShape;
/// The callback that should be called when this destination is tapped. /// The callback that should be called when this destination is tapped.
/// ///
/// This is computed by calling [NavigationBar.onDestinationSelected] /// This is computed by calling [NavigationBar.onDestinationSelected]
......
...@@ -57,6 +57,8 @@ class NavigationDrawer extends StatelessWidget { ...@@ -57,6 +57,8 @@ class NavigationDrawer extends StatelessWidget {
this.shadowColor, this.shadowColor,
this.surfaceTintColor, this.surfaceTintColor,
this.elevation, this.elevation,
this.indicatorColor,
this.indicatorShape,
this.onDestinationSelected, this.onDestinationSelected,
this.selectedIndex = 0, this.selectedIndex = 0,
}); });
...@@ -90,6 +92,18 @@ class NavigationDrawer extends StatelessWidget { ...@@ -90,6 +92,18 @@ class NavigationDrawer extends StatelessWidget {
/// is also null, it will be 1.0. /// is also null, it will be 1.0.
final double? elevation; final double? elevation;
/// The color of the [indicatorShape] when this destination is selected.
///
/// If this is null, [NavigationDrawerThemeData.indicatorColor] is used.
/// If that is also null, defaults to [ColorScheme.secondaryContainer].
final Color? indicatorColor;
/// The shape of the selected inidicator.
///
/// If this is null, [NavigationDrawerThemeData.indicatorShape] is used.
/// If that is also null, defaults to [StadiumBorder].
final ShapeBorder? indicatorShape;
/// Defines the appearance of the items within the navigation drawer. /// Defines the appearance of the items within the navigation drawer.
/// ///
/// The list contains [NavigationDrawerDestination] widgets and/or customized /// The list contains [NavigationDrawerDestination] widgets and/or customized
...@@ -125,6 +139,8 @@ class NavigationDrawer extends StatelessWidget { ...@@ -125,6 +139,8 @@ class NavigationDrawer extends StatelessWidget {
index: index, index: index,
totalNumberOfDestinations: totalNumberOfDestinations, totalNumberOfDestinations: totalNumberOfDestinations,
selectedAnimation: animation, selectedAnimation: animation,
indicatorColor: indicatorColor,
indicatorShape: indicatorShape,
onTap: () { onTap: () {
if (onDestinationSelected != null) { if (onDestinationSelected != null) {
onDestinationSelected!(index); onDestinationSelected!(index);
...@@ -315,9 +331,9 @@ class _NavigationDestinationBuilder extends StatelessWidget { ...@@ -315,9 +331,9 @@ class _NavigationDestinationBuilder extends StatelessWidget {
alignment: Alignment.center, alignment: Alignment.center,
children: <Widget>[ children: <Widget>[
NavigationIndicator( NavigationIndicator(
animation: _NavigationDrawerDestinationInfo.of(context).selectedAnimation, animation: info.selectedAnimation,
color: navigationDrawerTheme.indicatorColor ?? defaults.indicatorColor!, color: info.indicatorColor ?? navigationDrawerTheme.indicatorColor ?? defaults.indicatorColor!,
shape: navigationDrawerTheme.indicatorShape ?? defaults.indicatorShape!, shape: info.indicatorShape ?? navigationDrawerTheme.indicatorShape ?? defaults.indicatorShape!,
width: (navigationDrawerTheme.indicatorSize ?? defaults.indicatorSize!).width, width: (navigationDrawerTheme.indicatorSize ?? defaults.indicatorSize!).width,
height: (navigationDrawerTheme.indicatorSize ?? defaults.indicatorSize!).height, height: (navigationDrawerTheme.indicatorSize ?? defaults.indicatorSize!).height,
), ),
...@@ -433,6 +449,8 @@ class _NavigationDrawerDestinationInfo extends InheritedWidget { ...@@ -433,6 +449,8 @@ class _NavigationDrawerDestinationInfo extends InheritedWidget {
required this.index, required this.index,
required this.totalNumberOfDestinations, required this.totalNumberOfDestinations,
required this.selectedAnimation, required this.selectedAnimation,
required this.indicatorColor,
required this.indicatorShape,
required this.onTap, required this.onTap,
required super.child, required super.child,
}); });
...@@ -478,6 +496,16 @@ class _NavigationDrawerDestinationInfo extends InheritedWidget { ...@@ -478,6 +496,16 @@ class _NavigationDrawerDestinationInfo extends InheritedWidget {
/// to 1 (selected). /// to 1 (selected).
final Animation<double> selectedAnimation; final Animation<double> selectedAnimation;
/// The color of the indicator.
///
/// This is used by destinations to override the indicator color.
final Color? indicatorColor;
/// The shape of the indicator.
///
/// This is used by destinations to override the indicator shape.
final ShapeBorder? indicatorShape;
/// The callback that should be called when this destination is tapped. /// The callback that should be called when this destination is tapped.
/// ///
/// This is computed by calling [NavigationDrawer.onDestinationSelected] /// This is computed by calling [NavigationDrawer.onDestinationSelected]
......
...@@ -110,6 +110,7 @@ class NavigationRail extends StatefulWidget { ...@@ -110,6 +110,7 @@ class NavigationRail extends StatefulWidget {
this.minExtendedWidth, this.minExtendedWidth,
this.useIndicator, this.useIndicator,
this.indicatorColor, this.indicatorColor,
this.indicatorShape,
}) : assert(destinations != null && destinations.length >= 2), }) : assert(destinations != null && destinations.length >= 2),
assert(selectedIndex == null || (0 <= selectedIndex && selectedIndex < destinations.length)), assert(selectedIndex == null || (0 <= selectedIndex && selectedIndex < destinations.length)),
assert(elevation == null || elevation > 0), assert(elevation == null || elevation > 0),
...@@ -306,8 +307,18 @@ class NavigationRail extends StatefulWidget { ...@@ -306,8 +307,18 @@ class NavigationRail extends StatefulWidget {
/// Overrides the default value of [NavigationRail]'s selection indicator color, /// Overrides the default value of [NavigationRail]'s selection indicator color,
/// when [useIndicator] is true. /// when [useIndicator] is true.
///
/// If this is null, [NavigationRailThemeData.indicatorColor] is used. If
/// that is null, defaults to [ColorScheme.secondaryContainer].
final Color? indicatorColor; final Color? indicatorColor;
/// Overrides the default value of [NavigationRail]'s selection indicator shape,
/// when [useIndicator] is true.
///
/// If this is null, [NavigationRailThemeData.indicatorShape] is used. If
/// that is null, defaults to [StadiumBorder].
final ShapeBorder? indicatorShape;
/// Returns the animation that controls the [NavigationRail.extended] state. /// Returns the animation that controls the [NavigationRail.extended] state.
/// ///
/// This can be used to synchronize animations in the [leading] or [trailing] /// This can be used to synchronize animations in the [leading] or [trailing]
...@@ -396,7 +407,7 @@ class _NavigationRailState extends State<NavigationRail> with TickerProviderStat ...@@ -396,7 +407,7 @@ class _NavigationRailState extends State<NavigationRail> with TickerProviderStat
final NavigationRailLabelType labelType = widget.labelType ?? navigationRailTheme.labelType ?? defaults.labelType!; final NavigationRailLabelType labelType = widget.labelType ?? navigationRailTheme.labelType ?? defaults.labelType!;
final bool useIndicator = widget.useIndicator ?? navigationRailTheme.useIndicator ?? defaults.useIndicator!; final bool useIndicator = widget.useIndicator ?? navigationRailTheme.useIndicator ?? defaults.useIndicator!;
final Color? indicatorColor = widget.indicatorColor ?? navigationRailTheme.indicatorColor ?? defaults.indicatorColor; final Color? indicatorColor = widget.indicatorColor ?? navigationRailTheme.indicatorColor ?? defaults.indicatorColor;
final ShapeBorder? indicatorShape = navigationRailTheme.indicatorShape ?? defaults.indicatorShape; final ShapeBorder? indicatorShape = widget.indicatorShape ?? navigationRailTheme.indicatorShape ?? defaults.indicatorShape;
// For backwards compatibility, in M2 the opacity of the unselected icons needs // For backwards compatibility, in M2 the opacity of the unselected icons needs
// to be set to the default if it isn't in the given theme. This can be removed // to be set to the default if it isn't in the given theme. This can be removed
...@@ -900,6 +911,8 @@ class NavigationRailDestination { ...@@ -900,6 +911,8 @@ class NavigationRailDestination {
const NavigationRailDestination({ const NavigationRailDestination({
required this.icon, required this.icon,
Widget? selectedIcon, Widget? selectedIcon,
this.indicatorColor,
this.indicatorShape,
required this.label, required this.label,
this.padding, this.padding,
}) : selectedIcon = selectedIcon ?? icon, }) : selectedIcon = selectedIcon ?? icon,
...@@ -933,6 +946,12 @@ class NavigationRailDestination { ...@@ -933,6 +946,12 @@ class NavigationRailDestination {
/// icons. /// icons.
final Widget selectedIcon; final Widget selectedIcon;
/// The color of the [indicatorShape] when this destination is selected.
final Color? indicatorColor;
/// The shape of the selection inidicator.
final ShapeBorder? indicatorShape;
/// The label for the destination. /// The label for the destination.
/// ///
/// The label must be provided when used with the [NavigationRail]. When the /// The label must be provided when used with the [NavigationRail]. When the
......
...@@ -263,8 +263,8 @@ void main() { ...@@ -263,8 +263,8 @@ void main() {
expect(_getMaterial(tester).surfaceTintColor, null); expect(_getMaterial(tester).surfaceTintColor, null);
expect(_getMaterial(tester).elevation, 0); expect(_getMaterial(tester).elevation, 0);
expect(tester.getSize(find.byType(NavigationBar)).height, 80); expect(tester.getSize(find.byType(NavigationBar)).height, 80);
expect(_indicator(tester)?.color, const Color(0x3d2196f3)); expect(_getIndicatorDecoration(tester)?.color, const Color(0x3d2196f3));
expect(_indicator(tester)?.shape, RoundedRectangleBorder(borderRadius: BorderRadius.circular(16))); expect(_getIndicatorDecoration(tester)?.shape, RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)));
// M3 settings from the token database. // M3 settings from the token database.
await tester.pumpWidget( await tester.pumpWidget(
...@@ -292,8 +292,8 @@ void main() { ...@@ -292,8 +292,8 @@ void main() {
expect(_getMaterial(tester).surfaceTintColor, ThemeData().colorScheme.surfaceTint); expect(_getMaterial(tester).surfaceTintColor, ThemeData().colorScheme.surfaceTint);
expect(_getMaterial(tester).elevation, 3); expect(_getMaterial(tester).elevation, 3);
expect(tester.getSize(find.byType(NavigationBar)).height, 80); expect(tester.getSize(find.byType(NavigationBar)).height, 80);
expect(_indicator(tester)?.color, const Color(0xff2196f3)); expect(_getIndicatorDecoration(tester)?.color, const Color(0xff2196f3));
expect(_indicator(tester)?.shape, const StadiumBorder()); expect(_getIndicatorDecoration(tester)?.shape, const StadiumBorder());
}); });
testWidgets('NavigationBar shows tooltips with text scaling ', (WidgetTester tester) async { testWidgets('NavigationBar shows tooltips with text scaling ', (WidgetTester tester) async {
...@@ -807,21 +807,21 @@ void main() { ...@@ -807,21 +807,21 @@ void main() {
testWidgets('Navigation destination updates indicator color and shape', (WidgetTester tester) async { testWidgets('Navigation destination updates indicator color and shape', (WidgetTester tester) async {
final ThemeData theme = ThemeData(useMaterial3: true); final ThemeData theme = ThemeData(useMaterial3: true);
const Color color = Color(0xff0000ff); const Color color = Color(0xff0000ff);
const ShapeBorder shape = CircleBorder(); const ShapeBorder shape = RoundedRectangleBorder();
Widget buildNaviagationBar({Color? indicatorColor, ShapeBorder? indicatorShape}) { Widget buildNavigationBar({Color? indicatorColor, ShapeBorder? indicatorShape}) {
return MaterialApp( return MaterialApp(
theme: theme, theme: theme,
home: Scaffold( home: Scaffold(
bottomNavigationBar: NavigationBar( bottomNavigationBar: NavigationBar(
destinations: <Widget>[ indicatorColor: indicatorColor,
indicatorShape: indicatorShape,
destinations: const <Widget>[
NavigationDestination( NavigationDestination(
icon: const Icon(Icons.ac_unit), icon: Icon(Icons.ac_unit),
label: 'AC', label: 'AC',
indicatorColor: indicatorColor,
indicatorShape: indicatorShape,
), ),
const NavigationDestination( NavigationDestination(
icon: Icon(Icons.access_alarm), icon: Icon(Icons.access_alarm),
label: 'Alarm', label: 'Alarm',
), ),
...@@ -832,17 +832,17 @@ void main() { ...@@ -832,17 +832,17 @@ void main() {
); );
} }
await tester.pumpWidget(buildNaviagationBar()); await tester.pumpWidget(buildNavigationBar());
// Test default indicator color and shape. // Test default indicator color and shape.
expect(_indicator(tester)?.color, theme.colorScheme.secondaryContainer); expect(_getIndicatorDecoration(tester)?.color, theme.colorScheme.secondaryContainer);
expect(_indicator(tester)?.shape, const StadiumBorder()); expect(_getIndicatorDecoration(tester)?.shape, const StadiumBorder());
await tester.pumpWidget(buildNaviagationBar(indicatorColor: color, indicatorShape: shape)); await tester.pumpWidget(buildNavigationBar(indicatorColor: color, indicatorShape: shape));
// Test custom indicator color and shape. // Test custom indicator color and shape.
expect(_indicator(tester)?.color, color); expect(_getIndicatorDecoration(tester)?.color, color);
expect(_indicator(tester)?.shape, shape); expect(_getIndicatorDecoration(tester)?.shape, shape);
}); });
group('Material 2', () { group('Material 2', () {
...@@ -852,21 +852,21 @@ void main() { ...@@ -852,21 +852,21 @@ void main() {
testWidgets('Navigation destination updates indicator color and shape', (WidgetTester tester) async { testWidgets('Navigation destination updates indicator color and shape', (WidgetTester tester) async {
final ThemeData theme = ThemeData(useMaterial3: false); final ThemeData theme = ThemeData(useMaterial3: false);
const Color color = Color(0xff0000ff); const Color color = Color(0xff0000ff);
const ShapeBorder shape = CircleBorder(); const ShapeBorder shape = RoundedRectangleBorder();
Widget buildNaviagationBar({Color? indicatorColor, ShapeBorder? indicatorShape}) { Widget buildNavigationBar({Color? indicatorColor, ShapeBorder? indicatorShape}) {
return MaterialApp( return MaterialApp(
theme: theme, theme: theme,
home: Scaffold( home: Scaffold(
bottomNavigationBar: NavigationBar( bottomNavigationBar: NavigationBar(
destinations: <Widget>[ indicatorColor: indicatorColor,
indicatorShape: indicatorShape,
destinations: const <Widget>[
NavigationDestination( NavigationDestination(
icon: const Icon(Icons.ac_unit), icon: Icon(Icons.ac_unit),
label: 'AC', label: 'AC',
indicatorColor: indicatorColor,
indicatorShape: indicatorShape,
), ),
const NavigationDestination( NavigationDestination(
icon: Icon(Icons.access_alarm), icon: Icon(Icons.access_alarm),
label: 'Alarm', label: 'Alarm',
), ),
...@@ -877,20 +877,20 @@ void main() { ...@@ -877,20 +877,20 @@ void main() {
); );
} }
await tester.pumpWidget(buildNaviagationBar()); await tester.pumpWidget(buildNavigationBar());
// Test default indicator color and shape. // Test default indicator color and shape.
expect(_indicator(tester)?.color, theme.colorScheme.secondary.withOpacity(0.24)); expect(_getIndicatorDecoration(tester)?.color, theme.colorScheme.secondary.withOpacity(0.24));
expect( expect(
_indicator(tester)?.shape, _getIndicatorDecoration(tester)?.shape,
const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16))), const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16))),
); );
await tester.pumpWidget(buildNaviagationBar(indicatorColor: color, indicatorShape: shape)); await tester.pumpWidget(buildNavigationBar(indicatorColor: color, indicatorShape: shape));
// Test custom indicator color and shape. // Test custom indicator color and shape.
expect(_indicator(tester)?.color, color); expect(_getIndicatorDecoration(tester)?.color, color);
expect(_indicator(tester)?.shape, shape); expect(_getIndicatorDecoration(tester)?.shape, shape);
}); });
}); });
} }
...@@ -912,7 +912,7 @@ Material _getMaterial(WidgetTester tester) { ...@@ -912,7 +912,7 @@ Material _getMaterial(WidgetTester tester) {
); );
} }
ShapeDecoration? _indicator(WidgetTester tester) { ShapeDecoration? _getIndicatorDecoration(WidgetTester tester) {
return tester.firstWidget<Container>( return tester.firstWidget<Container>(
find.descendant( find.descendant(
of: find.byType(FadeTransition), of: find.byType(FadeTransition),
......
...@@ -23,7 +23,7 @@ void main() { ...@@ -23,7 +23,7 @@ void main() {
), ),
NavigationDrawerDestination( NavigationDrawerDestination(
icon: Icon(Icons.access_alarm, color: theme.iconTheme.color), icon: Icon(Icons.access_alarm, color: theme.iconTheme.color),
label: Text('Alarm',style: theme.textTheme.bodySmall), label: Text('Alarm', style: theme.textTheme.bodySmall),
), ),
], ],
onDestinationSelected: (int i) { onDestinationSelected: (int i) {
...@@ -68,7 +68,7 @@ void main() { ...@@ -68,7 +68,7 @@ void main() {
), ),
NavigationDrawerDestination( NavigationDrawerDestination(
icon: Icon(Icons.access_alarm, color: theme.iconTheme.color), icon: Icon(Icons.access_alarm, color: theme.iconTheme.color),
label: Text('Alarm',style: theme.textTheme.bodySmall), label: Text('Alarm', style: theme.textTheme.bodySmall),
), ),
], ],
onDestinationSelected: (int i) {}, onDestinationSelected: (int i) {},
...@@ -97,7 +97,7 @@ void main() { ...@@ -97,7 +97,7 @@ void main() {
), ),
NavigationDrawerDestination( NavigationDrawerDestination(
icon: Icon(Icons.access_alarm, color: theme.iconTheme.color), icon: Icon(Icons.access_alarm, color: theme.iconTheme.color),
label: Text('Alarm',style: theme.textTheme.bodySmall), label: Text('Alarm', style: theme.textTheme.bodySmall),
), ),
], ],
); );
...@@ -134,7 +134,7 @@ void main() { ...@@ -134,7 +134,7 @@ void main() {
), ),
NavigationDrawerDestination( NavigationDrawerDestination(
icon: Icon(Icons.access_alarm, color: theme.iconTheme.color), icon: Icon(Icons.access_alarm, color: theme.iconTheme.color),
label: Text('Alarm',style: theme.textTheme.bodySmall), label: Text('Alarm', style: theme.textTheme.bodySmall),
), ),
], ],
onDestinationSelected: (int i) {}, onDestinationSelected: (int i) {},
...@@ -149,8 +149,8 @@ void main() { ...@@ -149,8 +149,8 @@ void main() {
expect(_getMaterial(tester).surfaceTintColor, expect(_getMaterial(tester).surfaceTintColor,
ThemeData().colorScheme.surfaceTint); ThemeData().colorScheme.surfaceTint);
expect(_getMaterial(tester).elevation, 1); expect(_getMaterial(tester).elevation, 1);
expect(_indicator(tester)?.color, const Color(0xff2196f3)); expect(_getIndicatorDecoration(tester)?.color, const Color(0xff2196f3));
expect(_indicator(tester)?.shape, const StadiumBorder()); expect(_getIndicatorDecoration(tester)?.shape, const StadiumBorder());
}); });
testWidgets('Navigation drawer semantics', (WidgetTester tester) async { testWidgets('Navigation drawer semantics', (WidgetTester tester) async {
...@@ -169,7 +169,7 @@ void main() { ...@@ -169,7 +169,7 @@ void main() {
), ),
NavigationDrawerDestination( NavigationDrawerDestination(
icon: Icon(Icons.access_alarm, color: theme.iconTheme.color), icon: Icon(Icons.access_alarm, color: theme.iconTheme.color),
label: Text('Alarm',style: theme.textTheme.bodySmall), label: Text('Alarm', style: theme.textTheme.bodySmall),
), ),
], ],
), ),
...@@ -222,6 +222,53 @@ void main() { ...@@ -222,6 +222,53 @@ void main() {
), ),
); );
}); });
testWidgets('Navigation destination updates indicator color and shape', (WidgetTester tester) async {
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
final ThemeData theme = ThemeData(useMaterial3: true);
const Color color = Color(0xff0000ff);
const ShapeBorder shape = RoundedRectangleBorder();
Widget buildNavigationDrawer({Color? indicatorColor, ShapeBorder? indicatorShape}) {
return MaterialApp(
theme: theme,
home: Scaffold(
key: scaffoldKey,
drawer: NavigationDrawer(
indicatorColor: indicatorColor,
indicatorShape: indicatorShape,
children: <Widget>[
Text('Headline', style: theme.textTheme.bodyLarge),
const NavigationDrawerDestination(
icon: Icon(Icons.ac_unit),
label: Text('AC'),
),
const NavigationDrawerDestination(
icon: Icon(Icons.access_alarm),
label: Text('Alarm'),
),
],
onDestinationSelected: (int i) { },
),
body: Container(),
),
);
}
await tester.pumpWidget(buildNavigationDrawer());
scaffoldKey.currentState!.openDrawer();
await tester.pumpAndSettle();
// Test default indicator color and shape.
expect(_getIndicatorDecoration(tester)?.color, theme.colorScheme.secondaryContainer);
expect(_getIndicatorDecoration(tester)?.shape, const StadiumBorder());
await tester.pumpWidget(buildNavigationDrawer(indicatorColor: color, indicatorShape: shape));
// Test custom indicator color and shape.
expect(_getIndicatorDecoration(tester)?.color, color);
expect(_getIndicatorDecoration(tester)?.shape, shape);
});
} }
Widget _buildWidget(GlobalKey<ScaffoldState> scaffoldKey, Widget child) { Widget _buildWidget(GlobalKey<ScaffoldState> scaffoldKey, Widget child) {
...@@ -242,7 +289,7 @@ Material _getMaterial(WidgetTester tester) { ...@@ -242,7 +289,7 @@ Material _getMaterial(WidgetTester tester) {
); );
} }
ShapeDecoration? _indicator(WidgetTester tester) { ShapeDecoration? _getIndicatorDecoration(WidgetTester tester) {
return tester return tester
.firstWidget<Container>( .firstWidget<Container>(
find.descendant( find.descendant(
......
...@@ -2846,6 +2846,50 @@ void main() { ...@@ -2846,6 +2846,50 @@ void main() {
expect(transform.getColumn(0)[0], 1.0); expect(transform.getColumn(0)[0], 1.0);
}); });
testWidgets('Navigation destination updates indicator color and shape', (WidgetTester tester) async {
final ThemeData theme = ThemeData(useMaterial3: true);
const Color color = Color(0xff0000ff);
const ShapeBorder shape = RoundedRectangleBorder();
Widget buildNavigationRail({Color? indicatorColor, ShapeBorder? indicatorShape}) {
return MaterialApp(
theme: theme,
home: Builder(
builder: (BuildContext context) {
return Scaffold(
body: Row(
children: <Widget>[
NavigationRail(
useIndicator: true,
indicatorColor: indicatorColor,
indicatorShape: indicatorShape,
selectedIndex: 0,
destinations: _destinations(),
),
const Expanded(
child: Text('body'),
),
],
),
);
},
),
);
}
await tester.pumpWidget(buildNavigationRail());
// Test default indicator color and shape.
expect(_getIndicatorDecoration(tester)?.color, theme.colorScheme.secondaryContainer);
expect(_getIndicatorDecoration(tester)?.shape, const StadiumBorder());
await tester.pumpWidget(buildNavigationRail(indicatorColor: color, indicatorShape: shape));
// Test custom indicator color and shape.
expect(_getIndicatorDecoration(tester)?.color, color);
expect(_getIndicatorDecoration(tester)?.shape, shape);
});
group('Material 2', () { group('Material 2', () {
// Original Material 2 tests. Remove this group after `useMaterial3` has been deprecated. // Original Material 2 tests. Remove this group after `useMaterial3` has been deprecated.
testWidgets('Renders at the correct default width - [labelType]=none (default)', (WidgetTester tester) async { testWidgets('Renders at the correct default width - [labelType]=none (default)', (WidgetTester tester) async {
...@@ -4655,7 +4699,6 @@ void main() { ...@@ -4655,7 +4699,6 @@ void main() {
final double updatedWidthRTL = tester.getSize(find.byType(NavigationRail)).width; final double updatedWidthRTL = tester.getSize(find.byType(NavigationRail)).width;
expect(updatedWidthRTL, defaultWidth + safeAreaPadding); expect(updatedWidthRTL, defaultWidth + safeAreaPadding);
}); });
}); // End Material 2 group }); // End Material 2 group
} }
...@@ -4878,3 +4921,12 @@ Widget _buildWidget(Widget child, {bool useMaterial3 = true, bool isRTL = false} ...@@ -4878,3 +4921,12 @@ Widget _buildWidget(Widget child, {bool useMaterial3 = true, bool isRTL = false}
), ),
); );
} }
ShapeDecoration? _getIndicatorDecoration(WidgetTester tester) {
return tester.firstWidget<Container>(
find.descendant(
of: find.byType(FadeTransition),
matching: find.byType(Container),
),
).decoration as ShapeDecoration?;
}
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