Update Material 3 Demo App (#1530)

pull/1543/head
Qun Cheng 2 years ago committed by GitHub
parent 019441374e
commit 405ebafe04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

File diff suppressed because it is too large Load Diff

@ -12,35 +12,45 @@ class ElevationScreen extends StatelessWidget {
Color shadowColor = Theme.of(context).colorScheme.shadow; Color shadowColor = Theme.of(context).colorScheme.shadow;
Color surfaceTint = Theme.of(context).colorScheme.primary; Color surfaceTint = Theme.of(context).colorScheme.primary;
return Expanded( return Expanded(
child: ListView( child: CustomScrollView(
children: [ slivers: [
Padding( SliverToBoxAdapter(
padding: const EdgeInsets.fromLTRB(16.0, 20, 16.0, 0), child: Padding(
child: Text( padding: const EdgeInsets.fromLTRB(16.0, 20, 16.0, 0),
'Surface Tint only', child: Text(
style: Theme.of(context).textTheme.titleLarge, 'Surface Tint Color Only',
style: Theme.of(context).textTheme.titleLarge,
),
), ),
), ),
ElevationGrid(surfaceTintColor: surfaceTint), ElevationGrid(surfaceTintColor: surfaceTint),
const SizedBox(height: 10), SliverList(
Padding( delegate: SliverChildListDelegate(<Widget>[
padding: const EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 0), const SizedBox(height: 10),
child: Text( Padding(
'Surface Tint and Shadow', padding: const EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 0),
style: Theme.of(context).textTheme.titleLarge, child: Text(
), 'Surface Tint Color and Shadow Color',
style: Theme.of(context).textTheme.titleLarge,
),
),
]),
), ),
ElevationGrid( ElevationGrid(
shadowColor: shadowColor, shadowColor: shadowColor,
surfaceTintColor: surfaceTint, surfaceTintColor: surfaceTint,
), ),
const SizedBox(height: 10), SliverList(
Padding( delegate: SliverChildListDelegate(<Widget>[
padding: const EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 0), const SizedBox(height: 10),
child: Text( Padding(
'Shadow only', padding: const EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 0),
style: Theme.of(context).textTheme.titleLarge, child: Text(
), 'Shadow Color Only',
style: Theme.of(context).textTheme.titleLarge,
),
),
]),
), ),
ElevationGrid(shadowColor: shadowColor), ElevationGrid(shadowColor: shadowColor),
], ],
@ -72,18 +82,16 @@ class ElevationGrid extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Padding( return SliverPadding(
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
child: LayoutBuilder(builder: (context, constraints) { sliver: SliverLayoutBuilder(builder: (context, constraints) {
if (constraints.maxWidth < narrowScreenWidthThreshold) { if (constraints.crossAxisExtent < narrowScreenWidthThreshold) {
return GridView.count( return SliverGrid.count(
shrinkWrap: true,
crossAxisCount: 3, crossAxisCount: 3,
children: elevationCards(shadowColor, surfaceTintColor), children: elevationCards(shadowColor, surfaceTintColor),
); );
} else { } else {
return GridView.count( return SliverGrid.count(
shrinkWrap: true,
crossAxisCount: 6, crossAxisCount: 6,
children: elevationCards(shadowColor, surfaceTintColor), children: elevationCards(shadowColor, surfaceTintColor),
); );

@ -9,7 +9,8 @@ import 'elevation_screen.dart';
import 'typography_screen.dart'; import 'typography_screen.dart';
void main() { void main() {
runApp(const Material3Demo()); runApp(const MaterialApp(
debugShowCheckedModeBanner: false, home: Material3Demo()));
} }
class Material3Demo extends StatefulWidget { class Material3Demo extends StatefulWidget {
@ -23,25 +24,23 @@ class Material3Demo extends StatefulWidget {
// screenWidthThreshold; otherwise, NavigationBar is used for navigation. // screenWidthThreshold; otherwise, NavigationBar is used for navigation.
const double narrowScreenWidthThreshold = 450; const double narrowScreenWidthThreshold = 450;
const Color m3BaseColor = Color(0xff6750a4); const double transitionLength = 500;
const List<Color> colorOptions = [
m3BaseColor, enum ColorSeed {
Colors.blue, baseColor('M3 Baseline', Color(0xff6750a4)),
Colors.teal, indigo('Indigo', Colors.indigo),
Colors.green, blue('Blue', Colors.blue),
Colors.yellow, teal('Teal', Colors.teal),
Colors.orange, green('Green', Colors.green),
Colors.pink yellow('Yellow', Colors.yellow),
]; orange('Orange', Colors.orange),
const List<String> colorText = <String>[ deepOrange('Deep Orange', Colors.deepOrange),
'M3 Baseline', pink('Pink', Colors.pink);
'Blue',
'Teal', const ColorSeed(this.label, this.color);
'Green', final String label;
'Yellow', final Color color;
'Orange', }
'Pink',
];
enum ScreenSelected { enum ScreenSelected {
component(0), component(0),
@ -53,10 +52,17 @@ enum ScreenSelected {
final int value; final int value;
} }
class _Material3DemoState extends State<Material3Demo> { class _Material3DemoState extends State<Material3Demo>
with SingleTickerProviderStateMixin {
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
late final AnimationController controller;
late final CurvedAnimation railAnimation;
bool controllerInitialized = false;
bool showMediumSizeLayout = false;
bool showLargeSizeLayout = false;
bool useMaterial3 = true; bool useMaterial3 = true;
bool useLightMode = true; bool useLightMode = true;
int colorSelected = 0; ColorSeed colorSelected = ColorSeed.baseColor;
int screenIndex = ScreenSelected.component.value; int screenIndex = ScreenSelected.component.value;
late ThemeData themeData; late ThemeData themeData;
@ -64,12 +70,61 @@ class _Material3DemoState extends State<Material3Demo> {
@override @override
initState() { initState() {
super.initState(); super.initState();
themeData = updateThemes(colorSelected, useMaterial3, useLightMode); themeData = updateThemes(colorSelected.color, useMaterial3, useLightMode);
controller = AnimationController(
duration: Duration(milliseconds: transitionLength.toInt() * 2),
value: 0,
vsync: this,
);
railAnimation = CurvedAnimation(
parent: controller,
curve: const Interval(0.5, 1.0),
);
}
@override
void dispose() {
controller.dispose();
super.dispose();
} }
ThemeData updateThemes(int colorIndex, bool useMaterial3, bool useLightMode) { @override
void didChangeDependencies() {
super.didChangeDependencies();
final double width = MediaQuery.of(context).size.width;
final AnimationStatus status = controller.status;
if (width > 1000) {
if (width > 1500) {
showMediumSizeLayout = false;
showLargeSizeLayout = true;
} else {
showMediumSizeLayout = true;
showLargeSizeLayout = false;
}
if (status != AnimationStatus.forward &&
status != AnimationStatus.completed) {
controller.forward();
}
} else {
showMediumSizeLayout = false;
showLargeSizeLayout = false;
if (status != AnimationStatus.reverse &&
status != AnimationStatus.dismissed) {
controller.reverse();
}
}
if (!controllerInitialized) {
controllerInitialized = true;
controller.value = width > 1000 ? 1 : 0;
}
}
ThemeData updateThemes(
Color colorSelected, bool useMaterial3, bool useLightMode) {
return ThemeData( return ThemeData(
colorSchemeSeed: colorOptions[colorSelected], colorSchemeSeed: colorSelected,
useMaterial3: useMaterial3, useMaterial3: useMaterial3,
brightness: useLightMode ? Brightness.light : Brightness.dark); brightness: useLightMode ? Brightness.light : Brightness.dark);
} }
@ -83,21 +138,21 @@ class _Material3DemoState extends State<Material3Demo> {
void handleBrightnessChange() { void handleBrightnessChange() {
setState(() { setState(() {
useLightMode = !useLightMode; useLightMode = !useLightMode;
themeData = updateThemes(colorSelected, useMaterial3, useLightMode); themeData = updateThemes(colorSelected.color, useMaterial3, useLightMode);
}); });
} }
void handleMaterialVersionChange() { void handleMaterialVersionChange() {
setState(() { setState(() {
useMaterial3 = !useMaterial3; useMaterial3 = !useMaterial3;
themeData = updateThemes(colorSelected, useMaterial3, useLightMode); themeData = updateThemes(colorSelected.color, useMaterial3, useLightMode);
}); });
} }
void handleColorSelect(int value) { void handleColorSelect(int value) {
setState(() { setState(() {
colorSelected = value; colorSelected = ColorSeed.values[value];
themeData = updateThemes(colorSelected, useMaterial3, useLightMode); themeData = updateThemes(colorSelected.color, useMaterial3, useLightMode);
}); });
} }
@ -105,7 +160,15 @@ class _Material3DemoState extends State<Material3Demo> {
ScreenSelected screenSelected, bool showNavBarExample) { ScreenSelected screenSelected, bool showNavBarExample) {
switch (screenSelected) { switch (screenSelected) {
case ScreenSelected.component: case ScreenSelected.component:
return ComponentScreen(showNavBottomBar: showNavBarExample); return Expanded(
child: OneTwoTransition(
animation: railAnimation,
one: FirstComponentList(
showNavBottomBar: showNavBarExample,
scaffoldKey: scaffoldKey,
showSecondList:
showMediumSizeLayout || showLargeSizeLayout),
two: const SecondComponentList()));
case ScreenSelected.color: case ScreenSelected.color:
return const ColorPalettesScreen(); return const ColorPalettesScreen();
case ScreenSelected.typography: case ScreenSelected.typography:
@ -113,62 +176,140 @@ class _Material3DemoState extends State<Material3Demo> {
case ScreenSelected.elevation: case ScreenSelected.elevation:
return const ElevationScreen(); return const ElevationScreen();
default: default:
return ComponentScreen(showNavBottomBar: showNavBarExample); return FirstComponentList(
showNavBottomBar: showNavBarExample,
scaffoldKey: scaffoldKey,
showSecondList: showMediumSizeLayout || showLargeSizeLayout);
} }
} }
PreferredSizeWidget createAppBar() { Widget brightnessButton({bool showTooltipBelow = true}) => Tooltip(
return AppBar( preferBelow: showTooltipBelow,
title: useMaterial3 ? const Text('Material 3') : const Text('Material 2'), message: 'Toggle brightness',
actions: [ child: IconButton(
IconButton(
icon: useLightMode icon: useLightMode
? const Icon(Icons.wb_sunny_outlined) ? const Icon(Icons.wb_sunny_outlined)
: const Icon(Icons.wb_sunny), : const Icon(Icons.wb_sunny),
onPressed: handleBrightnessChange, onPressed: handleBrightnessChange,
tooltip: 'Toggle brightness',
), ),
IconButton( );
Widget material3Button({bool showTooltipBelow = true}) => Tooltip(
preferBelow: showTooltipBelow,
message: 'Switch to Material ${useMaterial3 ? 2 : 3}',
child: IconButton(
icon: useMaterial3 icon: useMaterial3
? const Icon(Icons.filter_3) ? const Icon(Icons.filter_3)
: const Icon(Icons.filter_2), : const Icon(Icons.filter_2),
onPressed: handleMaterialVersionChange, onPressed: handleMaterialVersionChange,
tooltip: 'Switch to Material ${useMaterial3 ? 2 : 3}',
), ),
PopupMenuButton( );
icon: const Icon(Icons.more_vert),
shape: Widget colorSeedButton(Icon icon) => PopupMenuButton(
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), icon: icon,
itemBuilder: (context) { shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
return List.generate(colorOptions.length, (index) { itemBuilder: (context) {
return PopupMenuItem( return List.generate(ColorSeed.values.length, (index) {
value: index, ColorSeed currentColor = ColorSeed.values[index];
child: Wrap(
children: [ return PopupMenuItem(
Padding( value: index,
padding: const EdgeInsets.only(left: 10), child: Wrap(
child: Icon( children: [
index == colorSelected Padding(
? Icons.color_lens padding: const EdgeInsets.only(left: 10),
: Icons.color_lens_outlined, child: Icon(
color: colorOptions[index], currentColor == colorSelected
), ? Icons.color_lens
), : Icons.color_lens_outlined,
Padding( color: currentColor.color,
padding: const EdgeInsets.only(left: 20),
child: Text(colorText[index]),
), ),
], ),
), Padding(
); padding: const EdgeInsets.only(left: 20),
}); child: Text(currentColor.label),
}, ),
onSelected: handleColorSelect, ],
), ),
], );
});
},
onSelected: handleColorSelect,
);
PreferredSizeWidget createAppBar() {
return AppBar(
title: useMaterial3 ? const Text('Material 3') : const Text('Material 2'),
actions: !showMediumSizeLayout && !showLargeSizeLayout
? [
brightnessButton(),
material3Button(),
colorSeedButton(const Icon(Icons.more_vert)),
]
: [Container()],
); );
} }
Widget _expandedTrailingActions() => Container(
constraints: const BoxConstraints.tightFor(width: 250),
padding: const EdgeInsets.symmetric(horizontal: 30),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row(
children: [
const Text('Brightness'),
Expanded(child: Container()),
Switch(
value: useLightMode,
onChanged: (_) {
handleBrightnessChange();
})
],
),
Row(
children: [
useMaterial3
? const Text('Material 3')
: const Text('Material 2'),
Expanded(child: Container()),
Switch(
value: useMaterial3,
onChanged: (_) {
handleMaterialVersionChange();
})
],
),
const Divider(),
ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 200.0),
child: GridView.count(
crossAxisCount: 3,
children: List.generate(
ColorSeed.values.length,
(i) => IconButton(
icon: const Icon(Icons.circle),
color: ColorSeed.values[i].color,
onPressed: () {
handleColorSelect(i);
},
)),
),
),
],
),
);
Widget _trailingActions() => Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Flexible(child: brightnessButton(showTooltipBelow: false)),
Flexible(child: material3Button(showTooltipBelow: false)),
Flexible(child: colorSeedButton(const Icon(Icons.more_horiz))),
],
);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
@ -176,40 +317,337 @@ class _Material3DemoState extends State<Material3Demo> {
title: 'Material 3', title: 'Material 3',
themeMode: useLightMode ? ThemeMode.light : ThemeMode.dark, themeMode: useLightMode ? ThemeMode.light : ThemeMode.dark,
theme: themeData, theme: themeData,
home: LayoutBuilder(builder: (context, constraints) { home: AnimatedBuilder(
if (constraints.maxWidth < narrowScreenWidthThreshold) { animation: controller,
return Scaffold( builder: (context, child) {
appBar: createAppBar(), return NavigationTransition(
body: Row(children: <Widget>[ scaffoldKey: scaffoldKey,
createScreenFor(ScreenSelected.values[screenIndex], false), animationController: controller,
]), railAnimation: railAnimation,
bottomNavigationBar: NavigationBars( appBar: createAppBar(),
onSelectItem: handleScreenChanged, body: createScreenFor(
selectedIndex: screenIndex, ScreenSelected.values[screenIndex], controller.value == 1),
isExampleBar: false, navigationRail: NavigationRail(
), extended: showLargeSizeLayout,
); destinations: navRailDestinations,
} else { selectedIndex: screenIndex,
return Scaffold( onDestinationSelected: (index) {
appBar: createAppBar(), setState(() {
body: SafeArea( screenIndex = index;
bottom: false, handleScreenChanged(screenIndex);
top: false, });
child: Row( },
children: <Widget>[ trailing: Expanded(
Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 5), padding: const EdgeInsets.only(bottom: 20),
child: NavigationRailSection( child: showLargeSizeLayout
onSelectItem: handleScreenChanged, ? _expandedTrailingActions()
selectedIndex: screenIndex)), : _trailingActions(),
const VerticalDivider(thickness: 1, width: 1), ),
createScreenFor(ScreenSelected.values[screenIndex], true), ),
], ),
navigationBar: NavigationBars(
onSelectItem: (index) {
setState(() {
screenIndex = index;
handleScreenChanged(screenIndex);
});
},
selectedIndex: screenIndex,
isExampleBar: false,
), ),
);
}),
);
}
}
class NavigationTransition extends StatefulWidget {
const NavigationTransition(
{super.key,
required this.scaffoldKey,
required this.animationController,
required this.railAnimation,
required this.navigationRail,
required this.navigationBar,
required this.appBar,
required this.body});
final GlobalKey<ScaffoldState> scaffoldKey;
final AnimationController animationController;
final CurvedAnimation railAnimation;
final Widget navigationRail;
final Widget navigationBar;
final PreferredSizeWidget appBar;
final Widget body;
@override
State<NavigationTransition> createState() => _NavigationTransitionState();
}
class _NavigationTransitionState extends State<NavigationTransition> {
late final AnimationController controller;
late final CurvedAnimation railAnimation;
late final ReverseAnimation barAnimation;
bool controllerInitialized = false;
bool showDivider = false;
@override
void initState() {
super.initState();
controller = widget.animationController;
railAnimation = widget.railAnimation;
barAnimation = ReverseAnimation(
CurvedAnimation(
parent: controller,
curve: const Interval(0.0, 0.5),
),
);
}
@override
Widget build(BuildContext context) {
final ColorScheme colorScheme = Theme.of(context).colorScheme;
return Scaffold(
key: widget.scaffoldKey,
appBar: widget.appBar,
body: Row(
children: <Widget>[
RailTransition(
animation: railAnimation,
backgroundColor: colorScheme.surface,
child: widget.navigationRail,
),
railAnimation.isDismissed
? const SizedBox()
: const VerticalDivider(width: 1),
widget.body,
],
),
bottomNavigationBar: BarTransition(
animation: barAnimation,
backgroundColor: colorScheme.surface,
child: widget.navigationBar,
),
endDrawer: const NavigationDrawerSection(),
);
}
}
final List<NavigationRailDestination> navRailDestinations = appBarDestinations
.map(
(destination) => NavigationRailDestination(
icon: Tooltip(
message: destination.label,
child: destination.icon,
),
selectedIcon: Tooltip(
message: destination.label,
child: destination.selectedIcon,
),
label: Text(destination.label),
),
)
.toList();
class SizeAnimation extends CurvedAnimation {
SizeAnimation(Animation<double> parent)
: super(
parent: parent,
curve: const Interval(
0.2,
0.8,
curve: Curves.easeInOutCubicEmphasized,
),
reverseCurve: Interval(
0,
0.2,
curve: Curves.easeInOutCubicEmphasized.flipped,
),
);
}
class OffsetAnimation extends CurvedAnimation {
OffsetAnimation(Animation<double> parent)
: super(
parent: parent,
curve: const Interval(
0.4,
1.0,
curve: Curves.easeInOutCubicEmphasized,
),
reverseCurve: Interval(
0,
0.2,
curve: Curves.easeInOutCubicEmphasized.flipped,
),
);
}
class RailTransition extends StatefulWidget {
const RailTransition(
{super.key,
required this.animation,
required this.backgroundColor,
required this.child});
final Animation<double> animation;
final Widget child;
final Color backgroundColor;
@override
State<RailTransition> createState() => _RailTransition();
}
class _RailTransition extends State<RailTransition> {
late Animation<Offset> offsetAnimation;
late Animation<double> widthAnimation;
@override
void didChangeDependencies() {
super.didChangeDependencies();
// The animations are only rebuilt by this method when the text
// direction changes because this widget only depends on Directionality.
final bool ltr = Directionality.of(context) == TextDirection.ltr;
widthAnimation = Tween<double>(
begin: 0,
end: 1,
).animate(SizeAnimation(widget.animation));
offsetAnimation = Tween<Offset>(
begin: ltr ? const Offset(-1, 0) : const Offset(1, 0),
end: Offset.zero,
).animate(OffsetAnimation(widget.animation));
}
@override
Widget build(BuildContext context) {
return ClipRect(
child: DecoratedBox(
decoration: BoxDecoration(color: widget.backgroundColor),
child: Align(
alignment: Alignment.topLeft,
widthFactor: widthAnimation.value,
child: FractionalTranslation(
translation: offsetAnimation.value,
child: widget.child,
),
),
),
);
}
}
class BarTransition extends StatefulWidget {
const BarTransition(
{super.key,
required this.animation,
required this.backgroundColor,
required this.child});
final Animation<double> animation;
final Color backgroundColor;
final Widget child;
@override
State<BarTransition> createState() => _BarTransition();
}
class _BarTransition extends State<BarTransition> {
late final Animation<Offset> offsetAnimation;
late final Animation<double> heightAnimation;
@override
void initState() {
super.initState();
offsetAnimation = Tween<Offset>(
begin: const Offset(0, 1),
end: Offset.zero,
).animate(OffsetAnimation(widget.animation));
heightAnimation = Tween<double>(
begin: 0,
end: 1,
).animate(SizeAnimation(widget.animation));
}
@override
Widget build(BuildContext context) {
return ClipRect(
child: DecoratedBox(
decoration: BoxDecoration(color: widget.backgroundColor),
child: Align(
alignment: Alignment.topLeft,
heightFactor: heightAnimation.value,
child: FractionalTranslation(
translation: offsetAnimation.value,
child: widget.child,
),
),
),
);
}
}
class OneTwoTransition extends StatefulWidget {
const OneTwoTransition({
super.key,
required this.animation,
required this.one,
required this.two,
});
final Animation<double> animation;
final Widget one;
final Widget two;
@override
State<OneTwoTransition> createState() => _OneTwoTransitionState();
}
class _OneTwoTransitionState extends State<OneTwoTransition> {
late final Animation<Offset> offsetAnimation;
late final Animation<double> widthAnimation;
@override
void initState() {
super.initState();
offsetAnimation = Tween<Offset>(
begin: const Offset(1, 0),
end: Offset.zero,
).animate(OffsetAnimation(widget.animation));
widthAnimation = Tween<double>(
begin: 0,
end: 1000,
).animate(SizeAnimation(widget.animation));
}
@override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Flexible(
flex: 1000,
child: widget.one,
),
if (widthAnimation.value.toInt() > 0) ...[
Flexible(
flex: widthAnimation.value.toInt(),
child: FractionalTranslation(
translation: offsetAnimation.value,
child: widget.two,
), ),
); )
} ],
}), ],
); );
} }
} }

@ -345,7 +345,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.13; MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx; SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule; SWIFT_COMPILATION_MODE = wholemodule;
@ -424,7 +424,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.13; MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx; SDKROOT = macosx;
@ -471,7 +471,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.13; MACOSX_DEPLOYMENT_TARGET = 10.14;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx; SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule; SWIFT_COMPILATION_MODE = wholemodule;

@ -16,17 +16,25 @@ void main() {
'on NavigationBar', (tester) async { 'on NavigationBar', (tester) async {
widgetSetup(tester, 449); widgetSetup(tester, 449);
addTearDown(tester.binding.window.clearPhysicalSizeTestValue); addTearDown(tester.binding.window.clearPhysicalSizeTestValue);
await tester.pumpWidget(const Material3Demo()); await tester.pumpWidget(const MaterialApp(home: Material3Demo()));
expect(find.text('Light Theme'), findsNothing); expect(find.text('Light Theme'), findsNothing);
expect(find.text('Dark Theme'), findsNothing); expect(find.text('Dark Theme'), findsNothing);
expect(find.byType(NavigationBar), findsOneWidget); expect(find.byType(NavigationBar), findsOneWidget);
Finder colorIconOnBar = find.byIcon(Icons.format_paint_outlined); Finder colorIconOnBar = find.descendant(
of: find.byType(NavigationBar),
matching: find.widgetWithIcon(
NavigationDestination, Icons.format_paint_outlined));
expect(colorIconOnBar, findsOneWidget); expect(colorIconOnBar, findsOneWidget);
await tester.tap(colorIconOnBar); await tester.tap(colorIconOnBar);
await tester.pumpAndSettle(const Duration(microseconds: 500)); await tester.pumpAndSettle(const Duration(microseconds: 500));
expect(colorIconOnBar, findsNothing); expect(colorIconOnBar, findsNothing);
expect(find.byIcon(Icons.format_paint), findsOneWidget);
Finder selectedColorIconOnBar = find.descendant(
of: find.byType(NavigationBar),
matching:
find.widgetWithIcon(NavigationDestination, Icons.format_paint));
expect(selectedColorIconOnBar, findsOneWidget);
expect(find.text('Light Theme'), findsOneWidget); expect(find.text('Light Theme'), findsOneWidget);
expect(find.text('Dark Theme'), findsOneWidget); expect(find.text('Dark Theme'), findsOneWidget);
}); });
@ -34,18 +42,25 @@ void main() {
testWidgets( testWidgets(
'Color palettes screen shows correctly when color icon is clicked ' 'Color palettes screen shows correctly when color icon is clicked '
'on NavigationRail', (tester) async { 'on NavigationRail', (tester) async {
widgetSetup(tester, 450); // NavigationRail shows only when width is >= 450. widgetSetup(
tester, 1200); // NavigationRail shows only when width is > 1000.
addTearDown(tester.binding.window.clearPhysicalSizeTestValue); addTearDown(tester.binding.window.clearPhysicalSizeTestValue);
await tester.pumpWidget(const Material3Demo()); await tester.pumpWidget(const MaterialApp(home: Material3Demo()));
await tester.pumpAndSettle();
expect(find.text('Light Theme'), findsNothing); expect(find.text('Light Theme'), findsNothing);
expect(find.text('Dark Theme'), findsNothing); expect(find.text('Dark Theme'), findsNothing);
expect(find.byType(NavigationRail), findsOneWidget); expect(find.byType(NavigationRail), findsOneWidget);
Finder colorIconOnRail = find.byIcon(Icons.format_paint_outlined); Finder colorIconOnRail = find.descendant(
of: find.byType(NavigationRail),
matching: find.byIcon(Icons.format_paint_outlined));
expect(colorIconOnRail, findsOneWidget); expect(colorIconOnRail, findsOneWidget);
await tester.tap(colorIconOnRail); await tester.tap(colorIconOnRail);
await tester.pumpAndSettle(const Duration(microseconds: 500)); await tester.pumpAndSettle(const Duration(microseconds: 500));
expect(colorIconOnRail, findsNothing); expect(colorIconOnRail, findsNothing);
expect(find.byIcon(Icons.format_paint), findsOneWidget); Finder selectedColorIconOnRail = find.descendant(
of: find.byType(NavigationRail),
matching: find.byIcon(Icons.format_paint));
expect(selectedColorIconOnRail, findsOneWidget);
expect(find.text('Light Theme'), findsOneWidget); expect(find.text('Light Theme'), findsOneWidget);
expect(find.text('Dark Theme'), findsOneWidget); expect(find.text('Dark Theme'), findsOneWidget);
}); });

@ -10,15 +10,15 @@ import 'package:material_3_demo/main.dart';
void main() { void main() {
testWidgets('Default main page shows all M3 components', (tester) async { testWidgets('Default main page shows all M3 components', (tester) async {
widgetSetup(tester, 800, windowHeight: 3500); widgetSetup(tester, 800, windowHeight: 7000);
await tester.pumpWidget(const Material3Demo()); await tester.pumpWidget(const MaterialApp(home: Material3Demo()));
// Elements on the app bar // Elements on the app bar
expect(find.text('Material 3'), findsOneWidget); expect(find.text('Material 3'), findsOneWidget);
expect(find.widgetWithIcon(IconButton, Icons.wb_sunny_outlined), expect(
findsOneWidget); find.widgetWithIcon(AppBar, Icons.wb_sunny_outlined), findsOneWidget);
expect(find.widgetWithIcon(IconButton, Icons.filter_3), findsOneWidget); expect(find.widgetWithIcon(AppBar, Icons.filter_3), findsOneWidget);
expect(find.widgetWithIcon(IconButton, Icons.more_vert), findsOneWidget); expect(find.widgetWithIcon(AppBar, Icons.more_vert), findsOneWidget);
// Elements on the component screen // Elements on the component screen
// Buttons // Buttons
@ -27,13 +27,14 @@ void main() {
expect(find.widgetWithText(FilledButton, 'Filled Tonal'), findsNWidgets(2)); expect(find.widgetWithText(FilledButton, 'Filled Tonal'), findsNWidgets(2));
expect(find.widgetWithText(OutlinedButton, 'Outlined'), findsNWidgets(2)); expect(find.widgetWithText(OutlinedButton, 'Outlined'), findsNWidgets(2));
expect(find.widgetWithText(TextButton, 'Text'), findsNWidgets(2)); expect(find.widgetWithText(TextButton, 'Text'), findsNWidgets(2));
expect(find.text('Icon'), findsNWidgets(5)); expect(find.widgetWithText(Buttons, 'Icon'), findsNWidgets(5));
// IconButtons // IconButtons
expect(find.byType(IconToggleButton), findsNWidgets(8)); expect(find.byType(IconToggleButton), findsNWidgets(8));
// FABs // FABs
expect(find.byType(FloatingActionButton), findsNWidgets(4)); expect(find.byType(FloatingActionButton),
findsNWidgets(6)); // 2 more shows up in the bottom app bar.
expect(find.widgetWithText(FloatingActionButton, 'Create'), findsOneWidget); expect(find.widgetWithText(FloatingActionButton, 'Create'), findsOneWidget);
// Chips // Chips
@ -43,9 +44,9 @@ void main() {
expect(find.byType(InputChip), findsNWidgets(4)); expect(find.byType(InputChip), findsNWidgets(4));
// Cards // Cards
expect(find.widgetWithText(Card, 'Filled'), findsOneWidget); expect(find.widgetWithText(Cards, 'Elevated'), findsOneWidget);
expect(find.widgetWithText(Card, 'Filled'), findsOneWidget); expect(find.widgetWithText(Cards, 'Filled'), findsOneWidget);
expect(find.widgetWithText(Card, 'Outlined'), findsOneWidget); expect(find.widgetWithText(Cards, 'Outlined'), findsOneWidget);
// TextFields // TextFields
expect(find.widgetWithText(TextField, 'Disabled'), findsNWidgets(2)); expect(find.widgetWithText(TextField, 'Disabled'), findsNWidgets(2));
@ -76,68 +77,57 @@ void main() {
}); });
testWidgets( testWidgets(
'NavigationRail doesn\'t show when width value is small than 450 ' 'NavigationRail doesn\'t show when width value is small than 1000 '
'(in Portrait mode or narrow screen)', (tester) async { '(in Portrait mode or narrow screen)', (tester) async {
widgetSetup(tester, 449); widgetSetup(tester, 999, windowHeight: 7000);
await tester.pumpWidget(const Material3Demo()); await tester.pumpWidget(const MaterialApp(home: Material3Demo()));
await tester.pumpAndSettle();
// When screen width is less than 450, NavigationBar will show. At the same // When screen width is less than 1000, NavigationBar will show. At the same
// time, the NavigationRail and the NavigationBar example will NOT show. // time, the NavigationBar example still show up in the navigation group.
expect(find.byType(NavigationBars), findsOneWidget); expect(find.byType(NavigationBars),
findsNWidgets(3)); // The real navBar, badges example and navBar example
expect(find.widgetWithText(NavigationBar, 'Components'), findsOneWidget); expect(find.widgetWithText(NavigationBar, 'Components'), findsOneWidget);
expect(find.widgetWithText(NavigationBar, 'Color'), findsOneWidget); expect(find.widgetWithText(NavigationBar, 'Color'), findsOneWidget);
expect(find.widgetWithText(NavigationBar, 'Typography'), findsOneWidget); expect(find.widgetWithText(NavigationBar, 'Typography'), findsOneWidget);
expect(find.widgetWithText(NavigationBar, 'Elevation'), findsOneWidget); expect(find.widgetWithText(NavigationBar, 'Elevation'), findsOneWidget);
expect(find.byType(NavigationRailSection), findsNothing); expect(find.widgetWithText(NavigationBar, 'Explore'), findsOneWidget);
expect(find.widgetWithText(NavigationBar, 'Explore'), findsNothing); expect(find.widgetWithText(NavigationBar, 'Pets'), findsOneWidget);
expect(find.widgetWithText(NavigationBar, 'Pets'), findsNothing); expect(find.widgetWithText(NavigationBar, 'Account'), findsOneWidget);
expect(find.widgetWithText(NavigationBar, 'Account'), findsNothing);
}); });
testWidgets( testWidgets(
'NavigationRail shows when width value is greater than or equal ' 'NavigationRail shows when width value is greater than or equal '
'to 450 (in Landscape mode or wider screen)', (tester) async { 'to 1000 (in Landscape mode or wider screen)', (tester) async {
widgetSetup(tester, 450); widgetSetup(tester, 1001, windowHeight: 3000);
await tester.pumpWidget(const Material3Demo()); await tester.pumpWidget(const MaterialApp(home: Material3Demo()));
await tester.pumpAndSettle();
// When screen width is greater than or equal to 450, NavigationRail and
// NavigationBar example will show. At the same time, the NavigationBar // When screen width is greater than or equal to 1000, NavigationRail will show.
// will NOT show. // At the same time, the NavigationBar will NOT show.
expect(find.byType(NavigationRailSection), findsOneWidget); expect(find.byType(NavigationRail), findsOneWidget);
expect(find.byType(Tooltip, skipOffstage: false), findsWidgets); expect(find.byType(Tooltip, skipOffstage: false), findsWidgets);
expect(find.widgetWithText(NavigationRailSection, 'Components'), expect(find.widgetWithText(NavigationRail, 'Components'), findsOneWidget);
findsOneWidget); expect(find.widgetWithText(NavigationRail, 'Color'), findsOneWidget);
expect(find.widgetWithText(NavigationRailSection, 'Color'), findsOneWidget); expect(find.widgetWithText(NavigationRail, 'Typography'), findsOneWidget);
expect(find.widgetWithText(NavigationRailSection, 'Typography'), expect(find.widgetWithText(NavigationRail, 'Elevation'), findsOneWidget);
findsOneWidget);
expect(find.widgetWithText(NavigationRailSection, 'Elevation'),
findsOneWidget);
final navbarExample = find.byType(NavigationBars);
await tester.scrollUntilVisible(
scrollable: find.byType(Scrollable).first,
navbarExample,
500.0,
);
expect(find.byType(NavigationBars), findsOneWidget);
expect(find.widgetWithText(NavigationBar, 'Explore'), findsOneWidget); expect(find.widgetWithText(NavigationBar, 'Explore'), findsOneWidget);
expect(find.widgetWithText(NavigationBar, 'Pets'), findsOneWidget); expect(find.widgetWithText(NavigationBar, 'Pets'), findsOneWidget);
expect(find.widgetWithText(NavigationBar, 'Account'), findsOneWidget); expect(find.widgetWithText(NavigationBar, 'Account'), findsOneWidget);
expect(find.widgetWithText(NavigationBar, 'Components'), findsNothing); // the Navigation bar should be out of screen.
expect(find.widgetWithText(NavigationBar, 'Colors'), findsNothing); final RenderBox box =
expect(find.widgetWithText(NavigationBar, 'Typography'), findsNothing); tester.renderObject(find.widgetWithText(NavigationBar, 'Components'));
expect(find.widgetWithText(NavigationBar, 'Elevation'), findsNothing); expect(box.localToGlobal(Offset.zero), const Offset(0.0, 3080.0));
}); });
testWidgets( testWidgets(
'Material version switches between Material3 and Material2 when' 'Material version switches between Material3 and Material2 when'
'the version icon is clicked', (tester) async { 'the version icon is clicked', (tester) async {
widgetSetup(tester, 450, windowHeight: 3000); widgetSetup(tester, 450, windowHeight: 7000);
await tester.pumpWidget(const Material3Demo()); await tester.pumpWidget(const MaterialApp(home: Material3Demo()));
Finder m3Icon = find.widgetWithIcon(IconButton, Icons.filter_3);
Finder m2Icon = find.widgetWithIcon(IconButton, Icons.filter_2);
BuildContext defaultElevatedButton = BuildContext defaultElevatedButton =
tester.firstElement(find.byType(ElevatedButton)); tester.firstElement(find.byType(ElevatedButton));
BuildContext defaultIconButton = BuildContext defaultIconButton =
@ -157,8 +147,8 @@ void main() {
await tester.tap(dismiss); await tester.tap(dismiss);
await tester.pumpAndSettle(const Duration(microseconds: 500)); await tester.pumpAndSettle(const Duration(microseconds: 500));
expect(m3Icon, findsOneWidget); expect(find.widgetWithIcon(AppBar, Icons.filter_3), findsOneWidget);
expect(m2Icon, findsNothing); expect(find.widgetWithIcon(AppBar, Icons.filter_2), findsNothing);
expect(find.text('Material 3'), findsOneWidget); expect(find.text('Material 3'), findsOneWidget);
expect(Theme.of(defaultElevatedButton).useMaterial3, true); expect(Theme.of(defaultElevatedButton).useMaterial3, true);
expect(Theme.of(defaultIconButton).useMaterial3, true); expect(Theme.of(defaultIconButton).useMaterial3, true);
@ -166,7 +156,10 @@ void main() {
expect(Theme.of(defaultCard).useMaterial3, true); expect(Theme.of(defaultCard).useMaterial3, true);
expect(Theme.of(defaultChip).useMaterial3, true); expect(Theme.of(defaultChip).useMaterial3, true);
await tester.tap(m3Icon); Finder appbarM3Icon = find.descendant(
of: find.byType(AppBar),
matching: find.widgetWithIcon(IconButton, Icons.filter_3));
await tester.tap(appbarM3Icon);
await tester.pumpAndSettle(const Duration(microseconds: 500)); await tester.pumpAndSettle(const Duration(microseconds: 500));
BuildContext updatedElevatedButton = BuildContext updatedElevatedButton =
tester.firstElement(find.byType(ElevatedButton)); tester.firstElement(find.byType(ElevatedButton));
@ -187,8 +180,8 @@ void main() {
await tester.tap(updatedDismiss); await tester.tap(updatedDismiss);
await tester.pumpAndSettle(const Duration(microseconds: 500)); await tester.pumpAndSettle(const Duration(microseconds: 500));
expect(m3Icon, findsNothing); expect(find.widgetWithIcon(AppBar, Icons.filter_2), findsOneWidget);
expect(m2Icon, findsOneWidget); expect(find.widgetWithIcon(AppBar, Icons.filter_3), findsNothing);
expect(find.text('Material 2'), findsOneWidget); expect(find.text('Material 2'), findsOneWidget);
expect(Theme.of(updatedElevatedButton).useMaterial3, false); expect(Theme.of(updatedElevatedButton).useMaterial3, false);
expect(Theme.of(updatedIconButton).useMaterial3, false); expect(Theme.of(updatedIconButton).useMaterial3, false);
@ -200,17 +193,32 @@ void main() {
testWidgets( testWidgets(
'Other screens become Material2 mode after changing mode from ' 'Other screens become Material2 mode after changing mode from '
'main screen', (tester) async { 'main screen', (tester) async {
await tester.pumpWidget(const Material3Demo()); await tester.pumpWidget(const MaterialApp(home: Material3Demo()));
await tester.tap(find.widgetWithIcon(IconButton, Icons.filter_3)); Finder appbarM3Icon = find.descendant(
await tester.tap(find.byIcon(Icons.format_paint_outlined)); of: find.byType(AppBar),
matching: find.widgetWithIcon(IconButton, Icons.filter_3));
await tester.tap(appbarM3Icon);
Finder secondScreenIcon = find.descendant(
of: find.byType(NavigationBar),
matching: find.widgetWithIcon(
NavigationDestination, Icons.format_paint_outlined));
await tester.tap(secondScreenIcon);
await tester.pumpAndSettle(const Duration(microseconds: 500)); await tester.pumpAndSettle(const Duration(microseconds: 500));
BuildContext lightThemeText = tester.element(find.text('Light Theme')); BuildContext lightThemeText = tester.element(find.text('Light Theme'));
expect(Theme.of(lightThemeText).useMaterial3, false); expect(Theme.of(lightThemeText).useMaterial3, false);
await tester.tap(find.byIcon(Icons.text_snippet_outlined)); Finder thirdScreenIcon = find.descendant(
of: find.byType(NavigationBar),
matching: find.widgetWithIcon(
NavigationDestination, Icons.text_snippet_outlined));
await tester.tap(thirdScreenIcon);
await tester.pumpAndSettle(const Duration(microseconds: 500)); await tester.pumpAndSettle(const Duration(microseconds: 500));
BuildContext displayLargeText = tester.element(find.text('Display Large')); BuildContext displayLargeText = tester.element(find.text('Display Large'));
expect(Theme.of(displayLargeText).useMaterial3, false); expect(Theme.of(displayLargeText).useMaterial3, false);
await tester.tap(find.byIcon(Icons.invert_colors_on_outlined)); Finder fourthScreenIcon = find.descendant(
of: find.byType(NavigationBar),
matching: find.widgetWithIcon(
NavigationDestination, Icons.invert_colors_on_outlined));
await tester.tap(fourthScreenIcon);
await tester.pumpAndSettle(const Duration(microseconds: 500)); await tester.pumpAndSettle(const Duration(microseconds: 500));
BuildContext material = tester.firstElement(find.byType(Material)); BuildContext material = tester.firstElement(find.byType(Material));
expect(Theme.of(material).useMaterial3, false); expect(Theme.of(material).useMaterial3, false);
@ -219,12 +227,17 @@ void main() {
testWidgets( testWidgets(
'Brightness mode switches between dark and light when' 'Brightness mode switches between dark and light when'
'the brightness icon is clicked', (tester) async { 'the brightness icon is clicked', (tester) async {
await tester.pumpWidget(const Material3Demo()); await tester.pumpWidget(const MaterialApp(home: Material3Demo()));
Finder lightIcon = find.widgetWithIcon(IconButton, Icons.wb_sunny_outlined); Finder lightIcon = find.descendant(
Finder darkIcon = find.widgetWithIcon(IconButton, Icons.wb_sunny); of: find.byType(AppBar),
BuildContext appBar = tester.element(find.byType(AppBar)); matching: find.widgetWithIcon(IconButton, Icons.wb_sunny_outlined));
BuildContext body = tester.element(find.byType(Scaffold)); Finder darkIcon = find.descendant(
BuildContext navigationRail = tester.element(find.byType(NavigationRail)); of: find.byType(AppBar),
matching: find.widgetWithIcon(IconButton, Icons.wb_sunny));
BuildContext appBar = tester.element(find.byType(AppBar).first);
BuildContext body = tester.firstElement(find.byType(Scaffold).first);
BuildContext navigationRail = tester.element(
find.widgetWithIcon(NavigationRail, Icons.format_paint_outlined));
expect(lightIcon, findsOneWidget); expect(lightIcon, findsOneWidget);
expect(darkIcon, findsNothing); expect(darkIcon, findsNothing);
expect(Theme.of(appBar).brightness, Brightness.light); expect(Theme.of(appBar).brightness, Brightness.light);
@ -233,8 +246,8 @@ void main() {
await tester.tap(lightIcon); await tester.tap(lightIcon);
await tester.pumpAndSettle(const Duration(microseconds: 500)); await tester.pumpAndSettle(const Duration(microseconds: 500));
BuildContext appBar2 = tester.element(find.byType(AppBar)); BuildContext appBar2 = tester.element(find.byType(AppBar).first);
BuildContext body2 = tester.element(find.byType(Scaffold)); BuildContext body2 = tester.element(find.byType(Scaffold).first);
BuildContext navigationRail2 = tester.element(find.byType(NavigationRail)); BuildContext navigationRail2 = tester.element(find.byType(NavigationRail));
expect(lightIcon, findsNothing); expect(lightIcon, findsNothing);
expect(darkIcon, findsOneWidget); expect(darkIcon, findsOneWidget);
@ -245,10 +258,15 @@ void main() {
testWidgets('Color theme changes when a color is selected from menu', testWidgets('Color theme changes when a color is selected from menu',
(tester) async { (tester) async {
await tester.pumpWidget(const Material3Demo()); Color m3BaseColor = const Color(0xff6750a4);
Finder menuIcon = find.widgetWithIcon(IconButton, Icons.more_vert); await tester.pumpWidget(Container());
BuildContext appBar = tester.element(find.byType(AppBar)); await tester.pumpWidget(const MaterialApp(home: Material3Demo()));
BuildContext body = tester.element(find.byType(Scaffold)); await tester.pump();
Finder menuIcon = find.descendant(
of: find.byType(AppBar),
matching: find.widgetWithIcon(IconButton, Icons.more_vert));
BuildContext appBar = tester.element(find.byType(AppBar).first);
BuildContext body = tester.element(find.byType(Scaffold).first);
BuildContext navigationRail = tester.element(find.byType(NavigationRail)); BuildContext navigationRail = tester.element(find.byType(NavigationRail));
expect(Theme.of(appBar).primaryColor, m3BaseColor); expect(Theme.of(appBar).primaryColor, m3BaseColor);
@ -256,11 +274,11 @@ void main() {
expect(Theme.of(navigationRail).primaryColor, m3BaseColor); expect(Theme.of(navigationRail).primaryColor, m3BaseColor);
await tester.tap(menuIcon); await tester.tap(menuIcon);
await tester.pumpAndSettle(); await tester.pumpAndSettle();
await tester.tap(find.text('Blue')); await tester.tap(find.text('Blue').last);
await tester.pumpAndSettle(); await tester.pumpAndSettle();
BuildContext appBar2 = tester.element(find.byType(AppBar)); BuildContext appBar2 = tester.element(find.byType(AppBar).first);
BuildContext body2 = tester.element(find.byType(Scaffold)); BuildContext body2 = tester.element(find.byType(Scaffold).first);
BuildContext navigationRail2 = tester.element(find.byType(NavigationRail)); BuildContext navigationRail2 = tester.element(find.byType(NavigationRail));
ThemeData expectedTheme = ThemeData(colorSchemeSeed: Colors.blue); ThemeData expectedTheme = ThemeData(colorSchemeSeed: Colors.blue);
expect(Theme.of(appBar2).primaryColor, expectedTheme.primaryColor); expect(Theme.of(appBar2).primaryColor, expectedTheme.primaryColor);

@ -16,43 +16,54 @@ void main() {
'selected on NavigationBar', (tester) async { 'selected on NavigationBar', (tester) async {
widgetSetup(tester, 449); widgetSetup(tester, 449);
addTearDown(tester.binding.window.clearPhysicalSizeTestValue); addTearDown(tester.binding.window.clearPhysicalSizeTestValue);
await tester.pumpWidget(const Material3Demo()); await tester.pumpWidget(const MaterialApp(home: Material3Demo()));
expect(find.text('Surface Tint only'), findsNothing); expect(find.text('Surface Tint Color Only'), findsNothing);
expect(find.byType(NavigationBar), findsOneWidget); expect(find.byType(NavigationBar), findsOneWidget);
Finder tintIconOnBar = find.byIcon(Icons.invert_colors_on_outlined); Finder tintIconOnBar = find.descendant(
of: find.byType(NavigationBar),
matching: find.widgetWithIcon(
NavigationDestination, Icons.invert_colors_on_outlined));
expect(tintIconOnBar, findsOneWidget); expect(tintIconOnBar, findsOneWidget);
await tester.tap(tintIconOnBar); await tester.tap(tintIconOnBar);
await tester.pumpAndSettle(const Duration(microseconds: 500)); await tester.pumpAndSettle(const Duration(microseconds: 500));
expect(tintIconOnBar, findsNothing); expect(tintIconOnBar, findsNothing);
expect(find.byIcon(Icons.opacity), findsOneWidget); Finder selectedTintIconOnBar = find.descendant(
expect(find.text('Surface Tint only'), findsOneWidget); of: find.byType(NavigationBar),
matching: find.widgetWithIcon(NavigationDestination, Icons.opacity));
expect(selectedTintIconOnBar, findsOneWidget);
expect(find.text('Surface Tint Color Only'), findsOneWidget);
}); });
testWidgets( testWidgets(
'Surface Tones screen shows correctly when the corresponding icon is ' 'Surface Tones screen shows correctly when the corresponding icon is '
'selected on NavigationRail', (tester) async { 'selected on NavigationRail', (tester) async {
widgetSetup(tester, 450); // NavigationRail shows only when width is >= 450. widgetSetup(
tester, 1200); // NavigationRail shows only when width is > 1000.
addTearDown(tester.binding.window.clearPhysicalSizeTestValue); addTearDown(tester.binding.window.clearPhysicalSizeTestValue);
await tester.pumpWidget(const Material3Demo()); await tester.pumpWidget(const MaterialApp(home: Material3Demo()));
expect(find.text('Surface Tint only'), findsNothing); expect(find.text('Surface Tint Color Only'), findsNothing);
expect(find.byType(NavigationRail), findsOneWidget); expect(find.byType(NavigationRail), findsOneWidget);
Finder tintIconOnRail = find.byIcon(Icons.invert_colors_on_outlined); Finder tintIconOnRail = find.descendant(
of: find.byType(NavigationRail),
matching: find.byIcon(Icons.invert_colors_on_outlined));
expect(tintIconOnRail, findsOneWidget); expect(tintIconOnRail, findsOneWidget);
await tester.tap(tintIconOnRail); await tester.tap(tintIconOnRail);
await tester.pumpAndSettle(const Duration(microseconds: 500)); await tester.pumpAndSettle(const Duration(microseconds: 500));
expect(tintIconOnRail, findsNothing); expect(tintIconOnRail, findsNothing);
expect(find.byIcon(Icons.opacity), findsOneWidget); Finder selectedTintIconOnRail = find.descendant(
expect(find.text('Surface Tint only'), findsOneWidget); of: find.byType(NavigationRail), matching: find.byIcon(Icons.opacity));
expect(selectedTintIconOnRail, findsOneWidget);
expect(find.text('Surface Tint Color Only'), findsOneWidget);
}); });
testWidgets('Surface Tones screen shows correct content', (tester) async { testWidgets('Surface Tones screen shows correct content', (tester) async {
await tester.pumpWidget(MaterialApp( await tester.pumpWidget(MaterialApp(
home: Scaffold(body: Row(children: const [ElevationScreen()])), home: Scaffold(body: Row(children: const [ElevationScreen()])),
)); ));
expect(find.text('Surface Tint only'), findsOneWidget); expect(find.text('Surface Tint Color Only'), findsOneWidget);
expect(find.text('Surface Tint and Shadow'), findsOneWidget); expect(find.text('Surface Tint Color and Shadow Color'), findsOneWidget);
expect(find.text('Shadow only'), findsOneWidget); expect(find.text('Shadow Color Only'), findsOneWidget);
expect(find.byType(ElevationGrid), findsNWidgets(3)); expect(find.byType(ElevationGrid), findsNWidgets(3));
expect(find.byType(ElevationCard), findsNWidgets(18)); expect(find.byType(ElevationCard), findsNWidgets(18));
}); });

@ -16,33 +16,44 @@ void main() {
'selected on NavigationBar', (tester) async { 'selected on NavigationBar', (tester) async {
widgetSetup(tester, 449); widgetSetup(tester, 449);
addTearDown(tester.binding.window.clearPhysicalSizeTestValue); addTearDown(tester.binding.window.clearPhysicalSizeTestValue);
await tester.pumpWidget(const Material3Demo()); await tester.pumpWidget(const MaterialApp(home: Material3Demo()));
expect(find.text('Display Large'), findsNothing); expect(find.text('Display Large'), findsNothing);
expect(find.byType(NavigationBar), findsOneWidget); expect(find.byType(NavigationBar), findsOneWidget);
Finder textIconOnBar = find.byIcon(Icons.text_snippet_outlined); Finder textIconOnBar = find.descendant(
of: find.byType(NavigationBar),
matching: find.byIcon(Icons.text_snippet_outlined));
expect(textIconOnBar, findsOneWidget); expect(textIconOnBar, findsOneWidget);
await tester.tap(textIconOnBar); await tester.tap(textIconOnBar);
await tester.pumpAndSettle(const Duration(microseconds: 500)); await tester.pumpAndSettle(const Duration(microseconds: 500));
expect(textIconOnBar, findsNothing); expect(textIconOnBar, findsNothing);
expect(find.byIcon(Icons.text_snippet), findsOneWidget); Finder selectedTextIconOnBar = find.descendant(
of: find.byType(NavigationBar),
matching: find.byIcon(Icons.text_snippet));
expect(selectedTextIconOnBar, findsOneWidget);
expect(find.text('Display Large'), findsOneWidget); expect(find.text('Display Large'), findsOneWidget);
}); });
testWidgets( testWidgets(
'Typography screen shows correctly when the corresponding icon is ' 'Typography screen shows correctly when the corresponding icon is '
'selected on NavigationRail', (tester) async { 'selected on NavigationRail', (tester) async {
widgetSetup(tester, 450); // NavigationRail shows only when width is >= 450. widgetSetup(
tester, 1200); // NavigationRail shows only when width is > 1000.
addTearDown(tester.binding.window.clearPhysicalSizeTestValue); addTearDown(tester.binding.window.clearPhysicalSizeTestValue);
await tester.pumpWidget(const Material3Demo()); await tester.pumpWidget(const MaterialApp(home: Material3Demo()));
expect(find.text('Display Large'), findsNothing); expect(find.text('Display Large'), findsNothing);
expect(find.byType(NavigationRail), findsOneWidget); expect(find.byType(NavigationRail), findsOneWidget);
Finder textIconOnRail = find.byIcon(Icons.text_snippet_outlined); Finder textIconOnRail = find.descendant(
of: find.byType(NavigationRail),
matching: find.byIcon(Icons.text_snippet_outlined));
expect(textIconOnRail, findsOneWidget); expect(textIconOnRail, findsOneWidget);
await tester.tap(textIconOnRail); await tester.tap(textIconOnRail);
await tester.pumpAndSettle(const Duration(microseconds: 500)); await tester.pumpAndSettle(const Duration(microseconds: 500));
expect(textIconOnRail, findsNothing); expect(textIconOnRail, findsNothing);
expect(find.byIcon(Icons.text_snippet), findsOneWidget); Finder selectedTextIconOnRail = find.descendant(
of: find.byType(NavigationRail),
matching: find.byIcon(Icons.text_snippet));
expect(selectedTextIconOnRail, findsOneWidget);
expect(find.text('Display Large'), findsOneWidget); expect(find.text('Display Large'), findsOneWidget);
}); });

Loading…
Cancel
Save