mirror of
https://github.com/flutter/samples.git
synced 2025-11-08 13:58:47 +00:00
Flutter 3.7.0 (#1556)
* Update `simplistic_editor` for Flutter 3.4 beta * Re-enable beta and master CI * Disable on master * Added sample code for using plugins and channels from background isolates. * goderbauer feedback 1 * goderbauer feedback2 * goderbauer feedback 3 * Add `background_isolate_channels` to CI * Enable beta CI * Enable all `stable` CI projects * `dart fix --apply` * `print` -> `denugPrint` * Make deps min version not pinned * Drop `_isDebug` * Remove unused import * `dart format` * Fixup `linting_tool` * Fixup `form_app` * Enable all `master` CI * Basic fixes * Patch `simplistic_editor` * Fix nl at eol * Comment out `simplistic_editor` * Incorporating @bleroux's latest changes * Clean up CI scripts * Copy `experimental/material_3_demo` to top level * Update `game_template` * Update `animations` * Update `desktop_photo_search` * Update `flutter_maps_firestore` * Update `form_app` * Update `infinite_list` * Update `isolate_example` * Update `jsonexample` * Update `navigation_and_routing` * Update `place_tracker` * Update `platform_channels` * Update `platform_design` * Update `provider_shopper` * Fixup `context_menus` * `dart format` * Update the main `material_3_demo` * Make `tool/flutter_ci_script_stable.sh` executable again Co-authored-by: Bruno Leroux <bruno.leroux@gmail.com> Co-authored-by: Aaron Clarke <aaclarke@google.com>
This commit is contained in:
@@ -2,9 +2,12 @@
|
||||
|
||||
This sample Flutter app showcases Material 3 features in the Flutter Material library. These features include updated components, typography, color system and elevation support. The app supports light and dark themes, different color palettes, as well as the ability to switch between Material 2 and Material 3. For more information about Material 3, the guidance is now live at https://m3.material.io/.
|
||||
|
||||
This app also includes new M3 components such as IconButtons, Chips, TextFields, Switches, Checkboxes, Radio buttons and ProgressIndicators.
|
||||
|
||||
# Preview
|
||||
|
||||
https://user-images.githubusercontent.com/36861262/166358511-43d6a30b-33fe-4680-a4d1-808f087e740e.mp4
|
||||
<img width="400" alt="Screen Shot 2022-08-12 at 12 00 28 PM" src="https://user-images.githubusercontent.com/36861262/184426137-47b550e1-5c6e-4bb7-b647-b1741f96d42b.png"><img width="400" alt="Screen Shot 2022-08-12 at 12 00 38 PM" src="https://user-images.githubusercontent.com/36861262/184426154-063a39e8-24bd-40be-90cd-984bf81c0fdf.png">
|
||||
|
||||
|
||||
# Features
|
||||
## Icon Buttons on the Top App Bar
|
||||
@@ -13,9 +16,9 @@ https://user-images.githubusercontent.com/36861262/166358511-43d6a30b-33fe-4680-
|
||||
<img src="https://user-images.githubusercontent.com/36861262/166508002-90fce980-d228-4312-a95f-a1919bb79ccc.png" width="25" /> Users can switch between Material 2 and Material 3 for the displayed components with this button.
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/36861262/166511137-85dea8df-0017-4649-b913-14d4b7a17c2f.png" width="25" /> This button will bring up a pop-up menu that allows the user to change the base color used for the light and dark themes. This uses a new color seed feature to generate entire color schemes from a single color.
|
||||
|
||||
|
||||
## Component Screen
|
||||
The default screen displays all the updated components in Material 3: AppBar, common Buttons, Floating Action Button(FAB), Card, Dialog, NavigationBar, and NavigationRail.
|
||||
The default screen displays all the updated components in Material 3: AppBar, common Buttons, Floating Action Button(FAB), Chips, Card, Checkbox, Dialog, NavigationBar, NavigationRail, ProgressIndicators, Radio buttons, TextFields and Switch.
|
||||
|
||||
### Adaptive Layout
|
||||
Based on the fact that NavigationRail is not recommended on a small screen, the app changes its layout based on the screen width. If it's played on iOS or Android devices which have a narrow screen, a Navigation Bar will show at the bottom and will be used to navigate. But if it's played as a desktop or a web app, a Navigation Rail will show on the left side and at the same time, a Navigation Bar will show as an example but will not have any functionality.
|
||||
@@ -30,5 +33,3 @@ The Typography Screen displays the text styles used in for the default TextTheme
|
||||
|
||||
## Elevation Screen
|
||||
The Elevation screen shows different ways of elevation with a new supported feature "surfaceTintColor" in the Material library.
|
||||
|
||||
|
||||
|
||||
@@ -17,10 +17,14 @@ class ColorPalettesScreen extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Color selectedColor = Theme.of(context).primaryColor;
|
||||
ThemeData lightTheme =
|
||||
ThemeData(colorSchemeSeed: selectedColor, brightness: Brightness.light);
|
||||
ThemeData darkTheme =
|
||||
ThemeData(colorSchemeSeed: selectedColor, brightness: Brightness.dark);
|
||||
ThemeData lightTheme = ThemeData(
|
||||
colorSchemeSeed: selectedColor,
|
||||
brightness: Brightness.light,
|
||||
);
|
||||
ThemeData darkTheme = ThemeData(
|
||||
colorSchemeSeed: selectedColor,
|
||||
brightness: Brightness.dark,
|
||||
);
|
||||
|
||||
Widget schemeLabel(String brightness) {
|
||||
return Padding(
|
||||
@@ -48,12 +52,12 @@ class ColorPalettesScreen extends StatelessWidget {
|
||||
child: Column(
|
||||
children: [
|
||||
divider,
|
||||
schemeLabel("Light Theme"),
|
||||
schemeLabel('Light Theme'),
|
||||
schemeView(lightTheme),
|
||||
divider,
|
||||
divider,
|
||||
schemeLabel("Dark Theme"),
|
||||
schemeView(darkTheme)
|
||||
schemeLabel('Dark Theme'),
|
||||
schemeView(darkTheme),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -66,19 +70,19 @@ class ColorPalettesScreen extends StatelessWidget {
|
||||
Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
schemeLabel("Light Theme"),
|
||||
schemeView(lightTheme)
|
||||
schemeLabel('Light Theme'),
|
||||
schemeView(lightTheme),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
schemeLabel("Dark Theme"),
|
||||
schemeView(darkTheme)
|
||||
schemeLabel('Dark Theme'),
|
||||
schemeView(darkTheme),
|
||||
],
|
||||
),
|
||||
)
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -100,46 +104,46 @@ class ColorSchemeView extends StatelessWidget {
|
||||
children: [
|
||||
ColorGroup(children: [
|
||||
ColorChip(
|
||||
label: "primary",
|
||||
label: 'primary',
|
||||
color: colorScheme.primary,
|
||||
onColor: colorScheme.onPrimary,
|
||||
),
|
||||
ColorChip(
|
||||
label: "onPrimary",
|
||||
label: 'onPrimary',
|
||||
color: colorScheme.onPrimary,
|
||||
onColor: colorScheme.primary),
|
||||
ColorChip(
|
||||
label: "primaryContainer",
|
||||
label: 'primaryContainer',
|
||||
color: colorScheme.primaryContainer,
|
||||
onColor: colorScheme.onPrimaryContainer,
|
||||
),
|
||||
ColorChip(
|
||||
label: "onPrimaryContainer",
|
||||
label: 'onPrimaryContainer',
|
||||
color: colorScheme.onPrimaryContainer,
|
||||
onColor: colorScheme.primaryContainer,
|
||||
)
|
||||
),
|
||||
]),
|
||||
divider,
|
||||
ColorGroup(children: [
|
||||
ColorChip(
|
||||
label: "secondary",
|
||||
label: 'secondary',
|
||||
color: colorScheme.secondary,
|
||||
onColor: colorScheme.onSecondary,
|
||||
),
|
||||
ColorChip(
|
||||
label: "onSecondary",
|
||||
label: 'onSecondary',
|
||||
color: colorScheme.onSecondary,
|
||||
onColor: colorScheme.secondary,
|
||||
),
|
||||
ColorChip(
|
||||
label: "secondaryContainer",
|
||||
label: 'secondaryContainer',
|
||||
color: colorScheme.secondaryContainer,
|
||||
onColor: colorScheme.onSecondaryContainer,
|
||||
),
|
||||
ColorChip(
|
||||
label: "onSecondaryContainer",
|
||||
label: 'onSecondaryContainer',
|
||||
color: colorScheme.onSecondaryContainer,
|
||||
onColor: colorScheme.secondaryContainer)
|
||||
onColor: colorScheme.secondaryContainer),
|
||||
]),
|
||||
divider,
|
||||
ColorGroup(
|
||||
@@ -248,10 +252,12 @@ class ColorGroup extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Card(
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: Column(
|
||||
children: children,
|
||||
return RepaintBoundary(
|
||||
child: Card(
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: Column(
|
||||
children: children,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,37 +12,47 @@ class ElevationScreen extends StatelessWidget {
|
||||
Color shadowColor = Theme.of(context).colorScheme.shadow;
|
||||
Color surfaceTint = Theme.of(context).colorScheme.primary;
|
||||
return Expanded(
|
||||
child: ListView(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16.0, 20, 16.0, 0),
|
||||
child: Text(
|
||||
'Surface Tint only',
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16.0, 20, 16.0, 0),
|
||||
child: Text(
|
||||
'Surface Tint Color Only',
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
),
|
||||
),
|
||||
ElevationGrid(surfaceTintColor: surfaceTint),
|
||||
const SizedBox(height: 10),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 0),
|
||||
child: Text(
|
||||
'Surface Tint and Shadow',
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
SliverList(
|
||||
delegate: SliverChildListDelegate(<Widget>[
|
||||
const SizedBox(height: 10),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 0),
|
||||
child: Text(
|
||||
'Surface Tint Color and Shadow Color',
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
),
|
||||
]),
|
||||
),
|
||||
ElevationGrid(
|
||||
shadowColor: shadowColor,
|
||||
surfaceTintColor: surfaceTint,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 0),
|
||||
child: Text(
|
||||
'Shadow only',
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
SliverList(
|
||||
delegate: SliverChildListDelegate(<Widget>[
|
||||
const SizedBox(height: 10),
|
||||
Padding(
|
||||
padding: const EdgeInsets.fromLTRB(16.0, 8.0, 16.0, 0),
|
||||
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
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
return SliverPadding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: LayoutBuilder(builder: (context, constraints) {
|
||||
if (constraints.maxWidth < narrowScreenWidthThreshold) {
|
||||
return GridView.count(
|
||||
shrinkWrap: true,
|
||||
sliver: SliverLayoutBuilder(builder: (context, constraints) {
|
||||
if (constraints.crossAxisExtent < narrowScreenWidthThreshold) {
|
||||
return SliverGrid.count(
|
||||
crossAxisCount: 3,
|
||||
children: elevationCards(shadowColor, surfaceTintColor),
|
||||
);
|
||||
} else {
|
||||
return GridView.count(
|
||||
shrinkWrap: true,
|
||||
return SliverGrid.count(
|
||||
crossAxisCount: 6,
|
||||
children: elevationCards(shadowColor, surfaceTintColor),
|
||||
);
|
||||
@@ -117,7 +125,6 @@ class _ElevationCardState extends State<ElevationCard> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
const BorderRadius borderRadius = BorderRadius.all(Radius.circular(4.0));
|
||||
final bool showOpacity = _elevation == widget.info.elevation;
|
||||
final Color color = Theme.of(context).colorScheme.surface;
|
||||
|
||||
return Padding(
|
||||
@@ -142,7 +149,7 @@ class _ElevationCardState extends State<ElevationCard> {
|
||||
'${widget.info.level.toInt()} dp',
|
||||
style: Theme.of(context).textTheme.labelMedium,
|
||||
),
|
||||
if (showOpacity)
|
||||
if (widget.surfaceTint != null)
|
||||
Expanded(
|
||||
child: Align(
|
||||
alignment: Alignment.bottomRight,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
|
||||
import 'color_palettes_screen.dart';
|
||||
import 'component_screen.dart';
|
||||
@@ -10,7 +11,12 @@ import 'elevation_screen.dart';
|
||||
import 'typography_screen.dart';
|
||||
|
||||
void main() {
|
||||
runApp(const Material3Demo());
|
||||
runApp(
|
||||
const MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
home: Material3Demo(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
class Material3Demo extends StatefulWidget {
|
||||
@@ -24,180 +30,708 @@ class Material3Demo extends StatefulWidget {
|
||||
// screenWidthThreshold; otherwise, NavigationBar is used for navigation.
|
||||
const double narrowScreenWidthThreshold = 450;
|
||||
|
||||
const Color m3BaseColor = Color(0xff6750a4);
|
||||
const List<Color> colorOptions = [
|
||||
m3BaseColor,
|
||||
Colors.blue,
|
||||
Colors.teal,
|
||||
Colors.green,
|
||||
Colors.yellow,
|
||||
Colors.orange,
|
||||
Colors.pink
|
||||
];
|
||||
const List<String> colorText = <String>[
|
||||
"M3 Baseline",
|
||||
"Blue",
|
||||
"Teal",
|
||||
"Green",
|
||||
"Yellow",
|
||||
"Orange",
|
||||
"Pink",
|
||||
];
|
||||
const double transitionLength = 500;
|
||||
|
||||
class _Material3DemoState extends State<Material3Demo> {
|
||||
enum ColorSeed {
|
||||
baseColor('M3 Baseline', Color(0xff6750a4)),
|
||||
indigo('Indigo', Colors.indigo),
|
||||
blue('Blue', Colors.blue),
|
||||
teal('Teal', Colors.teal),
|
||||
green('Green', Colors.green),
|
||||
yellow('Yellow', Colors.yellow),
|
||||
orange('Orange', Colors.orange),
|
||||
deepOrange('Deep Orange', Colors.deepOrange),
|
||||
pink('Pink', Colors.pink);
|
||||
|
||||
const ColorSeed(this.label, this.color);
|
||||
final String label;
|
||||
final Color color;
|
||||
}
|
||||
|
||||
enum ScreenSelected {
|
||||
component(0),
|
||||
color(1),
|
||||
typography(2),
|
||||
elevation(3);
|
||||
|
||||
const ScreenSelected(this.value);
|
||||
final int value;
|
||||
}
|
||||
|
||||
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 useLightMode = true;
|
||||
int colorSelected = 0;
|
||||
int screenIndex = 0;
|
||||
ThemeMode themeMode = ThemeMode.system;
|
||||
bool get useLightMode {
|
||||
switch (themeMode) {
|
||||
case ThemeMode.system:
|
||||
return SchedulerBinding.instance.window.platformBrightness ==
|
||||
Brightness.light;
|
||||
case ThemeMode.light:
|
||||
return true;
|
||||
case ThemeMode.dark:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
late ThemeData themeData;
|
||||
ColorSeed colorSelected = ColorSeed.baseColor;
|
||||
int screenIndex = ScreenSelected.component.value;
|
||||
|
||||
@override
|
||||
initState() {
|
||||
super.initState();
|
||||
themeData = updateThemes(colorSelected, 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),
|
||||
);
|
||||
}
|
||||
|
||||
ThemeData updateThemes(int colorIndex, bool useMaterial3, bool useLightMode) {
|
||||
return ThemeData(
|
||||
colorSchemeSeed: colorOptions[colorSelected],
|
||||
useMaterial3: useMaterial3,
|
||||
brightness: useLightMode ? Brightness.light : Brightness.dark);
|
||||
@override
|
||||
void dispose() {
|
||||
controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void handleScreenChanged(int selectedScreen) {
|
||||
@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;
|
||||
}
|
||||
}
|
||||
|
||||
void handleScreenChanged(int screenSelected) {
|
||||
setState(() {
|
||||
screenIndex = selectedScreen;
|
||||
screenIndex = screenSelected;
|
||||
});
|
||||
}
|
||||
|
||||
void handleBrightnessChange() {
|
||||
void handleBrightnessChange(bool useLightMode) {
|
||||
setState(() {
|
||||
useLightMode = !useLightMode;
|
||||
themeData = updateThemes(colorSelected, useMaterial3, useLightMode);
|
||||
themeMode = useLightMode ? ThemeMode.light : ThemeMode.dark;
|
||||
});
|
||||
}
|
||||
|
||||
void handleMaterialVersionChange() {
|
||||
setState(() {
|
||||
useMaterial3 = !useMaterial3;
|
||||
themeData = updateThemes(colorSelected, useMaterial3, useLightMode);
|
||||
});
|
||||
}
|
||||
|
||||
void handleColorSelect(int value) {
|
||||
setState(() {
|
||||
colorSelected = value;
|
||||
themeData = updateThemes(colorSelected, useMaterial3, useLightMode);
|
||||
colorSelected = ColorSeed.values[value];
|
||||
});
|
||||
}
|
||||
|
||||
Widget createScreenFor(int screenIndex, bool showNavBarExample) {
|
||||
switch (screenIndex) {
|
||||
case 0:
|
||||
return ComponentScreen(showNavBottomBar: showNavBarExample);
|
||||
case 1:
|
||||
Widget createScreenFor(
|
||||
ScreenSelected screenSelected, bool showNavBarExample) {
|
||||
switch (screenSelected) {
|
||||
case ScreenSelected.component:
|
||||
return Expanded(
|
||||
child: OneTwoTransition(
|
||||
animation: railAnimation,
|
||||
one: FirstComponentList(
|
||||
showNavBottomBar: showNavBarExample,
|
||||
scaffoldKey: scaffoldKey,
|
||||
showSecondList: showMediumSizeLayout || showLargeSizeLayout),
|
||||
two: SecondComponentList(
|
||||
scaffoldKey: scaffoldKey,
|
||||
),
|
||||
),
|
||||
);
|
||||
case ScreenSelected.color:
|
||||
return const ColorPalettesScreen();
|
||||
case 2:
|
||||
case ScreenSelected.typography:
|
||||
return const TypographyScreen();
|
||||
case 3:
|
||||
case ScreenSelected.elevation:
|
||||
return const ElevationScreen();
|
||||
default:
|
||||
return ComponentScreen(showNavBottomBar: showNavBarExample);
|
||||
return FirstComponentList(
|
||||
showNavBottomBar: showNavBarExample,
|
||||
scaffoldKey: scaffoldKey,
|
||||
showSecondList: showMediumSizeLayout || showLargeSizeLayout);
|
||||
}
|
||||
}
|
||||
|
||||
PreferredSizeWidget createAppBar() {
|
||||
return AppBar(
|
||||
title: useMaterial3 ? const Text("Material 3") : const Text("Material 2"),
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: useLightMode
|
||||
? const Icon(Icons.wb_sunny_outlined)
|
||||
: const Icon(Icons.wb_sunny),
|
||||
onPressed: handleBrightnessChange,
|
||||
tooltip: "Toggle brightness",
|
||||
),
|
||||
IconButton(
|
||||
icon: useMaterial3
|
||||
? const Icon(Icons.filter_3)
|
||||
: const Icon(Icons.filter_2),
|
||||
onPressed: handleMaterialVersionChange,
|
||||
tooltip: "Switch to Material ${useMaterial3 ? 2 : 3}",
|
||||
),
|
||||
PopupMenuButton(
|
||||
icon: const Icon(Icons.more_vert),
|
||||
shape:
|
||||
RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
||||
itemBuilder: (context) {
|
||||
return List.generate(colorOptions.length, (index) {
|
||||
return PopupMenuItem(
|
||||
value: index,
|
||||
child: Wrap(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 10),
|
||||
child: Icon(
|
||||
index == colorSelected
|
||||
? Icons.color_lens
|
||||
: Icons.color_lens_outlined,
|
||||
color: colorOptions[index],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 20),
|
||||
child: Text(colorText[index]))
|
||||
],
|
||||
));
|
||||
});
|
||||
},
|
||||
onSelected: handleColorSelect,
|
||||
),
|
||||
],
|
||||
title: useMaterial3 ? const Text('Material 3') : const Text('Material 2'),
|
||||
actions: !showMediumSizeLayout && !showLargeSizeLayout
|
||||
? [
|
||||
_BrightnessButton(
|
||||
handleBrightnessChange: handleBrightnessChange,
|
||||
),
|
||||
_Material3Button(
|
||||
handleMaterialVersionChange: handleMaterialVersionChange,
|
||||
),
|
||||
_ColorSeedButton(
|
||||
handleColorSelect: handleColorSelect,
|
||||
colorSelected: colorSelected,
|
||||
),
|
||||
]
|
||||
: [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: (value) {
|
||||
handleBrightnessChange(value);
|
||||
})
|
||||
],
|
||||
),
|
||||
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.radio_button_unchecked),
|
||||
color: ColorSeed.values[i].color,
|
||||
isSelected:
|
||||
colorSelected.color == ColorSeed.values[i].color,
|
||||
selectedIcon: const Icon(Icons.circle),
|
||||
onPressed: () {
|
||||
handleColorSelect(i);
|
||||
},
|
||||
)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
Widget _trailingActions() => Column(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Flexible(
|
||||
child: _BrightnessButton(
|
||||
handleBrightnessChange: handleBrightnessChange,
|
||||
showTooltipBelow: false,
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: _Material3Button(
|
||||
handleMaterialVersionChange: handleMaterialVersionChange,
|
||||
showTooltipBelow: false,
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: _ColorSeedButton(
|
||||
handleColorSelect: handleColorSelect,
|
||||
colorSelected: colorSelected,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
title: 'Material 3',
|
||||
themeMode: useLightMode ? ThemeMode.light : ThemeMode.dark,
|
||||
theme: themeData,
|
||||
home: LayoutBuilder(builder: (context, constraints) {
|
||||
if (constraints.maxWidth < narrowScreenWidthThreshold) {
|
||||
return Scaffold(
|
||||
themeMode: themeMode,
|
||||
theme: ThemeData(
|
||||
colorSchemeSeed: colorSelected.color,
|
||||
useMaterial3: useMaterial3,
|
||||
brightness: Brightness.light,
|
||||
),
|
||||
darkTheme: ThemeData(
|
||||
colorSchemeSeed: colorSelected.color,
|
||||
useMaterial3: useMaterial3,
|
||||
brightness: Brightness.dark,
|
||||
),
|
||||
home: AnimatedBuilder(
|
||||
animation: controller,
|
||||
builder: (context, child) {
|
||||
return NavigationTransition(
|
||||
scaffoldKey: scaffoldKey,
|
||||
animationController: controller,
|
||||
railAnimation: railAnimation,
|
||||
appBar: createAppBar(),
|
||||
body: Row(children: <Widget>[
|
||||
createScreenFor(screenIndex, false),
|
||||
]),
|
||||
bottomNavigationBar: NavigationBars(
|
||||
onSelectItem: handleScreenChanged,
|
||||
body: createScreenFor(
|
||||
ScreenSelected.values[screenIndex], controller.value == 1),
|
||||
navigationRail: NavigationRail(
|
||||
extended: showLargeSizeLayout,
|
||||
destinations: navRailDestinations,
|
||||
selectedIndex: screenIndex,
|
||||
onDestinationSelected: (index) {
|
||||
setState(() {
|
||||
screenIndex = index;
|
||||
handleScreenChanged(screenIndex);
|
||||
});
|
||||
},
|
||||
trailing: Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(bottom: 20),
|
||||
child: showLargeSizeLayout
|
||||
? _expandedTrailingActions()
|
||||
: _trailingActions(),
|
||||
),
|
||||
),
|
||||
),
|
||||
navigationBar: NavigationBars(
|
||||
onSelectItem: (index) {
|
||||
setState(() {
|
||||
screenIndex = index;
|
||||
handleScreenChanged(screenIndex);
|
||||
});
|
||||
},
|
||||
selectedIndex: screenIndex,
|
||||
isExampleBar: false,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return Scaffold(
|
||||
appBar: createAppBar(),
|
||||
body: SafeArea(
|
||||
bottom: false,
|
||||
top: false,
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 5),
|
||||
child: NavigationRailSection(
|
||||
onSelectItem: handleScreenChanged,
|
||||
selectedIndex: screenIndex)),
|
||||
const VerticalDivider(thickness: 1, width: 1),
|
||||
createScreenFor(screenIndex, true),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}),
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _BrightnessButton extends StatelessWidget {
|
||||
const _BrightnessButton({
|
||||
required this.handleBrightnessChange,
|
||||
this.showTooltipBelow = true,
|
||||
});
|
||||
|
||||
final Function handleBrightnessChange;
|
||||
final bool showTooltipBelow;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isBright = Theme.of(context).brightness == Brightness.light;
|
||||
return Tooltip(
|
||||
preferBelow: showTooltipBelow,
|
||||
message: 'Toggle brightness',
|
||||
child: IconButton(
|
||||
icon: isBright
|
||||
? const Icon(Icons.dark_mode_outlined)
|
||||
: const Icon(Icons.light_mode_outlined),
|
||||
onPressed: () => handleBrightnessChange(!isBright),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _Material3Button extends StatelessWidget {
|
||||
const _Material3Button({
|
||||
required this.handleMaterialVersionChange,
|
||||
this.showTooltipBelow = true,
|
||||
});
|
||||
|
||||
final void Function() handleMaterialVersionChange;
|
||||
final bool showTooltipBelow;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final useMaterial3 = Theme.of(context).useMaterial3;
|
||||
return Tooltip(
|
||||
preferBelow: showTooltipBelow,
|
||||
message: 'Switch to Material ${useMaterial3 ? 2 : 3}',
|
||||
child: IconButton(
|
||||
icon: useMaterial3
|
||||
? const Icon(Icons.filter_2)
|
||||
: const Icon(Icons.filter_3),
|
||||
onPressed: handleMaterialVersionChange,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ColorSeedButton extends StatelessWidget {
|
||||
const _ColorSeedButton({
|
||||
required this.handleColorSelect,
|
||||
required this.colorSelected,
|
||||
});
|
||||
|
||||
final void Function(int) handleColorSelect;
|
||||
final ColorSeed colorSelected;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return PopupMenuButton(
|
||||
icon: Icon(
|
||||
Icons.palette_outlined,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
tooltip: 'Select a seed color',
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
||||
itemBuilder: (context) {
|
||||
return List.generate(ColorSeed.values.length, (index) {
|
||||
ColorSeed currentColor = ColorSeed.values[index];
|
||||
|
||||
return PopupMenuItem(
|
||||
value: index,
|
||||
enabled: currentColor != colorSelected,
|
||||
child: Wrap(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 10),
|
||||
child: Icon(
|
||||
currentColor == colorSelected
|
||||
? Icons.color_lens
|
||||
: Icons.color_lens_outlined,
|
||||
color: currentColor.color,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 20),
|
||||
child: Text(currentColor.label),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
onSelected: handleColorSelect,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
),
|
||||
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,
|
||||
),
|
||||
)
|
||||
],
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,26 +17,26 @@ class TypographyScreen extends StatelessWidget {
|
||||
children: <Widget>[
|
||||
const SizedBox(height: 7),
|
||||
TextStyleExample(
|
||||
name: "Display Large", style: textTheme.displayLarge!),
|
||||
name: 'Display Large', style: textTheme.displayLarge!),
|
||||
TextStyleExample(
|
||||
name: "Display Medium", style: textTheme.displayMedium!),
|
||||
name: 'Display Medium', style: textTheme.displayMedium!),
|
||||
TextStyleExample(
|
||||
name: "Display Small", style: textTheme.displaySmall!),
|
||||
name: 'Display Small', style: textTheme.displaySmall!),
|
||||
TextStyleExample(
|
||||
name: "Headline Large", style: textTheme.headlineLarge!),
|
||||
name: 'Headline Large', style: textTheme.headlineLarge!),
|
||||
TextStyleExample(
|
||||
name: "Headline Medium", style: textTheme.headlineMedium!),
|
||||
name: 'Headline Medium', style: textTheme.headlineMedium!),
|
||||
TextStyleExample(
|
||||
name: "Headline Small", style: textTheme.headlineSmall!),
|
||||
TextStyleExample(name: "Title Large", style: textTheme.titleLarge!),
|
||||
TextStyleExample(name: "Title Medium", style: textTheme.titleMedium!),
|
||||
TextStyleExample(name: "Title Small", style: textTheme.titleSmall!),
|
||||
TextStyleExample(name: "Label Large", style: textTheme.labelLarge!),
|
||||
TextStyleExample(name: "Label Medium", style: textTheme.labelMedium!),
|
||||
TextStyleExample(name: "Label Small", style: textTheme.labelSmall!),
|
||||
TextStyleExample(name: "Body Large", style: textTheme.bodyLarge!),
|
||||
TextStyleExample(name: "Body Medium", style: textTheme.bodyMedium!),
|
||||
TextStyleExample(name: "Body Small", style: textTheme.bodySmall!),
|
||||
name: 'Headline Small', style: textTheme.headlineSmall!),
|
||||
TextStyleExample(name: 'Title Large', style: textTheme.titleLarge!),
|
||||
TextStyleExample(name: 'Title Medium', style: textTheme.titleMedium!),
|
||||
TextStyleExample(name: 'Title Small', style: textTheme.titleSmall!),
|
||||
TextStyleExample(name: 'Label Large', style: textTheme.labelLarge!),
|
||||
TextStyleExample(name: 'Label Medium', style: textTheme.labelMedium!),
|
||||
TextStyleExample(name: 'Label Small', style: textTheme.labelSmall!),
|
||||
TextStyleExample(name: 'Body Large', style: textTheme.bodyLarge!),
|
||||
TextStyleExample(name: 'Body Medium', style: textTheme.bodyMedium!),
|
||||
TextStyleExample(name: 'Body Small', style: textTheme.bodySmall!),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 51;
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXAggregateTarget section */
|
||||
@@ -235,6 +235,7 @@
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
3399D490228B24CF009A79C7 /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
@@ -344,7 +345,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
@@ -423,7 +424,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = macosx;
|
||||
@@ -470,7 +471,7 @@
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.11;
|
||||
MACOSX_DEPLOYMENT_TARGET = 10.14;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = macosx;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
|
||||
@@ -8,7 +8,7 @@ publish_to: "none"
|
||||
version: 1.0.0+1
|
||||
|
||||
environment:
|
||||
sdk: ">=2.17.0-0 <3.0.0"
|
||||
sdk: ">=2.18.0-0 <3.0.0"
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
|
||||
@@ -16,46 +16,61 @@ void main() {
|
||||
'on NavigationBar', (tester) async {
|
||||
widgetSetup(tester, 449);
|
||||
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("Dark Theme"), findsNothing);
|
||||
expect(find.text('Light Theme'), findsNothing);
|
||||
expect(find.text('Dark Theme'), findsNothing);
|
||||
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);
|
||||
await tester.tap(colorIconOnBar);
|
||||
await tester.pumpAndSettle(const Duration(microseconds: 500));
|
||||
expect(colorIconOnBar, findsNothing);
|
||||
expect(find.byIcon(Icons.format_paint), findsOneWidget);
|
||||
expect(find.text("Light Theme"), findsOneWidget);
|
||||
expect(find.text("Dark Theme"), 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('Dark Theme'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'Color palettes screen shows correctly when color icon is clicked '
|
||||
'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);
|
||||
await tester.pumpWidget(const Material3Demo());
|
||||
expect(find.text("Light Theme"), findsNothing);
|
||||
expect(find.text("Dark Theme"), findsNothing);
|
||||
await tester.pumpWidget(const MaterialApp(home: Material3Demo()));
|
||||
await tester.pumpAndSettle();
|
||||
expect(find.text('Light Theme'), findsNothing);
|
||||
expect(find.text('Dark Theme'), findsNothing);
|
||||
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);
|
||||
await tester.tap(colorIconOnRail);
|
||||
await tester.pumpAndSettle(const Duration(microseconds: 500));
|
||||
expect(colorIconOnRail, findsNothing);
|
||||
expect(find.byIcon(Icons.format_paint), findsOneWidget);
|
||||
expect(find.text("Light Theme"), findsOneWidget);
|
||||
expect(find.text("Dark Theme"), 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('Dark Theme'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('Color screen shows correct content', (tester) async {
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
home: Scaffold(body: Row(children: const [ColorPalettesScreen()])),
|
||||
));
|
||||
expect(find.text("Light Theme"), findsOneWidget);
|
||||
expect(find.text("Dark Theme"), findsOneWidget);
|
||||
expect(find.text('Light Theme'), findsOneWidget);
|
||||
expect(find.text('Dark Theme'), findsOneWidget);
|
||||
expect(find.byType(ColorGroup, skipOffstage: false), findsNWidgets(14));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -10,186 +10,216 @@ import 'package:material_3_demo/main.dart';
|
||||
|
||||
void main() {
|
||||
testWidgets('Default main page shows all M3 components', (tester) async {
|
||||
await tester.pumpWidget(const Material3Demo());
|
||||
widgetSetup(tester, 800, windowHeight: 7000);
|
||||
await tester.pumpWidget(const MaterialApp(home: Material3Demo()));
|
||||
|
||||
// Elements on the app bar
|
||||
expect(find.text('Material 3'), findsOneWidget);
|
||||
expect(find.widgetWithIcon(IconButton, Icons.wb_sunny_outlined),
|
||||
findsOneWidget);
|
||||
expect(find.widgetWithIcon(IconButton, Icons.filter_3), findsOneWidget);
|
||||
expect(find.widgetWithIcon(IconButton, Icons.more_vert), findsOneWidget);
|
||||
expect(
|
||||
find.widgetWithIcon(AppBar, Icons.dark_mode_outlined), findsOneWidget);
|
||||
expect(find.widgetWithIcon(AppBar, Icons.filter_2), findsOneWidget);
|
||||
expect(find.widgetWithIcon(AppBar, Icons.palette_outlined), findsOneWidget);
|
||||
|
||||
// Elements on the component screen
|
||||
// Buttons
|
||||
expect(find.widgetWithText(ElevatedButton, "Elevated"), findsNWidgets(2));
|
||||
expect(find.widgetWithText(ElevatedButton, "Filled"), findsNWidgets(2));
|
||||
expect(
|
||||
find.widgetWithText(ElevatedButton, "Filled Tonal"), findsNWidgets(2));
|
||||
expect(find.widgetWithText(OutlinedButton, "Outlined"), findsNWidgets(2));
|
||||
expect(find.widgetWithText(TextButton, "Text"), findsNWidgets(2));
|
||||
expect(find.text("Icon"), findsNWidgets(5));
|
||||
expect(find.widgetWithText(ElevatedButton, 'Elevated'), findsNWidgets(2));
|
||||
expect(find.widgetWithText(FilledButton, 'Filled'), findsNWidgets(2));
|
||||
expect(find.widgetWithText(FilledButton, 'Filled tonal'), findsNWidgets(2));
|
||||
expect(find.widgetWithText(OutlinedButton, 'Outlined'), findsNWidgets(2));
|
||||
expect(find.widgetWithText(TextButton, 'Text'), findsNWidgets(2));
|
||||
expect(find.widgetWithText(Buttons, 'Icon'), findsNWidgets(5));
|
||||
|
||||
// IconButtons
|
||||
expect(find.byType(IconToggleButton), findsNWidgets(8));
|
||||
|
||||
// FABs
|
||||
Finder floatingActionButton = find.text("Create");
|
||||
await tester.scrollUntilVisible(
|
||||
floatingActionButton,
|
||||
500.0,
|
||||
);
|
||||
expect(
|
||||
find.widgetWithIcon(FloatingActionButton, Icons.add), findsNWidgets(4));
|
||||
expect(find.widgetWithText(FloatingActionButton, "Create"), findsOneWidget);
|
||||
expect(find.byType(FloatingActionButton),
|
||||
findsNWidgets(5)); // 2 more shows up in the bottom app bar.
|
||||
expect(find.widgetWithText(FloatingActionButton, 'Create'), findsOneWidget);
|
||||
|
||||
// Chips
|
||||
expect(find.byType(ActionChip),
|
||||
findsNWidgets(4)); // includes Assist and Suggestion chip.
|
||||
expect(find.byType(FilterChip), findsNWidgets(2));
|
||||
expect(find.byType(InputChip), findsNWidgets(2));
|
||||
|
||||
// Cards
|
||||
expect(find.widgetWithText(Card, "Elevated"), findsOneWidget);
|
||||
expect(find.widgetWithText(Card, "Filled"), findsOneWidget);
|
||||
expect(find.widgetWithText(Card, "Outlined"), findsOneWidget);
|
||||
expect(find.widgetWithText(Cards, 'Elevated'), findsOneWidget);
|
||||
expect(find.widgetWithText(Cards, 'Filled'), findsOneWidget);
|
||||
expect(find.widgetWithText(Cards, 'Outlined'), findsOneWidget);
|
||||
|
||||
// TextFields
|
||||
expect(find.widgetWithText(TextField, 'Disabled'), findsNWidgets(2));
|
||||
expect(find.widgetWithText(TextField, 'Filled'), findsNWidgets(2));
|
||||
expect(find.widgetWithText(TextField, 'Outlined'), findsNWidgets(2));
|
||||
|
||||
// Alert Dialog
|
||||
Finder dialogExample = find.widgetWithText(TextButton, "Open Dialog");
|
||||
await tester.scrollUntilVisible(
|
||||
dialogExample,
|
||||
500.0,
|
||||
);
|
||||
Finder dialogExample = find.widgetWithText(TextButton, 'Show dialog');
|
||||
expect(dialogExample, findsOneWidget);
|
||||
|
||||
// Switches
|
||||
Finder switchExample = find.byType(Switch);
|
||||
expect(switchExample, findsNWidgets(4));
|
||||
|
||||
// Checkboxes
|
||||
Finder checkboxExample = find.byType(CheckboxListTile);
|
||||
expect(checkboxExample, findsNWidgets(4));
|
||||
|
||||
// Radios
|
||||
// TODO(guidezpl): Figure out why this isn't working
|
||||
// Finder radioExample = find.byType(RadioListTile<Value>);
|
||||
// expect(radioExample, findsNWidgets(4));
|
||||
|
||||
// ProgressIndicator
|
||||
Finder circularProgressIndicator = find.byType(CircularProgressIndicator);
|
||||
expect(circularProgressIndicator, findsOneWidget);
|
||||
Finder linearProgressIndicator = find.byType(LinearProgressIndicator);
|
||||
expect(linearProgressIndicator, findsOneWidget);
|
||||
});
|
||||
|
||||
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 {
|
||||
widgetSetup(tester, 449);
|
||||
await tester.pumpWidget(const Material3Demo());
|
||||
widgetSetup(tester, 999, windowHeight: 7000);
|
||||
await tester.pumpWidget(const MaterialApp(home: Material3Demo()));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// When screen width is less than 450, NavigationBar will show. At the same
|
||||
// time, the NavigationRail and the NavigationBar example will NOT show.
|
||||
expect(find.byType(NavigationBars), findsOneWidget);
|
||||
expect(find.widgetWithText(NavigationBar, "Components"), findsOneWidget);
|
||||
expect(find.widgetWithText(NavigationBar, "Color"), findsOneWidget);
|
||||
expect(find.widgetWithText(NavigationBar, "Typography"), findsOneWidget);
|
||||
expect(find.widgetWithText(NavigationBar, "Elevation"), findsOneWidget);
|
||||
// When screen width is less than 1000, NavigationBar will show. At the same
|
||||
// time, the NavigationBar example still show up in the navigation group.
|
||||
expect(find.byType(NavigationBars),
|
||||
findsNWidgets(3)); // The real navBar, badges example and navBar example
|
||||
expect(find.widgetWithText(NavigationBar, 'Components'), findsOneWidget);
|
||||
expect(find.widgetWithText(NavigationBar, 'Color'), findsOneWidget);
|
||||
expect(find.widgetWithText(NavigationBar, 'Typography'), findsOneWidget);
|
||||
expect(find.widgetWithText(NavigationBar, 'Elevation'), findsOneWidget);
|
||||
|
||||
expect(find.byType(NavigationRailSection), findsNothing);
|
||||
expect(find.widgetWithText(NavigationBar, "Explore"), findsNothing);
|
||||
expect(find.widgetWithText(NavigationBar, "Pets"), findsNothing);
|
||||
expect(find.widgetWithText(NavigationBar, "Account"), findsNothing);
|
||||
expect(find.widgetWithText(NavigationBar, 'Explore'), findsOneWidget);
|
||||
expect(find.widgetWithText(NavigationBar, 'Pets'), findsOneWidget);
|
||||
expect(find.widgetWithText(NavigationBar, 'Account'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'NavigationRail shows when width value is greater than or equal '
|
||||
'to 450 (in Landscape mode or wider screen)', (tester) async {
|
||||
widgetSetup(tester, 450);
|
||||
await tester.pumpWidget(const Material3Demo());
|
||||
'to 1000 (in Landscape mode or wider screen)', (tester) async {
|
||||
widgetSetup(tester, 1001, windowHeight: 3000);
|
||||
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
|
||||
// will NOT show.
|
||||
expect(find.byType(NavigationRailSection), findsOneWidget);
|
||||
// When screen width is greater than or equal to 1000, NavigationRail will show.
|
||||
// At the same time, the NavigationBar will NOT show.
|
||||
expect(find.byType(NavigationRail), findsOneWidget);
|
||||
expect(find.byType(Tooltip, skipOffstage: false), findsWidgets);
|
||||
expect(find.widgetWithText(NavigationRailSection, "Components"),
|
||||
findsOneWidget);
|
||||
expect(find.widgetWithText(NavigationRailSection, "Color"), findsOneWidget);
|
||||
expect(find.widgetWithText(NavigationRailSection, "Typography"),
|
||||
findsOneWidget);
|
||||
expect(find.widgetWithText(NavigationRailSection, "Elevation"),
|
||||
findsOneWidget);
|
||||
expect(find.widgetWithText(NavigationRail, 'Components'), findsOneWidget);
|
||||
expect(find.widgetWithText(NavigationRail, 'Color'), findsOneWidget);
|
||||
expect(find.widgetWithText(NavigationRail, 'Typography'), findsOneWidget);
|
||||
expect(find.widgetWithText(NavigationRail, 'Elevation'), findsOneWidget);
|
||||
|
||||
final navbarExample = find.byType(NavigationBars);
|
||||
await tester.scrollUntilVisible(
|
||||
navbarExample,
|
||||
500.0,
|
||||
);
|
||||
expect(find.byType(NavigationBars), findsOneWidget);
|
||||
expect(find.widgetWithText(NavigationBar, "Explore"), findsOneWidget);
|
||||
expect(find.widgetWithText(NavigationBar, "Pets"), findsOneWidget);
|
||||
expect(find.widgetWithText(NavigationBar, "Account"), findsOneWidget);
|
||||
expect(find.widgetWithText(NavigationBar, 'Explore'), findsOneWidget);
|
||||
expect(find.widgetWithText(NavigationBar, 'Pets'), findsOneWidget);
|
||||
expect(find.widgetWithText(NavigationBar, 'Account'), findsOneWidget);
|
||||
|
||||
expect(find.widgetWithText(NavigationBar, "Components"), findsNothing);
|
||||
expect(find.widgetWithText(NavigationBar, "Colors"), findsNothing);
|
||||
expect(find.widgetWithText(NavigationBar, "Typography"), findsNothing);
|
||||
expect(find.widgetWithText(NavigationBar, "Elevation"), findsNothing);
|
||||
// the Navigation bar should be out of screen.
|
||||
final RenderBox box =
|
||||
tester.renderObject(find.widgetWithText(NavigationBar, 'Components'));
|
||||
expect(box.localToGlobal(Offset.zero), const Offset(0.0, 3080.0));
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'Material version switches between Material3 and Material2 when'
|
||||
'the version icon is clicked', (tester) async {
|
||||
await tester.pumpWidget(const Material3Demo());
|
||||
Finder m3Icon = find.widgetWithIcon(IconButton, Icons.filter_3);
|
||||
Finder m2Icon = find.widgetWithIcon(IconButton, Icons.filter_2);
|
||||
widgetSetup(tester, 450, windowHeight: 7000);
|
||||
await tester.pumpWidget(const MaterialApp(home: Material3Demo()));
|
||||
BuildContext defaultElevatedButton =
|
||||
tester.firstElement(find.byType(ElevatedButton));
|
||||
BuildContext defaultIconButton =
|
||||
tester.firstElement(find.byType(IconButton));
|
||||
BuildContext defaultFAB =
|
||||
tester.firstElement(find.byType(FloatingActionButton));
|
||||
BuildContext defaultCard = tester.firstElement(find.byType(Card));
|
||||
Finder dialog = find.text("Open Dialog");
|
||||
await tester.scrollUntilVisible(
|
||||
dialog,
|
||||
500.0,
|
||||
);
|
||||
BuildContext defaultCard =
|
||||
tester.firstElement(find.widgetWithText(Card, 'Elevated'));
|
||||
BuildContext defaultChip =
|
||||
tester.firstElement(find.widgetWithText(ActionChip, 'Assist'));
|
||||
Finder dialog = find.text('Show dialog');
|
||||
await tester.tap(dialog);
|
||||
await tester.pumpAndSettle(const Duration(microseconds: 500));
|
||||
BuildContext defaultAlertDialog = tester.element(find.byType(AlertDialog));
|
||||
expect(Theme.of(defaultAlertDialog).useMaterial3, true);
|
||||
Finder dismiss = find.text("Dismiss");
|
||||
await tester.scrollUntilVisible(
|
||||
dismiss,
|
||||
500.0,
|
||||
);
|
||||
Finder dismiss = find.text('Okay');
|
||||
await tester.tap(dismiss);
|
||||
await tester.pumpAndSettle(const Duration(microseconds: 500));
|
||||
|
||||
expect(m3Icon, findsOneWidget);
|
||||
expect(m2Icon, findsNothing);
|
||||
expect(find.text("Material 3"), findsOneWidget);
|
||||
expect(find.widgetWithIcon(AppBar, Icons.filter_2), findsOneWidget);
|
||||
expect(find.widgetWithIcon(AppBar, Icons.filter_3), findsNothing);
|
||||
expect(find.text('Material 3'), findsOneWidget);
|
||||
expect(Theme.of(defaultElevatedButton).useMaterial3, true);
|
||||
expect(Theme.of(defaultIconButton).useMaterial3, true);
|
||||
expect(Theme.of(defaultFAB).useMaterial3, true);
|
||||
expect(Theme.of(defaultCard).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_2));
|
||||
await tester.tap(appbarM3Icon);
|
||||
await tester.pumpAndSettle(const Duration(microseconds: 500));
|
||||
BuildContext updatedElevatedButton =
|
||||
tester.firstElement(find.byType(ElevatedButton));
|
||||
BuildContext updatedIconButton =
|
||||
tester.firstElement(find.byType(IconButton));
|
||||
BuildContext updatedFAB =
|
||||
tester.firstElement(find.byType(FloatingActionButton));
|
||||
BuildContext updatedCard = tester.firstElement(find.byType(Card));
|
||||
Finder updatedDialog = find.text("Open Dialog");
|
||||
await tester.scrollUntilVisible(
|
||||
updatedDialog,
|
||||
500.0,
|
||||
);
|
||||
BuildContext updatedChip =
|
||||
tester.firstElement(find.widgetWithText(ActionChip, 'Assist'));
|
||||
Finder updatedDialog = find.text('Show dialog');
|
||||
await tester.tap(updatedDialog);
|
||||
await tester.pumpAndSettle(const Duration(microseconds: 500));
|
||||
BuildContext updatedAlertDialog =
|
||||
tester.firstElement(find.byType(AlertDialog));
|
||||
expect(Theme.of(updatedAlertDialog).useMaterial3, false);
|
||||
Finder updatedDismiss = find.text("Dismiss");
|
||||
await tester.scrollUntilVisible(
|
||||
updatedDismiss,
|
||||
500.0,
|
||||
);
|
||||
Finder updatedDismiss = find.text('Dismiss');
|
||||
await tester.tap(updatedDismiss);
|
||||
await tester.pumpAndSettle(const Duration(microseconds: 500));
|
||||
|
||||
expect(m3Icon, findsNothing);
|
||||
expect(m2Icon, findsOneWidget);
|
||||
expect(find.text("Material 2"), findsOneWidget);
|
||||
expect(find.widgetWithIcon(AppBar, Icons.filter_3), findsOneWidget);
|
||||
expect(find.widgetWithIcon(AppBar, Icons.filter_2), findsNothing);
|
||||
expect(find.text('Material 2'), findsOneWidget);
|
||||
expect(Theme.of(updatedElevatedButton).useMaterial3, false);
|
||||
expect(Theme.of(updatedIconButton).useMaterial3, false);
|
||||
expect(Theme.of(updatedFAB).useMaterial3, false);
|
||||
expect(Theme.of(updatedCard).useMaterial3, false);
|
||||
expect(Theme.of(updatedChip).useMaterial3, false);
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'Other screens become Material2 mode after changing mode from '
|
||||
'main screen', (tester) async {
|
||||
await tester.pumpWidget(const Material3Demo());
|
||||
await tester.tap(find.widgetWithIcon(IconButton, Icons.filter_3));
|
||||
await tester.tap(find.byIcon(Icons.format_paint_outlined));
|
||||
await tester.pumpWidget(const MaterialApp(home: Material3Demo()));
|
||||
Finder appbarM2Icon = find.descendant(
|
||||
of: find.byType(AppBar),
|
||||
matching: find.widgetWithIcon(IconButton, Icons.filter_2));
|
||||
await tester.tap(appbarM2Icon);
|
||||
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));
|
||||
BuildContext lightThemeText = tester.element(find.text("Light Theme"));
|
||||
BuildContext lightThemeText = tester.element(find.text('Light Theme'));
|
||||
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));
|
||||
BuildContext displayLargeText = tester.element(find.text("Display Large"));
|
||||
BuildContext displayLargeText = tester.element(find.text('Display Large'));
|
||||
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));
|
||||
BuildContext material = tester.firstElement(find.byType(Material));
|
||||
expect(Theme.of(material).useMaterial3, false);
|
||||
@@ -198,25 +228,30 @@ void main() {
|
||||
testWidgets(
|
||||
'Brightness mode switches between dark and light when'
|
||||
'the brightness icon is clicked', (tester) async {
|
||||
await tester.pumpWidget(const Material3Demo());
|
||||
Finder lightIcon = find.widgetWithIcon(IconButton, Icons.wb_sunny_outlined);
|
||||
Finder darkIcon = find.widgetWithIcon(IconButton, Icons.wb_sunny);
|
||||
BuildContext appBar = tester.element(find.byType(AppBar));
|
||||
BuildContext body = tester.element(find.byType(Scaffold));
|
||||
BuildContext navigationRail = tester.element(find.byType(NavigationRail));
|
||||
expect(lightIcon, findsOneWidget);
|
||||
expect(darkIcon, findsNothing);
|
||||
await tester.pumpWidget(const MaterialApp(home: Material3Demo()));
|
||||
Finder lightIcon = find.descendant(
|
||||
of: find.byType(AppBar),
|
||||
matching: find.widgetWithIcon(IconButton, Icons.light_mode_outlined));
|
||||
Finder darkIcon = find.descendant(
|
||||
of: find.byType(AppBar),
|
||||
matching: find.widgetWithIcon(IconButton, Icons.dark_mode_outlined));
|
||||
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(darkIcon, findsOneWidget);
|
||||
expect(lightIcon, findsNothing);
|
||||
expect(Theme.of(appBar).brightness, Brightness.light);
|
||||
expect(Theme.of(body).brightness, Brightness.light);
|
||||
expect(Theme.of(navigationRail).brightness, Brightness.light);
|
||||
await tester.tap(lightIcon);
|
||||
await tester.tap(darkIcon);
|
||||
await tester.pumpAndSettle(const Duration(microseconds: 500));
|
||||
|
||||
BuildContext appBar2 = tester.element(find.byType(AppBar));
|
||||
BuildContext body2 = tester.element(find.byType(Scaffold));
|
||||
BuildContext appBar2 = tester.element(find.byType(AppBar).first);
|
||||
BuildContext body2 = tester.element(find.byType(Scaffold).first);
|
||||
BuildContext navigationRail2 = tester.element(find.byType(NavigationRail));
|
||||
expect(lightIcon, findsNothing);
|
||||
expect(darkIcon, findsOneWidget);
|
||||
expect(darkIcon, findsNothing);
|
||||
expect(lightIcon, findsOneWidget);
|
||||
expect(Theme.of(appBar2).brightness, Brightness.dark);
|
||||
expect(Theme.of(body2).brightness, Brightness.dark);
|
||||
expect(Theme.of(navigationRail2).brightness, Brightness.dark);
|
||||
@@ -224,10 +259,15 @@ void main() {
|
||||
|
||||
testWidgets('Color theme changes when a color is selected from menu',
|
||||
(tester) async {
|
||||
await tester.pumpWidget(const Material3Demo());
|
||||
Finder menuIcon = find.widgetWithIcon(IconButton, Icons.more_vert);
|
||||
BuildContext appBar = tester.element(find.byType(AppBar));
|
||||
BuildContext body = tester.element(find.byType(Scaffold));
|
||||
Color m3BaseColor = const Color(0xff6750a4);
|
||||
await tester.pumpWidget(Container());
|
||||
await tester.pumpWidget(const MaterialApp(home: Material3Demo()));
|
||||
await tester.pump();
|
||||
Finder menuIcon = find.descendant(
|
||||
of: find.byType(AppBar),
|
||||
matching: find.widgetWithIcon(IconButton, Icons.palette_outlined));
|
||||
BuildContext appBar = tester.element(find.byType(AppBar).first);
|
||||
BuildContext body = tester.element(find.byType(Scaffold).first);
|
||||
BuildContext navigationRail = tester.element(find.byType(NavigationRail));
|
||||
|
||||
expect(Theme.of(appBar).primaryColor, m3BaseColor);
|
||||
@@ -235,11 +275,11 @@ void main() {
|
||||
expect(Theme.of(navigationRail).primaryColor, m3BaseColor);
|
||||
await tester.tap(menuIcon);
|
||||
await tester.pumpAndSettle();
|
||||
await tester.tap(find.text("Blue"));
|
||||
await tester.tap(find.text('Blue').last);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
BuildContext appBar2 = tester.element(find.byType(AppBar));
|
||||
BuildContext body2 = tester.element(find.byType(Scaffold));
|
||||
BuildContext appBar2 = tester.element(find.byType(AppBar).first);
|
||||
BuildContext body2 = tester.element(find.byType(Scaffold).first);
|
||||
BuildContext navigationRail2 = tester.element(find.byType(NavigationRail));
|
||||
ThemeData expectedTheme = ThemeData(colorSchemeSeed: Colors.blue);
|
||||
expect(Theme.of(appBar2).primaryColor, expectedTheme.primaryColor);
|
||||
@@ -248,9 +288,11 @@ void main() {
|
||||
});
|
||||
}
|
||||
|
||||
void widgetSetup(WidgetTester tester, double width) {
|
||||
const height = 846;
|
||||
void widgetSetup(WidgetTester tester, double windowWidth,
|
||||
{double? windowHeight}) {
|
||||
final height = windowHeight ?? 846;
|
||||
tester.binding.window.devicePixelRatioTestValue = (2);
|
||||
final dpi = tester.binding.window.devicePixelRatio;
|
||||
tester.binding.window.physicalSizeTestValue = Size(width * dpi, height * dpi);
|
||||
tester.binding.window.physicalSizeTestValue =
|
||||
Size(windowWidth * dpi, height * dpi);
|
||||
}
|
||||
|
||||
@@ -16,43 +16,54 @@ void main() {
|
||||
'selected on NavigationBar', (tester) async {
|
||||
widgetSetup(tester, 449);
|
||||
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);
|
||||
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);
|
||||
await tester.tap(tintIconOnBar);
|
||||
await tester.pumpAndSettle(const Duration(microseconds: 500));
|
||||
expect(tintIconOnBar, findsNothing);
|
||||
expect(find.byIcon(Icons.opacity), findsOneWidget);
|
||||
expect(find.text("Surface Tint only"), findsOneWidget);
|
||||
Finder selectedTintIconOnBar = find.descendant(
|
||||
of: find.byType(NavigationBar),
|
||||
matching: find.widgetWithIcon(NavigationDestination, Icons.opacity));
|
||||
expect(selectedTintIconOnBar, findsOneWidget);
|
||||
expect(find.text('Surface Tint Color Only'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'Surface Tones screen shows correctly when the corresponding icon is '
|
||||
'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);
|
||||
await tester.pumpWidget(const Material3Demo());
|
||||
expect(find.text("Surface Tint only"), findsNothing);
|
||||
await tester.pumpWidget(const MaterialApp(home: Material3Demo()));
|
||||
expect(find.text('Surface Tint Color Only'), findsNothing);
|
||||
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);
|
||||
await tester.tap(tintIconOnRail);
|
||||
await tester.pumpAndSettle(const Duration(microseconds: 500));
|
||||
expect(tintIconOnRail, findsNothing);
|
||||
expect(find.byIcon(Icons.opacity), findsOneWidget);
|
||||
expect(find.text("Surface Tint only"), findsOneWidget);
|
||||
Finder selectedTintIconOnRail = find.descendant(
|
||||
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 {
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
home: Scaffold(body: Row(children: const [ElevationScreen()])),
|
||||
));
|
||||
expect(find.text("Surface Tint only"), findsOneWidget);
|
||||
expect(find.text("Surface Tint and Shadow"), findsOneWidget);
|
||||
expect(find.text("Shadow only"), findsOneWidget);
|
||||
expect(find.text('Surface Tint Color Only'), findsOneWidget);
|
||||
expect(find.text('Surface Tint Color and Shadow Color'), findsOneWidget);
|
||||
expect(find.text('Shadow Color Only'), findsOneWidget);
|
||||
expect(find.byType(ElevationGrid), findsNWidgets(3));
|
||||
expect(find.byType(ElevationCard), findsNWidgets(18));
|
||||
});
|
||||
|
||||
@@ -16,59 +16,70 @@ void main() {
|
||||
'selected on NavigationBar', (tester) async {
|
||||
widgetSetup(tester, 449);
|
||||
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);
|
||||
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);
|
||||
await tester.tap(textIconOnBar);
|
||||
await tester.pumpAndSettle(const Duration(microseconds: 500));
|
||||
expect(textIconOnBar, findsNothing);
|
||||
expect(find.byIcon(Icons.text_snippet), findsOneWidget);
|
||||
expect(find.text("Display Large"), findsOneWidget);
|
||||
Finder selectedTextIconOnBar = find.descendant(
|
||||
of: find.byType(NavigationBar),
|
||||
matching: find.byIcon(Icons.text_snippet));
|
||||
expect(selectedTextIconOnBar, findsOneWidget);
|
||||
expect(find.text('Display Large'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'Typography screen shows correctly when the corresponding icon is '
|
||||
'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);
|
||||
await tester.pumpWidget(const Material3Demo());
|
||||
expect(find.text("Display Large"), findsNothing);
|
||||
await tester.pumpWidget(const MaterialApp(home: Material3Demo()));
|
||||
expect(find.text('Display Large'), findsNothing);
|
||||
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);
|
||||
await tester.tap(textIconOnRail);
|
||||
await tester.pumpAndSettle(const Duration(microseconds: 500));
|
||||
expect(textIconOnRail, findsNothing);
|
||||
expect(find.byIcon(Icons.text_snippet), findsOneWidget);
|
||||
expect(find.text("Display Large"), findsOneWidget);
|
||||
Finder selectedTextIconOnRail = find.descendant(
|
||||
of: find.byType(NavigationRail),
|
||||
matching: find.byIcon(Icons.text_snippet));
|
||||
expect(selectedTextIconOnRail, findsOneWidget);
|
||||
expect(find.text('Display Large'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('Typography screen shows correct content', (tester) async {
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
home: Scaffold(body: Row(children: const [TypographyScreen()])),
|
||||
));
|
||||
expect(find.text("Display Large"), findsOneWidget);
|
||||
expect(find.text("Display Medium"), findsOneWidget);
|
||||
expect(find.text("Display Small"), findsOneWidget);
|
||||
expect(find.text("Headline Large"), findsOneWidget);
|
||||
expect(find.text("Headline Medium"), findsOneWidget);
|
||||
expect(find.text("Headline Small"), findsOneWidget);
|
||||
expect(find.text("Title Large"), findsOneWidget);
|
||||
expect(find.text("Title Medium"), findsOneWidget);
|
||||
expect(find.text("Title Small"), findsOneWidget);
|
||||
expect(find.text('Display Large'), findsOneWidget);
|
||||
expect(find.text('Display Medium'), findsOneWidget);
|
||||
expect(find.text('Display Small'), findsOneWidget);
|
||||
expect(find.text('Headline Large'), findsOneWidget);
|
||||
expect(find.text('Headline Medium'), findsOneWidget);
|
||||
expect(find.text('Headline Small'), findsOneWidget);
|
||||
expect(find.text('Title Large'), findsOneWidget);
|
||||
expect(find.text('Title Medium'), findsOneWidget);
|
||||
expect(find.text('Title Small'), findsOneWidget);
|
||||
await tester.scrollUntilVisible(
|
||||
find.text("Body Small"),
|
||||
find.text('Body Small'),
|
||||
500.0,
|
||||
);
|
||||
expect(find.text("Label Large"), findsOneWidget);
|
||||
expect(find.text("Label Medium"), findsOneWidget);
|
||||
expect(find.text("Label Small"), findsOneWidget);
|
||||
expect(find.text("Body Large"), findsOneWidget);
|
||||
expect(find.text("Body Medium"), findsOneWidget);
|
||||
expect(find.text("Body Small"), findsOneWidget);
|
||||
expect(find.text('Label Large'), findsOneWidget);
|
||||
expect(find.text('Label Medium'), findsOneWidget);
|
||||
expect(find.text('Label Small'), findsOneWidget);
|
||||
expect(find.text('Body Large'), findsOneWidget);
|
||||
expect(find.text('Body Medium'), findsOneWidget);
|
||||
expect(find.text('Body Small'), findsOneWidget);
|
||||
|
||||
expect(find.byType(TextStyleExample), findsNWidgets(15));
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user