Auto-format Framework (#160545)

This auto-formats all *.dart files in the repository outside of the
`engine` subdirectory and enforces that these files stay formatted with
a presubmit check.

**Reviewers:** Please carefully review all the commits except for the
one titled "formatted". The "formatted" commit was auto-generated by
running `dev/tools/format.sh -a -f`. The other commits were hand-crafted
to prepare the repo for the formatting change. I recommend reviewing the
commits one-by-one via the "Commits" tab and avoiding Github's "Files
changed" tab as it will likely slow down your browser because of the
size of this PR.

---------

Co-authored-by: Kate Lovett <katelovett@google.com>
Co-authored-by: LongCatIsLooong <31859944+LongCatIsLooong@users.noreply.github.com>
This commit is contained in:
Michael Goderbauer 2024-12-19 12:06:21 -08:00 committed by GitHub
parent 8e0993eda8
commit 5491c8c146
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4411 changed files with 455108 additions and 415991 deletions

View File

@ -393,6 +393,7 @@ targets:
- name: Linux packages_autoroller
presubmit: false
recipe: pub_autoroller/pub_autoroller
bringup: true # https://github.com/flutter/flutter/issues/160473
# This takes a while because we need to fetch network dependencies and run
# Gradle for every android app in the repo
timeout: 45

View File

@ -1,15 +1,6 @@
// VSCode workspace settings that are shared among all users of this project.
// This only affects subdirectories of this project.
{
// VSCode formats files on save by default. Since Flutter source code is
// hand-formatted, the default settings are changed to prevent inadvertent
// reformatting of code.
"[dart]": {
"editor.formatOnSave": false,
"editor.formatOnType": false,
"editor.formatOnPaste": false,
},
"html.format.enable": false,
"githubPullRequests.ignoredPullRequestBranches": [
"master"

View File

@ -12,10 +12,6 @@ class DynamicTitle extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Title(
title: title,
color: Theme.of(context).colorScheme.primary,
child: child,
);
return Title(title: title, color: Theme.of(context).colorScheme.primary, child: child);
}
}

View File

@ -21,21 +21,26 @@ class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
final ThemeData lightTheme = ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xff6750a4),
contrastLevel: MediaQuery.highContrastOf(context) ? 1.0 : 0.0,
));
colorScheme: ColorScheme.fromSeed(
seedColor: const Color(0xff6750a4),
contrastLevel: MediaQuery.highContrastOf(context) ? 1.0 : 0.0,
),
);
final ThemeData darkTheme = ThemeData(
colorScheme: ColorScheme.fromSeed(
brightness: Brightness.dark,
seedColor: const Color(0xff6750a4),
contrastLevel: MediaQuery.highContrastOf(context) ? 1.0 : 0.0,
));
colorScheme: ColorScheme.fromSeed(
brightness: Brightness.dark,
seedColor: const Color(0xff6750a4),
contrastLevel: MediaQuery.highContrastOf(context) ? 1.0 : 0.0,
),
);
final Map<String, WidgetBuilder> routes =
Map<String, WidgetBuilder>.fromEntries(
useCases.map((UseCase useCase) =>
MapEntry<String, WidgetBuilder>(useCase.route, (BuildContext context) => useCase.buildWithTitle(context))),
final Map<String, WidgetBuilder> routes = Map<String, WidgetBuilder>.fromEntries(
useCases.map(
(UseCase useCase) => MapEntry<String, WidgetBuilder>(
useCase.route,
(BuildContext context) => useCase.buildWithTitle(context),
),
),
);
return MaterialApp(
@ -65,22 +70,25 @@ class HomePageState extends State<HomePage> {
Widget _buildUseCaseItem(int index, UseCase useCase) {
return Padding(
padding: const EdgeInsets.all(10),
child: Builder(builder: (BuildContext context) {
padding: const EdgeInsets.all(10),
child: Builder(
builder: (BuildContext context) {
return TextButton(
key: Key(useCase.name),
onPressed: () => Navigator.of(context).pushNamed(useCase.route, arguments: useCase.name),
onPressed:
() => Navigator.of(context).pushNamed(useCase.route, arguments: useCase.name),
child: Text(useCase.name),
);
}));
},
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Semantics(headingLevel: 1, child: const Text('Accessibility Assessments')),
title: Semantics(headingLevel: 1, child: const Text('Accessibility Assessments')),
),
body: Center(
child: ListView(

View File

@ -34,7 +34,7 @@ class MainWidgetState extends State<MainWidget> {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Semantics(headingLevel:1, child: Text('$pageTitle Demo')),
title: Semantics(headingLevel: 1, child: Text('$pageTitle Demo')),
),
body: Center(
child: Column(
@ -45,10 +45,7 @@ class MainWidgetState extends State<MainWidget> {
label: const Text('Action'),
onPressed: () {},
),
const ActionChip(
avatar: Icon(Icons.favorite),
label: Text('Action'),
),
const ActionChip(avatar: Icon(Icons.favorite), label: Text('Action')),
],
),
),

View File

@ -36,63 +36,58 @@ class MainWidgetState extends State<MainWidget> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: <PreferredSizeWidget>[
AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Semantics(headingLevel: 1, child: const Text('AppBar')),
),
AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Semantics(headingLevel: 1, child: const Text('AppBar')),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.add_alert),
tooltip: 'Show Snackbar',
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('This is a snackbar')));
},
appBar:
<PreferredSizeWidget>[
AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Semantics(headingLevel: 1, child: const Text('AppBar')),
),
IconButton(
icon: const Icon(Icons.navigate_next),
tooltip: 'Go to the next page',
onPressed: () {
Navigator.push(context, MaterialPageRoute<void>(
builder: (BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor:
Theme.of(context).colorScheme.inversePrimary,
title: Semantics(headingLevel: 1, child: const Text('Next Page')),
),
body: const Center(
child: Text(
'This is the next page',
style: TextStyle(fontSize: 24),
),
AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Semantics(headingLevel: 1, child: const Text('AppBar')),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.add_alert),
tooltip: 'Show Snackbar',
onPressed: () {
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('This is a snackbar')));
},
),
IconButton(
icon: const Icon(Icons.navigate_next),
tooltip: 'Go to the next page',
onPressed: () {
Navigator.push(
context,
MaterialPageRoute<void>(
builder: (BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Semantics(headingLevel: 1, child: const Text('Next Page')),
),
body: const Center(
child: Text('This is the next page', style: TextStyle(fontSize: 24)),
),
);
},
),
);
},
));
},
),
],
),
],
),
AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Semantics(headingLevel: 1, child: const Text('AppBar')),
actions: <Widget>[
TextButton(
onPressed: () {},
child: const Text('Action 1'),
AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Semantics(headingLevel: 1, child: const Text('AppBar')),
actions: <Widget>[
TextButton(onPressed: () {}, child: const Text('Action 1')),
TextButton(onPressed: () {}, child: const Text('Action 2')),
],
),
TextButton(
onPressed: () {},
child: const Text('Action 2'),
),
],
),
][currentIndex],
][currentIndex],
body: ListView(
children: <Widget>[
RadioListTile<int>(

View File

@ -25,17 +25,14 @@ class _MainWidget extends StatefulWidget {
}
class _MainWidgetState extends State<_MainWidget> {
static const List<String> _kOptions = <String>[
'apple',
'banana',
'lemon',
];
static const List<String> _kOptions = <String>['apple', 'banana', 'lemon'];
static Widget _fieldViewBuilder(
BuildContext context,
TextEditingController textEditingController,
FocusNode focusNode,
VoidCallback onFieldSubmitted) {
BuildContext context,
TextEditingController textEditingController,
FocusNode focusNode,
VoidCallback onFieldSubmitted,
) {
return TextFormField(
focusNode: focusNode,
controller: textEditingController,
@ -58,8 +55,7 @@ class _MainWidgetState extends State<_MainWidget> {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Type below to autocomplete the following possible results: $_kOptions.'),
Text('Type below to autocomplete the following possible results: $_kOptions.'),
Autocomplete<String>(
optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text == '') {

View File

@ -36,11 +36,7 @@ class MainWidgetState extends State<MainWidget> {
),
body: const Center(
child: Badge(
label: Text(
'5',
semanticsLabel: '5 new messages',
style: TextStyle(color: Colors.white),
),
label: Text('5', semanticsLabel: '5 new messages', style: TextStyle(color: Colors.white)),
backgroundColor: Colors.green,
child: Icon(Icons.mail, semanticLabel: 'Messages'),
),

View File

@ -40,12 +40,7 @@ class MainWidgetState extends State<MainWidget> {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Card(
child: Padding(
padding: EdgeInsets.all(16),
child: Text('Card'),
),
),
Card(child: Padding(padding: EdgeInsets.all(16), child: Text('Card'))),
],
),
),

View File

@ -30,9 +30,7 @@ class _MainWidgetState extends State<_MainWidget> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Semantics(headingLevel: 1, child: Text('$pageTitle Demo')),
),
appBar: AppBar(title: Semantics(headingLevel: 1, child: Text('$pageTitle Demo'))),
body: ListView(
children: <Widget>[
CheckboxListTile(

View File

@ -25,7 +25,6 @@ class _MainWidget extends StatefulWidget {
}
class _MainWidgetState extends State<_MainWidget> {
String pageTitle = getUseCaseName(DatePickerUseCase());
@override
@ -37,13 +36,14 @@ class _MainWidgetState extends State<_MainWidget> {
),
body: Center(
child: TextButton(
onPressed: () => showDatePicker(
context: context,
initialEntryMode: DatePickerEntryMode.calendarOnly,
initialDate: DateTime.now(),
firstDate: DateTime.now().subtract(const Duration(days: 365)),
lastDate: DateTime.now().add(const Duration(days: 365)),
),
onPressed:
() => showDatePicker(
context: context,
initialEntryMode: DatePickerEntryMode.calendarOnly,
initialDate: DateTime.now(),
firstDate: DateTime.now().subtract(const Duration(days: 365)),
lastDate: DateTime.now().add(const Duration(days: 365)),
),
child: const Text('Show Date Picker'),
),
),

View File

@ -31,40 +31,42 @@ class _MainWidget extends StatelessWidget {
),
body: Center(
child: TextButton(
onPressed: () => showDialog<String>(
context: context,
builder: (BuildContext context) => Dialog(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('This is a typical dialog.'),
const SizedBox(height: 15),
Row(
children: <Widget>[
TextButton(
key: const Key('OK Button'),
autofocus: true,
onPressed: () {
Navigator.pop(context);
},
child: const Text('OK'),
onPressed:
() => showDialog<String>(
context: context,
builder:
(BuildContext context) => Dialog(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('This is a typical dialog.'),
const SizedBox(height: 15),
Row(
children: <Widget>[
TextButton(
key: const Key('OK Button'),
autofocus: true,
onPressed: () {
Navigator.pop(context);
},
child: const Text('OK'),
),
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('Cancel'),
),
],
),
],
),
TextButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('Cancel'),
),
],
),
),
],
),
),
),
),
child: const Text('Show Dialog'),
),
),

View File

@ -41,16 +41,8 @@ class _DrawerExampleState extends State<DrawerExample> {
padding: EdgeInsets.zero,
children: <Widget>[
const DrawerHeader(
decoration: BoxDecoration(
color: Colors.blue,
),
child: Text(
'Drawer Header',
style: TextStyle(
color: Colors.white,
fontSize: 24,
),
),
decoration: BoxDecoration(color: Colors.blue),
child: Text('Drawer Header', style: TextStyle(color: Colors.white, fontSize: 24)),
),
ListTile(
leading: const Icon(Icons.message),
@ -82,9 +74,7 @@ class _DrawerExampleState extends State<DrawerExample> {
],
),
),
body: Center(
child: Text('Page: $selectedPage'),
),
body: Center(child: Text('Page: $selectedPage')),
);
}
}

View File

@ -41,9 +41,7 @@ class _ExpansionTileExampleState extends State<ExpansionTileExample> {
const ExpansionTile(
title: Text('ExpansionTile 1'),
subtitle: Text('Trailing expansion arrow icon'),
children: <Widget>[
ListTile(title: Text('This is tile number 1')),
],
children: <Widget>[ListTile(title: Text('This is tile number 1'))],
),
ExpansionTile(
title: const Text('ExpansionTile 2'),
@ -51,9 +49,7 @@ class _ExpansionTileExampleState extends State<ExpansionTileExample> {
trailing: Icon(
_customTileExpanded ? Icons.arrow_drop_down_circle : Icons.arrow_drop_down,
),
children: const <Widget>[
ListTile(title: Text('This is tile number 2')),
],
children: const <Widget>[ListTile(title: Text('This is tile number 2'))],
onExpansionChanged: (bool expanded) {
setState(() {
_customTileExpanded = expanded;
@ -64,9 +60,7 @@ class _ExpansionTileExampleState extends State<ExpansionTileExample> {
title: Text('ExpansionTile 3'),
subtitle: Text('Leading expansion arrow icon'),
controlAffinity: ListTileControlAffinity.leading,
children: <Widget>[
ListTile(title: Text('This is tile number 3')),
],
children: <Widget>[ListTile(title: Text('This is tile number 3'))],
),
],
),

View File

@ -25,7 +25,6 @@ class MainWidget extends StatefulWidget {
}
class MainWidgetState extends State<MainWidget> {
final FocusNode dismissButtonFocusNode = FocusNode();
final FocusNode showButtonFocusNode = FocusNode();
@ -64,7 +63,7 @@ class MainWidgetState extends State<MainWidget> {
@override
Widget build(BuildContext context) {
return Scaffold(
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Semantics(headingLevel: 1, child: Text('$pageTitle Demo')),

View File

@ -50,10 +50,7 @@ class MainWidgetState extends State<MainWidget> {
icon: Icon(Icons.home_outlined),
label: 'Home',
),
NavigationDestination(
icon: Icon(Icons.business),
label: 'Business',
),
NavigationDestination(icon: Icon(Icons.business), label: 'Business'),
NavigationDestination(
selectedIcon: Icon(Icons.school),
icon: Icon(Icons.school_outlined),
@ -61,20 +58,12 @@ class MainWidgetState extends State<MainWidget> {
),
],
),
body: <Widget>[
Container(
alignment: Alignment.center,
child: const Text('Page 1'),
),
Container(
alignment: Alignment.center,
child: const Text('Page 2'),
),
Container(
alignment: Alignment.center,
child: const Text('Page 3'),
),
][currentPageIndex],
body:
<Widget>[
Container(alignment: Alignment.center, child: const Text('Page 1')),
Container(alignment: Alignment.center, child: const Text('Page 2')),
Container(alignment: Alignment.center, child: const Text('Page 3')),
][currentPageIndex],
);
}
}

View File

@ -2,12 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import '../utils.dart';
import 'use_cases.dart';
class ExampleDestination {
const ExampleDestination(this.label, this.icon, this.selectedIcon);
@ -17,12 +15,9 @@ class ExampleDestination {
}
const List<ExampleDestination> destinations = <ExampleDestination>[
ExampleDestination(
'Messages', Icon(Icons.widgets_outlined), Icon(Icons.widgets)),
ExampleDestination(
'Profile', Icon(Icons.format_paint_outlined), Icon(Icons.format_paint)),
ExampleDestination(
'Settings', Icon(Icons.settings_outlined), Icon(Icons.settings)),
ExampleDestination('Messages', Icon(Icons.widgets_outlined), Icon(Icons.widgets)),
ExampleDestination('Profile', Icon(Icons.format_paint_outlined), Icon(Icons.format_paint)),
ExampleDestination('Settings', Icon(Icons.settings_outlined), Icon(Icons.settings)),
];
class NavigationDrawerUseCase extends UseCase {
@ -40,8 +35,7 @@ class NavigationDrawerExample extends StatefulWidget {
const NavigationDrawerExample({super.key});
@override
State<NavigationDrawerExample> createState() =>
_NavigationDrawerExampleState();
State<NavigationDrawerExample> createState() => _NavigationDrawerExampleState();
}
class _NavigationDrawerExampleState extends State<NavigationDrawerExample> {
@ -77,10 +71,7 @@ class _NavigationDrawerExampleState extends State<NavigationDrawerExample> {
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Text('Page Index = $screenIndex'),
ElevatedButton(
onPressed: openDrawer,
child: const Text('Open Drawer'),
),
ElevatedButton(onPressed: openDrawer, child: const Text('Open Drawer')),
],
),
),
@ -91,24 +82,16 @@ class _NavigationDrawerExampleState extends State<NavigationDrawerExample> {
children: <Widget>[
Padding(
padding: const EdgeInsets.fromLTRB(28, 16, 16, 10),
child: Text(
'Header',
style: Theme.of(context).textTheme.titleSmall,
),
),
...destinations.map(
(ExampleDestination destination) {
return NavigationDrawerDestination(
label: Text(destination.label),
icon: destination.icon,
selectedIcon: destination.selectedIcon,
);
},
),
const Padding(
padding: EdgeInsets.fromLTRB(28, 16, 28, 10),
child: Divider(),
child: Text('Header', style: Theme.of(context).textTheme.titleSmall),
),
...destinations.map((ExampleDestination destination) {
return NavigationDrawerDestination(
label: Text(destination.label),
icon: destination.icon,
selectedIcon: destination.selectedIcon,
);
}),
const Padding(padding: EdgeInsets.fromLTRB(28, 16, 28, 10), child: Divider()),
],
),
);

View File

@ -47,23 +47,25 @@ class _NavRailExampleState extends State<NavRailExample> {
});
},
labelType: labelType,
leading: showLeading
? FloatingActionButton(
elevation: 0,
onPressed: () {
// Add your onPressed code here!
},
child: const Icon(Icons.add),
)
: const SizedBox(),
trailing: showTrailing
? IconButton(
onPressed: () {
// Add your onPressed code here!
},
icon: const Icon(Icons.more_horiz_rounded),
)
: const SizedBox(),
leading:
showLeading
? FloatingActionButton(
elevation: 0,
onPressed: () {
// Add your onPressed code here!
},
child: const Icon(Icons.add),
)
: const SizedBox(),
trailing:
showTrailing
? IconButton(
onPressed: () {
// Add your onPressed code here!
},
icon: const Icon(Icons.more_horiz_rounded),
)
: const SizedBox(),
destinations: const <NavigationRailDestination>[
NavigationRailDestination(
icon: Icon(Icons.favorite_border),

View File

@ -38,9 +38,7 @@ class _MainWidgetState extends State<_MainWidget> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Semantics(headingLevel: 1, child: Text('$pageTitle Demo'))
),
appBar: AppBar(title: Semantics(headingLevel: 1, child: Text('$pageTitle Demo'))),
body: ListView(
children: <Widget>[
RadioListTile<SingingCharacter>(

View File

@ -25,7 +25,6 @@ class MainWidget extends StatefulWidget {
}
class MainWidgetState extends State<MainWidget> {
String pageTitle = getUseCaseName(SnackBarUseCase());
@override
@ -41,11 +40,9 @@ class MainWidgetState extends State<MainWidget> {
ElevatedButton(
child: const Text('Show Snackbar'),
onPressed: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Awesome Snackbar!'),
),
);
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('Awesome Snackbar!')));
},
),
ElevatedButton(
@ -54,10 +51,7 @@ class MainWidgetState extends State<MainWidget> {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: const Text('Awesome Snackbar!'),
action: SnackBarAction(
label: 'Action',
onPressed: () {},
),
action: SnackBarAction(label: 'Action', onPressed: () {}),
),
);
},

View File

@ -7,7 +7,6 @@ import 'package:flutter/material.dart';
import 'use_cases.dart';
class TabBarViewUseCase extends UseCase {
@override
String get name => 'TabBarView';
@ -18,7 +17,6 @@ class TabBarViewUseCase extends UseCase {
Widget build(BuildContext context) => const TabBarViewExample();
}
class TabBarViewExample extends StatelessWidget {
const TabBarViewExample({super.key});
@ -32,32 +30,17 @@ class TabBarViewExample extends StatelessWidget {
title: Semantics(headingLevel: 1, child: const Text('TabBarView Sample')),
bottom: const TabBar(
tabs: <Widget>[
Tab(
icon: Icon(Icons.cloud_outlined),
text: 'Cloudy',
),
Tab(
icon: Icon(Icons.beach_access_sharp),
text: 'Rainy',
),
Tab(
icon: Icon(Icons.brightness_5_sharp),
text: 'Sunny',
),
Tab(icon: Icon(Icons.cloud_outlined), text: 'Cloudy'),
Tab(icon: Icon(Icons.beach_access_sharp), text: 'Rainy'),
Tab(icon: Icon(Icons.brightness_5_sharp), text: 'Sunny'),
],
),
),
body: const TabBarView(
children: <Widget>[
Center(
child: Text("It's cloudy here"),
),
Center(
child: Text("It's rainy here"),
),
Center(
child: Text("It's sunny here"),
),
Center(child: Text("It's cloudy here")),
Center(child: Text("It's rainy here")),
Center(child: Text("It's sunny here")),
],
),
),

View File

@ -57,12 +57,12 @@ class MainWidgetState extends State<MainWidget> {
if (_formKey.currentState!.validate()) {
// If the form is valid, display a snackbar. In the real world,
// this might also send a request to a server.
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Form submitted')),
);
ScaffoldMessenger.of(
context,
).showSnackBar(const SnackBar(content: Text('Form submitted')));
}
},
child: const Text('Submit'),
child: const Text('Submit'),
),
),
],

View File

@ -33,16 +33,12 @@ class _MainWidget extends StatelessWidget {
children: const <Widget>[
TextField(
key: Key('enabled password'),
decoration: InputDecoration(
labelText: 'Password',
),
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
),
TextField(
key: Key('disabled password'),
decoration: InputDecoration(
labelText: 'Password',
),
decoration: InputDecoration(labelText: 'Password'),
enabled: false,
obscureText: true,
),

View File

@ -33,10 +33,7 @@ abstract class UseCase {
String get route;
Widget buildWithTitle(BuildContext context) {
return DynamicTitle(
title: name,
child: build(context),
);
return DynamicTitle(title: name, child: build(context));
}
Widget build(BuildContext context);

View File

@ -9,8 +9,7 @@ import 'package:flutter_test/flutter_test.dart';
void main() {
for (final UseCase useCase in useCases) {
testWidgets('testing accessibility guideline for ${useCase.name}',
(WidgetTester tester) async {
testWidgets('testing accessibility guideline for ${useCase.name}', (WidgetTester tester) async {
await tester.pumpWidget(const App());
final ScrollController controller =
tester.state<HomePageState>(find.byType(HomePage)).scrollController;

View File

@ -8,8 +8,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'test_utils.dart';
void main() {
testWidgets('check box list tile use-case renders check boxes',
(WidgetTester tester) async {
testWidgets('check box list tile use-case renders check boxes', (WidgetTester tester) async {
await pumpsUseCase(tester, CheckBoxListTile());
expect(find.text('a check box list title'), findsOneWidget);
expect(find.text('a disabled check box list title'), findsOneWidget);

View File

@ -35,278 +35,391 @@ import 'test_utils.dart';
void main() {
testWidgets('Has light and dark theme', (WidgetTester tester) async {
await tester.pumpWidget(const App());
final MaterialApp app =
find.byType(MaterialApp).evaluate().first.widget as MaterialApp;
final MaterialApp app = find.byType(MaterialApp).evaluate().first.widget as MaterialApp;
expect(app.theme!.brightness, equals(Brightness.light));
expect(app.darkTheme!.brightness, equals(Brightness.dark));
});
testWidgets('App can generate high-contrast color scheme',
(WidgetTester tester) async {
await tester.pumpWidget(const MediaQuery(
data: MediaQueryData(
highContrast: true,
),
child: App()));
testWidgets('App can generate high-contrast color scheme', (WidgetTester tester) async {
await tester.pumpWidget(
const MediaQuery(data: MediaQueryData(highContrast: true), child: App()),
);
final MaterialApp app =
find.byType(MaterialApp).evaluate().first.widget as MaterialApp;
final MaterialApp app = find.byType(MaterialApp).evaluate().first.widget as MaterialApp;
final DynamicScheme highContrastScheme = SchemeTonalSpot(
sourceColorHct: Hct.fromInt(const Color(0xff6750a4).value),
isDark: false,
contrastLevel: 1.0);
sourceColorHct: Hct.fromInt(const Color(0xff6750a4).value),
isDark: false,
contrastLevel: 1.0,
);
final ColorScheme appScheme = app.theme!.colorScheme;
expect(appScheme.primary.value,
MaterialDynamicColors.primary.getArgb(highContrastScheme));
expect(appScheme.onPrimary.value,
MaterialDynamicColors.onPrimary.getArgb(highContrastScheme));
expect(appScheme.primaryContainer.value,
MaterialDynamicColors.primaryContainer.getArgb(highContrastScheme));
expect(appScheme.onPrimaryContainer.value,
MaterialDynamicColors.onPrimaryContainer.getArgb(highContrastScheme));
expect(appScheme.primaryFixed.value,
MaterialDynamicColors.primaryFixed.getArgb(highContrastScheme));
expect(appScheme.primaryFixedDim.value,
MaterialDynamicColors.primaryFixedDim.getArgb(highContrastScheme));
expect(appScheme.onPrimaryFixed.value,
MaterialDynamicColors.onPrimaryFixed.getArgb(highContrastScheme));
expect(appScheme.primary.value, MaterialDynamicColors.primary.getArgb(highContrastScheme));
expect(appScheme.onPrimary.value, MaterialDynamicColors.onPrimary.getArgb(highContrastScheme));
expect(
appScheme.onPrimaryFixedVariant.value,
MaterialDynamicColors.onPrimaryFixedVariant
.getArgb(highContrastScheme));
expect(appScheme.secondary.value,
MaterialDynamicColors.secondary.getArgb(highContrastScheme));
expect(appScheme.onSecondary.value,
MaterialDynamicColors.onSecondary.getArgb(highContrastScheme));
expect(appScheme.secondaryContainer.value,
MaterialDynamicColors.secondaryContainer.getArgb(highContrastScheme));
expect(appScheme.onSecondaryContainer.value,
MaterialDynamicColors.onSecondaryContainer.getArgb(highContrastScheme));
expect(appScheme.secondaryFixed.value,
MaterialDynamicColors.secondaryFixed.getArgb(highContrastScheme));
expect(appScheme.secondaryFixedDim.value,
MaterialDynamicColors.secondaryFixedDim.getArgb(highContrastScheme));
expect(appScheme.onSecondaryFixed.value,
MaterialDynamicColors.onSecondaryFixed.getArgb(highContrastScheme));
appScheme.primaryContainer.value,
MaterialDynamicColors.primaryContainer.getArgb(highContrastScheme),
);
expect(
appScheme.onSecondaryFixedVariant.value,
MaterialDynamicColors.onSecondaryFixedVariant
.getArgb(highContrastScheme));
expect(appScheme.tertiary.value,
MaterialDynamicColors.tertiary.getArgb(highContrastScheme));
expect(appScheme.onTertiary.value,
MaterialDynamicColors.onTertiary.getArgb(highContrastScheme));
expect(appScheme.tertiaryContainer.value,
MaterialDynamicColors.tertiaryContainer.getArgb(highContrastScheme));
expect(appScheme.onTertiaryContainer.value,
MaterialDynamicColors.onTertiaryContainer.getArgb(highContrastScheme));
expect(appScheme.tertiaryFixed.value,
MaterialDynamicColors.tertiaryFixed.getArgb(highContrastScheme));
expect(appScheme.tertiaryFixedDim.value,
MaterialDynamicColors.tertiaryFixedDim.getArgb(highContrastScheme));
expect(appScheme.onTertiaryFixed.value,
MaterialDynamicColors.onTertiaryFixed.getArgb(highContrastScheme));
appScheme.onPrimaryContainer.value,
MaterialDynamicColors.onPrimaryContainer.getArgb(highContrastScheme),
);
expect(
appScheme.onTertiaryFixedVariant.value,
MaterialDynamicColors.onTertiaryFixedVariant
.getArgb(highContrastScheme));
expect(appScheme.error.value,
MaterialDynamicColors.error.getArgb(highContrastScheme));
expect(appScheme.onError.value,
MaterialDynamicColors.onError.getArgb(highContrastScheme));
expect(appScheme.errorContainer.value,
MaterialDynamicColors.errorContainer.getArgb(highContrastScheme));
expect(appScheme.onErrorContainer.value,
MaterialDynamicColors.onErrorContainer.getArgb(highContrastScheme));
expect(appScheme.background.value,
MaterialDynamicColors.background.getArgb(highContrastScheme));
expect(appScheme.onBackground.value,
MaterialDynamicColors.onBackground.getArgb(highContrastScheme));
expect(appScheme.surface.value,
MaterialDynamicColors.surface.getArgb(highContrastScheme));
expect(appScheme.surfaceDim.value,
MaterialDynamicColors.surfaceDim.getArgb(highContrastScheme));
expect(appScheme.surfaceBright.value,
MaterialDynamicColors.surfaceBright.getArgb(highContrastScheme));
appScheme.primaryFixed.value,
MaterialDynamicColors.primaryFixed.getArgb(highContrastScheme),
);
expect(
appScheme.surfaceContainerLowest.value,
MaterialDynamicColors.surfaceContainerLowest
.getArgb(highContrastScheme));
expect(appScheme.surfaceContainerLow.value,
MaterialDynamicColors.surfaceContainerLow.getArgb(highContrastScheme));
expect(appScheme.surfaceContainer.value,
MaterialDynamicColors.surfaceContainer.getArgb(highContrastScheme));
expect(appScheme.surfaceContainerHigh.value,
MaterialDynamicColors.surfaceContainerHigh.getArgb(highContrastScheme));
appScheme.primaryFixedDim.value,
MaterialDynamicColors.primaryFixedDim.getArgb(highContrastScheme),
);
expect(
appScheme.surfaceContainerHighest.value,
MaterialDynamicColors.surfaceContainerHighest
.getArgb(highContrastScheme));
expect(appScheme.onSurface.value,
MaterialDynamicColors.onSurface.getArgb(highContrastScheme));
expect(appScheme.surfaceVariant.value,
MaterialDynamicColors.surfaceVariant.getArgb(highContrastScheme));
expect(appScheme.onSurfaceVariant.value,
MaterialDynamicColors.onSurfaceVariant.getArgb(highContrastScheme));
expect(appScheme.outline.value,
MaterialDynamicColors.outline.getArgb(highContrastScheme));
expect(appScheme.outlineVariant.value,
MaterialDynamicColors.outlineVariant.getArgb(highContrastScheme));
expect(appScheme.shadow.value,
MaterialDynamicColors.shadow.getArgb(highContrastScheme));
expect(appScheme.scrim.value,
MaterialDynamicColors.scrim.getArgb(highContrastScheme));
expect(appScheme.inverseSurface.value,
MaterialDynamicColors.inverseSurface.getArgb(highContrastScheme));
expect(appScheme.onInverseSurface.value,
MaterialDynamicColors.inverseOnSurface.getArgb(highContrastScheme));
expect(appScheme.inversePrimary.value,
MaterialDynamicColors.inversePrimary.getArgb(highContrastScheme));
appScheme.onPrimaryFixed.value,
MaterialDynamicColors.onPrimaryFixed.getArgb(highContrastScheme),
);
expect(
appScheme.onPrimaryFixedVariant.value,
MaterialDynamicColors.onPrimaryFixedVariant.getArgb(highContrastScheme),
);
expect(appScheme.secondary.value, MaterialDynamicColors.secondary.getArgb(highContrastScheme));
expect(
appScheme.onSecondary.value,
MaterialDynamicColors.onSecondary.getArgb(highContrastScheme),
);
expect(
appScheme.secondaryContainer.value,
MaterialDynamicColors.secondaryContainer.getArgb(highContrastScheme),
);
expect(
appScheme.onSecondaryContainer.value,
MaterialDynamicColors.onSecondaryContainer.getArgb(highContrastScheme),
);
expect(
appScheme.secondaryFixed.value,
MaterialDynamicColors.secondaryFixed.getArgb(highContrastScheme),
);
expect(
appScheme.secondaryFixedDim.value,
MaterialDynamicColors.secondaryFixedDim.getArgb(highContrastScheme),
);
expect(
appScheme.onSecondaryFixed.value,
MaterialDynamicColors.onSecondaryFixed.getArgb(highContrastScheme),
);
expect(
appScheme.onSecondaryFixedVariant.value,
MaterialDynamicColors.onSecondaryFixedVariant.getArgb(highContrastScheme),
);
expect(appScheme.tertiary.value, MaterialDynamicColors.tertiary.getArgb(highContrastScheme));
expect(
appScheme.onTertiary.value,
MaterialDynamicColors.onTertiary.getArgb(highContrastScheme),
);
expect(
appScheme.tertiaryContainer.value,
MaterialDynamicColors.tertiaryContainer.getArgb(highContrastScheme),
);
expect(
appScheme.onTertiaryContainer.value,
MaterialDynamicColors.onTertiaryContainer.getArgb(highContrastScheme),
);
expect(
appScheme.tertiaryFixed.value,
MaterialDynamicColors.tertiaryFixed.getArgb(highContrastScheme),
);
expect(
appScheme.tertiaryFixedDim.value,
MaterialDynamicColors.tertiaryFixedDim.getArgb(highContrastScheme),
);
expect(
appScheme.onTertiaryFixed.value,
MaterialDynamicColors.onTertiaryFixed.getArgb(highContrastScheme),
);
expect(
appScheme.onTertiaryFixedVariant.value,
MaterialDynamicColors.onTertiaryFixedVariant.getArgb(highContrastScheme),
);
expect(appScheme.error.value, MaterialDynamicColors.error.getArgb(highContrastScheme));
expect(appScheme.onError.value, MaterialDynamicColors.onError.getArgb(highContrastScheme));
expect(
appScheme.errorContainer.value,
MaterialDynamicColors.errorContainer.getArgb(highContrastScheme),
);
expect(
appScheme.onErrorContainer.value,
MaterialDynamicColors.onErrorContainer.getArgb(highContrastScheme),
);
expect(
appScheme.background.value,
MaterialDynamicColors.background.getArgb(highContrastScheme),
);
expect(
appScheme.onBackground.value,
MaterialDynamicColors.onBackground.getArgb(highContrastScheme),
);
expect(appScheme.surface.value, MaterialDynamicColors.surface.getArgb(highContrastScheme));
expect(
appScheme.surfaceDim.value,
MaterialDynamicColors.surfaceDim.getArgb(highContrastScheme),
);
expect(
appScheme.surfaceBright.value,
MaterialDynamicColors.surfaceBright.getArgb(highContrastScheme),
);
expect(
appScheme.surfaceContainerLowest.value,
MaterialDynamicColors.surfaceContainerLowest.getArgb(highContrastScheme),
);
expect(
appScheme.surfaceContainerLow.value,
MaterialDynamicColors.surfaceContainerLow.getArgb(highContrastScheme),
);
expect(
appScheme.surfaceContainer.value,
MaterialDynamicColors.surfaceContainer.getArgb(highContrastScheme),
);
expect(
appScheme.surfaceContainerHigh.value,
MaterialDynamicColors.surfaceContainerHigh.getArgb(highContrastScheme),
);
expect(
appScheme.surfaceContainerHighest.value,
MaterialDynamicColors.surfaceContainerHighest.getArgb(highContrastScheme),
);
expect(appScheme.onSurface.value, MaterialDynamicColors.onSurface.getArgb(highContrastScheme));
expect(
appScheme.surfaceVariant.value,
MaterialDynamicColors.surfaceVariant.getArgb(highContrastScheme),
);
expect(
appScheme.onSurfaceVariant.value,
MaterialDynamicColors.onSurfaceVariant.getArgb(highContrastScheme),
);
expect(appScheme.outline.value, MaterialDynamicColors.outline.getArgb(highContrastScheme));
expect(
appScheme.outlineVariant.value,
MaterialDynamicColors.outlineVariant.getArgb(highContrastScheme),
);
expect(appScheme.shadow.value, MaterialDynamicColors.shadow.getArgb(highContrastScheme));
expect(appScheme.scrim.value, MaterialDynamicColors.scrim.getArgb(highContrastScheme));
expect(
appScheme.inverseSurface.value,
MaterialDynamicColors.inverseSurface.getArgb(highContrastScheme),
);
expect(
appScheme.onInverseSurface.value,
MaterialDynamicColors.inverseOnSurface.getArgb(highContrastScheme),
);
expect(
appScheme.inversePrimary.value,
MaterialDynamicColors.inversePrimary.getArgb(highContrastScheme),
);
});
testWidgets('Each A11y Assessments page has a unique page title.', (WidgetTester tester) async {
final List<MethodCall> log = <MethodCall>[];
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (MethodCall methodCall) async {
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.platform, (
MethodCall methodCall,
) async {
if (methodCall.method == 'SystemChrome.setApplicationSwitcherDescription') {
log.add(methodCall);
}
return null;
});
await tester.pumpWidget(Title(
color: const Color(0xFF00FF00),
title: 'Accessibility Assessments',
child: Container(),
));
expect(log[0], isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'Accessibility Assessments', 'primaryColor': 4278255360},
));
await tester.pumpWidget(
Title(color: const Color(0xFF00FF00), title: 'Accessibility Assessments', child: Container()),
);
expect(
log[0],
isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{
'label': 'Accessibility Assessments',
'primaryColor': 4278255360,
},
),
);
await pumpsUseCase(tester, AutoCompleteUseCase());
expect(log[2], isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'AutoComplete', 'primaryColor': 4284960932},
));
expect(
log[2],
isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'AutoComplete', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, ActionChipUseCase());
expect(log[4], isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'ActionChip', 'primaryColor': 4284960932},
));
expect(
log[4],
isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'ActionChip', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, BadgeUseCase());
expect(log[6], isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'Badge', 'primaryColor': 4284960932},
));
expect(
log[6],
isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'Badge', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, CardUseCase());
expect(log[8], isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'Card', 'primaryColor': 4284960932},
));
expect(
log[8],
isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'Card', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, CheckBoxListTile());
expect(log[10], isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'CheckBoxListTile', 'primaryColor': 4284960932},
));
expect(
log[10],
isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'CheckBoxListTile', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, DatePickerUseCase());
expect(log[12], isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'DatePicker', 'primaryColor': 4284960932},
));
expect(
log[12],
isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'DatePicker', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, DialogUseCase());
expect(log[14], isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'Dialog', 'primaryColor': 4284960932},
));
expect(
log[14],
isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'Dialog', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, ExpansionTileUseCase());
expect(log[16], isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'ExpansionTile', 'primaryColor': 4284960932},
));
expect(
log[16],
isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'ExpansionTile', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, MaterialBannerUseCase());
expect(log[18], isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'MaterialBanner', 'primaryColor': 4284960932},
));
expect(
log[18],
isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'MaterialBanner', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, NavigationBarUseCase());
expect(log[20], isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'NavigationBar', 'primaryColor': 4284960932},
));
expect(
log[20],
isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'NavigationBar', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, RadioListTileUseCase());
expect(log[22], isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'RadioListTile', 'primaryColor': 4284960932},
));
expect(
log[22],
isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'RadioListTile', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, SliderUseCase());
expect(log[24], isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'Slider', 'primaryColor': 4284960932},
));
expect(
log[24],
isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'Slider', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, SnackBarUseCase());
expect(log[26], isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'SnackBar', 'primaryColor': 4284960932},
));
expect(
log[26],
isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'SnackBar', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, SwitchListTileUseCase());
expect(log[28], isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'SwitchListTile', 'primaryColor': 4284960932},
));
expect(
log[28],
isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'SwitchListTile', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, TextButtonUseCase());
expect(log[30], isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'TextButton', 'primaryColor': 4284960932},
));
expect(
log[30],
isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'TextButton', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, TextFieldUseCase());
expect(log[32], isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'TextField', 'primaryColor': 4284960932},
));
expect(
log[32],
isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'TextField', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, TextFieldPasswordUseCase());
expect(log[34], isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'TextField password', 'primaryColor': 4284960932},
));
expect(
log[34],
isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'TextField password', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, NavigationDrawerUseCase());
expect(log[36], isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'NavigationDrawer', 'primaryColor': 4284960932},
));
expect(
log[36],
isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'NavigationDrawer', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, NavigationRailUseCase());
expect(log[38], isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'NavigationRail', 'primaryColor': 4284960932},
));
expect(
log[38],
isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'NavigationRail', 'primaryColor': 4284960932},
),
);
await pumpsUseCase(tester, DrawerUseCase());
expect(log[40], isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'drawer', 'primaryColor': 4284960932},
));
expect(
log[40],
isMethodCall(
'SystemChrome.setApplicationSwitcherDescription',
arguments: <String, dynamic>{'label': 'drawer', 'primaryColor': 4284960932},
),
);
});
testWidgets('a11y assessments home page has one h1 tag', (WidgetTester tester) async {

View File

@ -38,7 +38,9 @@ void main() {
await tester.tap(find.byType(TextButton));
final ElevatedButton showButtonFinder = tester.widget<ElevatedButton>(find.byType(ElevatedButton));
final ElevatedButton showButtonFinder = tester.widget<ElevatedButton>(
find.byType(ElevatedButton),
);
expect(showButtonFinder.focusNode!.hasFocus, isTrue);
});

View File

@ -8,8 +8,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'test_utils.dart';
void main() {
testWidgets('radio list tile use-case renders radio buttons',
(WidgetTester tester) async {
testWidgets('radio list tile use-case renders radio buttons', (WidgetTester tester) async {
await pumpsUseCase(tester, RadioListTileUseCase());
expect(find.text('Lafayette'), findsOneWidget);
expect(find.text('Jefferson'), findsOneWidget);

View File

@ -16,14 +16,12 @@ void main() {
await tester.tapAt(tester.getCenter(find.byType(Slider)));
await tester.pumpAndSettle();
final MainWidgetState state =
tester.state<MainWidgetState>(find.byType(MainWidget));
final MainWidgetState state = tester.state<MainWidgetState>(find.byType(MainWidget));
expect(state.currentSliderValue, 60);
});
testWidgets('slider semantics wrapper exists', (WidgetTester tester) async {
await pumpsUseCase(tester, SliderUseCase());
final Finder semanticsWidget =
find.bySemanticsLabel('Accessibility Test Slider');
final Finder semanticsWidget = find.bySemanticsLabel('Accessibility Test Slider');
expect(semanticsWidget, findsOneWidget);
});

View File

@ -7,11 +7,13 @@ import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
Future<void> pumpsUseCase(WidgetTester tester, UseCase useCase) async {
await tester.pumpWidget(MaterialApp(
home: Builder(
builder: (BuildContext context) {
return useCase.buildWithTitle(context);
},
await tester.pumpWidget(
MaterialApp(
home: Builder(
builder: (BuildContext context) {
return useCase.buildWithTitle(context);
},
),
),
));
);
}

View File

@ -31,8 +31,7 @@ void main() {
}
});
testWidgets('text field passwords do not have hint text',
(WidgetTester tester) async {
testWidgets('text field passwords do not have hint text', (WidgetTester tester) async {
await pumpsUseCase(tester, TextFieldPasswordUseCase());
expect(find.byType(TextField), findsExactly(2));

View File

@ -31,20 +31,21 @@ void main() {
}
});
testWidgets('font size increase does not ellipsize hint text',
(WidgetTester tester) async {
testWidgets('font size increase does not ellipsize hint text', (WidgetTester tester) async {
await pumpsUseCase(tester, TextFieldUseCase());
await tester.pumpWidget(MaterialApp(
home: MediaQuery.withClampedTextScaling(
minScaleFactor: 3,
maxScaleFactor: 3,
child: Builder(
builder: (BuildContext context) {
return TextFieldUseCase().build(context);
},
await tester.pumpWidget(
MaterialApp(
home: MediaQuery.withClampedTextScaling(
minScaleFactor: 3,
maxScaleFactor: 3,
child: Builder(
builder: (BuildContext context) {
return TextFieldUseCase().build(context);
},
),
),
),
));
);
// Test the enabled text field
{
final Finder finder = find.byKey(const Key('enabled text field'));
@ -60,8 +61,7 @@ void main() {
await pumpsUseCase(tester, TextFieldUseCase());
const String textFieldLabel = 'Input field with suffix @gmail.com';
final Finder semanticsWidgets =
find.bySemanticsLabel(RegExp(textFieldLabel));
final Finder semanticsWidgets = find.bySemanticsLabel(RegExp(textFieldLabel));
expect(semanticsWidgets, findsExactly(2));
});

View File

@ -5,5 +5,5 @@
import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
void main() {
test('trivial', () { });
test('trivial', () {});
}

View File

@ -5,5 +5,5 @@
import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
void main() {
test('trivial', () { });
test('trivial', () {});
}

View File

@ -14,26 +14,91 @@ import 'package:platform/platform.dart';
// 1x1 colored pixel
const List<int> _kFailPngBytes = <int>[
137, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0,
13, 73, 72, 68, 82, 0, 0, 0, 1, 0, 0, 0, 1, 8, 6, 0, 0, 0, 31, 21, 196, 137,
0, 0, 0, 13, 73, 68, 65, 84, 120, 1, 99, 249, 207, 240, 255, 63, 0, 7, 18, 3,
2, 164, 147, 160, 197, 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130,
137,
80,
78,
71,
13,
10,
26,
10,
0,
0,
0,
13,
73,
72,
68,
82,
0,
0,
0,
1,
0,
0,
0,
1,
8,
6,
0,
0,
0,
31,
21,
196,
137,
0,
0,
0,
13,
73,
68,
65,
84,
120,
1,
99,
249,
207,
240,
255,
63,
0,
7,
18,
3,
2,
164,
147,
160,
197,
0,
0,
0,
0,
73,
69,
78,
68,
174,
66,
96,
130,
];
void main() {
final List<String> log = <String>[];
final MemoryFileSystem fs = MemoryFileSystem();
final Directory basedir = fs.directory('flutter/test/library/')
..createSync(recursive: true);
final FakeSkiaGoldClient fakeSkiaClient = FakeSkiaGoldClient()
..expectationForTestValues['flutter.new_golden_test.1'] = '';
final Directory basedir = fs.directory('flutter/test/library/')..createSync(recursive: true);
final FakeSkiaGoldClient fakeSkiaClient =
FakeSkiaGoldClient()..expectationForTestValues['flutter.new_golden_test.1'] = '';
final FlutterLocalFileComparator comparator = FlutterLocalFileComparator(
basedir.uri,
fakeSkiaClient,
fs: fs,
platform: FakePlatform(
environment: <String, String>{'FLUTTER_ROOT': '/flutter'},
operatingSystem: 'macos'
operatingSystem: 'macos',
),
log: log.add,
);
@ -48,9 +113,9 @@ void main() {
isTrue,
);
const String expectation =
'No expectations provided by Skia Gold for test: library.flutter.new_golden_test.1.png. '
'This may be a new test. If this is an unexpected result, check https://flutter-gold.skia.org.\n'
'Validate image output found at flutter/test/library/';
'No expectations provided by Skia Gold for test: library.flutter.new_golden_test.1.png. '
'This may be a new test. If this is an unexpected result, check https://flutter-gold.skia.org.\n'
'Validate image output found at flutter/test/library/';
expect(log, const <String>[expectation]);
});
@ -64,9 +129,9 @@ void main() {
isTrue,
);
const String expectation =
'No expectations provided by Skia Gold for test: library.flutter.new_golden_test.2.png. '
'This may be a new test. If this is an unexpected result, check https://flutter-gold.skia.org.\n'
'Validate image output found at flutter/test/library/';
'No expectations provided by Skia Gold for test: library.flutter.new_golden_test.2.png. '
'This may be a new test. If this is an unexpected result, check https://flutter-gold.skia.org.\n'
'Validate image output found at flutter/test/library/';
expect(log, const <String>[expectation]);
});
}

View File

@ -8,12 +8,6 @@ import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Rendering Error', (WidgetTester tester) async {
// Assets can load with its package name.
await tester.pumpWidget(
Image.asset('icon/test.png',
width: 54,
height: 54,
fit: BoxFit.none,
),
);
await tester.pumpWidget(Image.asset('icon/test.png', width: 54, height: 54, fit: BoxFit.none));
});
}

View File

@ -12,9 +12,7 @@ void main() {
MaterialApp(
theme: ThemeData(useMaterial3: false),
home: Scaffold(
appBar: AppBar(
title: const Text('RenderFlex OverFlow'),
),
appBar: AppBar(title: const Text('RenderFlex OverFlow')),
body: const SizedBox(
width: 400.0,
child: Row(
@ -30,7 +28,7 @@ void main() {
'do eiusmod tempor incididunt ut labore et dolore magna '
'aliqua. Ut enim ad minim veniam, quis nostrud '
'exercitation ullamco laboris nisi ut aliquip ex ea '
'commodo consequat.'
'commodo consequat.',
),
],
),
@ -38,7 +36,7 @@ void main() {
),
),
),
)
),
);
});
}

View File

@ -9,11 +9,7 @@ void main() {
testWidgets('Rendering Error', (WidgetTester tester) async {
// this should fail
await tester.pumpWidget(
CustomScrollView(
slivers: <Widget>[
SliverToBoxAdapter(child: Container()),
],
)
CustomScrollView(slivers: <Widget>[SliverToBoxAdapter(child: Container())]),
);
});
}

View File

@ -9,11 +9,7 @@ void main() {
testWidgets('Rendering Error', (WidgetTester tester) async {
// this should fail
await tester.pumpWidget(
CustomScrollView(
slivers: <Widget>[
SliverToBoxAdapter(child: Container()),
],
)
CustomScrollView(slivers: <Widget>[SliverToBoxAdapter(child: Container())]),
);
});
}

View File

@ -9,7 +9,9 @@ import 'package:flutter_test/flutter_test.dart';
class TestTestBinding extends AutomatedTestWidgetsFlutterBinding {
@override
DebugPrintCallback get debugPrintOverride => testPrint;
static void testPrint(String? message, { int? wrapWidth }) { print(message); }
static void testPrint(String? message, {int? wrapWidth}) {
print(message);
}
}
Future<void> guardedHelper(WidgetTester tester) {

View File

@ -8,7 +8,9 @@ import 'package:flutter_test/flutter_test.dart';
class TestTestBinding extends AutomatedTestWidgetsFlutterBinding {
@override
DebugPrintCallback get debugPrintOverride => testPrint;
static void testPrint(String? message, { int? wrapWidth }) { print(message); }
static void testPrint(String? message, {int? wrapWidth}) {
print(message);
}
}
Future<void> helperFunction(WidgetTester tester) async {
@ -17,7 +19,9 @@ Future<void> helperFunction(WidgetTester tester) async {
void main() {
TestTestBinding();
testWidgets('TestAsyncUtils - handling unguarded async helper functions', (WidgetTester tester) async {
testWidgets('TestAsyncUtils - handling unguarded async helper functions', (
WidgetTester tester,
) async {
helperFunction(tester);
helperFunction(tester);
// this should fail

View File

@ -8,9 +8,13 @@ import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('Does flutter_test catch leaking tickers?', (WidgetTester tester) async {
Ticker((Duration duration) { }).start();
Ticker((Duration duration) {}).start();
final ByteData? message = const StringCodec().encodeMessage('AppLifecycleState.paused');
await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/lifecycle', message, (_) {});
await tester.binding.defaultBinaryMessenger.handlePlatformMessage(
'flutter/lifecycle',
message,
(_) {},
);
});
}

View File

@ -5,5 +5,5 @@
import 'package:test/test.dart' hide TypeMatcher, isInstanceOf;
void main() {
test('trivial', () { });
test('trivial', () {});
}

View File

@ -13,7 +13,9 @@ void main() {
test('test smoke test -- this test should fail', () async {
if (system.Process.killPid(system.pid, system.ProcessSignal.sigsegv)) {
print('system.Process.killPid returned before the process ended!');
print('Sleeping for a few seconds just in case signal delivery is delayed or our signal handler is being slow...');
print(
'Sleeping for a few seconds just in case signal delivery is delayed or our signal handler is being slow...',
);
system.sleep(const Duration(seconds: 10)); // don't sleep too much, we must not time out
} else {
print('system.Process.killPid reports that the SIGSEGV signal was not delivered!');

View File

@ -6,7 +6,5 @@ import 'package:flutter/widgets.dart';
import 'src/app.dart';
void main() {
runApp(
const ComplexLayoutApp()
);
runApp(const ComplexLayoutApp());
}

View File

@ -6,7 +6,5 @@ import 'package:flutter/widgets.dart';
import 'src/app.dart';
void main() {
runApp(
const ComplexLayoutApp(badScroll: true)
);
runApp(const ComplexLayoutApp(badScroll: true));
}

View File

@ -15,7 +15,8 @@ class ComplexLayoutApp extends StatefulWidget {
@override
ComplexLayoutAppState createState() => ComplexLayoutAppState();
static ComplexLayoutAppState? of(BuildContext context) => context.findAncestorStateOfType<ComplexLayoutAppState>();
static ComplexLayoutAppState? of(BuildContext context) =>
context.findAncestorStateOfType<ComplexLayoutAppState>();
}
class ComplexLayoutAppState extends State<ComplexLayoutApp> {
@ -24,7 +25,11 @@ class ComplexLayoutAppState extends State<ComplexLayoutApp> {
return MaterialApp(
theme: lightTheme ? ThemeData.light() : ThemeData.dark(),
title: 'Advanced Layout',
home: scrollMode == ScrollMode.complex ? ComplexLayout(badScroll: widget.badScroll) : const TileScrollLayout());
home:
scrollMode == ScrollMode.complex
? ComplexLayout(badScroll: widget.badScroll)
: const TileScrollLayout(),
);
}
bool _lightTheme = true;
@ -51,7 +56,7 @@ class ComplexLayoutAppState extends State<ComplexLayoutApp> {
}
class TileScrollLayout extends StatelessWidget {
const TileScrollLayout({ super.key });
const TileScrollLayout({super.key});
@override
Widget build(BuildContext context) {
@ -77,14 +82,15 @@ class TileScrollLayout extends StatelessWidget {
}
class ComplexLayout extends StatefulWidget {
const ComplexLayout({ super.key, required this.badScroll });
const ComplexLayout({super.key, required this.badScroll});
final bool badScroll;
@override
ComplexLayoutState createState() => ComplexLayoutState();
static ComplexLayoutState? of(BuildContext context) => context.findAncestorStateOfType<ComplexLayoutState>();
static ComplexLayoutState? of(BuildContext context) =>
context.findAncestorStateOfType<ComplexLayoutState>();
}
class ComplexLayoutState extends State<ComplexLayout> {
@ -92,7 +98,7 @@ class ComplexLayoutState extends State<ComplexLayout> {
Widget build(BuildContext context) {
Widget body = ListView.builder(
key: const Key('complex-scroll'), // this key is used by the driver test
controller: ScrollController(), // So that the scroll offset can be tracked
controller: ScrollController(), // So that the scroll offset can be tracked
itemCount: widget.badScroll ? 500 : null,
shrinkWrap: widget.badScroll,
itemBuilder: (BuildContext context, int index) {
@ -104,10 +110,7 @@ class ComplexLayoutState extends State<ComplexLayout> {
},
);
if (widget.badScroll) {
body = ListView(
key: const Key('complex-scroll-bad'),
children: <Widget>[body],
);
body = ListView(key: const Key('complex-scroll-bad'), children: <Widget>[body]);
}
return Scaffold(
@ -124,12 +127,7 @@ class ComplexLayoutState extends State<ComplexLayout> {
const TopBarMenu(),
],
),
body: Column(
children: <Widget>[
Expanded(child: body),
const BottomBar(),
],
),
body: Column(children: <Widget>[Expanded(child: body), const BottomBar()]),
drawer: const GalleryDrawer(),
);
}
@ -141,49 +139,52 @@ class TopBarMenu extends StatelessWidget {
@override
Widget build(BuildContext context) {
return PopupMenuButton<String>(
onSelected: (String value) { print('Selected: $value'); },
itemBuilder: (BuildContext context) => <PopupMenuItem<String>>[
const PopupMenuItem<String>(
value: 'Friends',
child: MenuItemWithIcon(Icons.people, 'Friends', '5 new'),
),
const PopupMenuItem<String>(
value: 'Events',
child: MenuItemWithIcon(Icons.event, 'Events', '12 upcoming'),
),
const PopupMenuItem<String>(
value: 'Events',
child: MenuItemWithIcon(Icons.group, 'Groups', '14'),
),
const PopupMenuItem<String>(
value: 'Events',
child: MenuItemWithIcon(Icons.image, 'Pictures', '12'),
),
const PopupMenuItem<String>(
value: 'Events',
child: MenuItemWithIcon(Icons.near_me, 'Nearby', '33'),
),
const PopupMenuItem<String>(
value: 'Friends',
child: MenuItemWithIcon(Icons.people, 'Friends', '5'),
),
const PopupMenuItem<String>(
value: 'Events',
child: MenuItemWithIcon(Icons.event, 'Events', '12'),
),
const PopupMenuItem<String>(
value: 'Events',
child: MenuItemWithIcon(Icons.group, 'Groups', '14'),
),
const PopupMenuItem<String>(
value: 'Events',
child: MenuItemWithIcon(Icons.image, 'Pictures', '12'),
),
const PopupMenuItem<String>(
value: 'Events',
child: MenuItemWithIcon(Icons.near_me, 'Nearby', '33'),
),
],
onSelected: (String value) {
print('Selected: $value');
},
itemBuilder:
(BuildContext context) => <PopupMenuItem<String>>[
const PopupMenuItem<String>(
value: 'Friends',
child: MenuItemWithIcon(Icons.people, 'Friends', '5 new'),
),
const PopupMenuItem<String>(
value: 'Events',
child: MenuItemWithIcon(Icons.event, 'Events', '12 upcoming'),
),
const PopupMenuItem<String>(
value: 'Events',
child: MenuItemWithIcon(Icons.group, 'Groups', '14'),
),
const PopupMenuItem<String>(
value: 'Events',
child: MenuItemWithIcon(Icons.image, 'Pictures', '12'),
),
const PopupMenuItem<String>(
value: 'Events',
child: MenuItemWithIcon(Icons.near_me, 'Nearby', '33'),
),
const PopupMenuItem<String>(
value: 'Friends',
child: MenuItemWithIcon(Icons.people, 'Friends', '5'),
),
const PopupMenuItem<String>(
value: 'Events',
child: MenuItemWithIcon(Icons.event, 'Events', '12'),
),
const PopupMenuItem<String>(
value: 'Events',
child: MenuItemWithIcon(Icons.group, 'Groups', '14'),
),
const PopupMenuItem<String>(
value: 'Events',
child: MenuItemWithIcon(Icons.image, 'Pictures', '12'),
),
const PopupMenuItem<String>(
value: 'Events',
child: MenuItemWithIcon(Icons.near_me, 'Nearby', '33'),
),
],
);
}
}
@ -200,10 +201,7 @@ class MenuItemWithIcon extends StatelessWidget {
return Row(
children: <Widget>[
Icon(icon),
Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: Text(title),
),
Padding(padding: const EdgeInsets.only(left: 8.0, right: 8.0), child: Text(title)),
Text(subtitle, style: Theme.of(context).textTheme.bodySmall),
],
);
@ -223,10 +221,7 @@ class FancyImageItem extends StatelessWidget {
const ItemDescription(),
const ItemImageBox(),
const InfoBar(),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 8.0),
child: Divider(),
),
const Padding(padding: EdgeInsets.symmetric(horizontal: 8.0), child: Divider()),
const IconBar(),
const FatDivider(),
],
@ -245,10 +240,7 @@ class FancyGalleryItem extends StatelessWidget {
const UserHeader('Ali Connors'),
ItemGalleryBox(index),
const InfoBar(),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 8.0),
child: Divider(),
),
const Padding(padding: EdgeInsets.symmetric(horizontal: 8.0), child: Divider()),
const IconBar(),
const FatDivider(),
],
@ -306,7 +298,9 @@ class IconWithText extends StatelessWidget {
children: <Widget>[
IconButton(
icon: Icon(icon),
onPressed: () { print('Pressed $title button'); },
onPressed: () {
print('Pressed $title button');
},
),
Text(title),
],
@ -348,10 +342,7 @@ class FatDivider extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
height: 8.0,
color: Theme.of(context).dividerColor,
);
return Container(height: 8.0, color: Theme.of(context).dividerColor);
}
}
@ -379,18 +370,24 @@ class UserHeader extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
RichText(text: TextSpan(
style: Theme.of(context).textTheme.bodyMedium,
children: <TextSpan>[
TextSpan(text: userName, style: const TextStyle(fontWeight: FontWeight.bold)),
const TextSpan(text: ' shared a new '),
const TextSpan(text: 'photo', style: TextStyle(fontWeight: FontWeight.bold)),
],
)),
RichText(
text: TextSpan(
style: Theme.of(context).textTheme.bodyMedium,
children: <TextSpan>[
TextSpan(text: userName, style: const TextStyle(fontWeight: FontWeight.bold)),
const TextSpan(text: ' shared a new '),
const TextSpan(text: 'photo', style: TextStyle(fontWeight: FontWeight.bold)),
],
),
),
Row(
children: <Widget>[
Text('Yesterday at 11:55 • ', style: Theme.of(context).textTheme.bodySmall),
Icon(Icons.people, size: 16.0, color: Theme.of(context).textTheme.bodySmall!.color),
Icon(
Icons.people,
size: 16.0,
color: Theme.of(context).textTheme.bodySmall!.color,
),
],
),
],
@ -410,7 +407,9 @@ class ItemDescription extends StatelessWidget {
Widget build(BuildContext context) {
return const Padding(
padding: EdgeInsets.all(8.0),
child: Text('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.'),
child: Text(
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
),
);
}
}
@ -431,7 +430,9 @@ class ItemImageBox extends StatelessWidget {
const SizedBox(
height: 230.0,
child: Image(
image: AssetImage('packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png')
image: AssetImage(
'packages/flutter_gallery_assets/places/india_chettinad_silk_maker.png',
),
),
),
Theme(
@ -441,11 +442,15 @@ class ItemImageBox extends StatelessWidget {
children: <Widget>[
IconButton(
icon: const Icon(Icons.edit),
onPressed: () { print('Pressed edit button'); },
onPressed: () {
print('Pressed edit button');
},
),
IconButton(
icon: const Icon(Icons.zoom_in),
onPressed: () { print('Pressed zoom button'); },
onPressed: () {
print('Pressed zoom button');
},
),
],
),
@ -463,9 +468,7 @@ class ItemImageBox extends StatelessWidget {
text: const TextSpan(
style: TextStyle(color: Colors.white),
children: <TextSpan>[
TextSpan(
text: 'Photo by '
),
TextSpan(text: 'Photo by '),
TextSpan(
style: TextStyle(fontWeight: FontWeight.bold),
text: 'Chris Godley',
@ -476,8 +479,7 @@ class ItemImageBox extends StatelessWidget {
),
),
],
)
,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
@ -503,9 +505,7 @@ class ItemGalleryBox extends StatelessWidget {
@override
Widget build(BuildContext context) {
final List<String> tabNames = <String>[
'A', 'B', 'C', 'D',
];
final List<String> tabNames = <String>['A', 'B', 'C', 'D'];
return SizedBox(
height: 200.0,
@ -515,46 +515,56 @@ class ItemGalleryBox extends StatelessWidget {
children: <Widget>[
Expanded(
child: TabBarView(
children: tabNames.map<Widget>((String tabName) {
return Container(
key: PageStorageKey<String>(tabName),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
child: Column(
children: <Widget>[
Expanded(
child: ColoredBox(
color: Theme.of(context).primaryColor,
child: Center(
child: Text(tabName, style: Theme.of(context).textTheme.headlineSmall!.copyWith(color: Colors.white)),
),
),
),
Row(
children:
tabNames.map<Widget>((String tabName) {
return Container(
key: PageStorageKey<String>(tabName),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
child: Column(
children: <Widget>[
IconButton(
icon: const Icon(Icons.share),
onPressed: () { print('Pressed share'); },
),
IconButton(
icon: const Icon(Icons.event),
onPressed: () { print('Pressed event'); },
),
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Text('This is item $tabName'),
child: ColoredBox(
color: Theme.of(context).primaryColor,
child: Center(
child: Text(
tabName,
style: Theme.of(
context,
).textTheme.headlineSmall!.copyWith(color: Colors.white),
),
),
),
),
Row(
children: <Widget>[
IconButton(
icon: const Icon(Icons.share),
onPressed: () {
print('Pressed share');
},
),
IconButton(
icon: const Icon(Icons.event),
onPressed: () {
print('Pressed event');
},
),
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Text('This is item $tabName'),
),
),
],
),
],
),
],
),
),
),
),
);
}).toList(),
);
}).toList(),
),
),
const TabPageSelector(),
@ -572,11 +582,7 @@ class BottomBar extends StatelessWidget {
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
border: Border(
top: BorderSide(
color: Theme.of(context).dividerColor,
),
),
border: Border(top: BorderSide(color: Theme.of(context).dividerColor)),
),
child: const Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -606,7 +612,9 @@ class BottomBarButton extends StatelessWidget {
children: <Widget>[
IconButton(
icon: Icon(icon),
onPressed: () { print('Pressed: $title'); },
onPressed: () {
print('Pressed: $title');
},
),
Text(title, style: Theme.of(context).textTheme.bodySmall),
],
@ -616,7 +624,7 @@ class BottomBarButton extends StatelessWidget {
}
class GalleryDrawer extends StatelessWidget {
const GalleryDrawer({ super.key });
const GalleryDrawer({super.key});
void _changeTheme(BuildContext context, bool value) {
ComplexLayoutApp.of(context)?.lightTheme = value;
@ -642,31 +650,42 @@ class GalleryDrawer extends StatelessWidget {
key: const Key('scroll-switcher'),
title: const Text('Scroll Mode'),
onTap: () {
_changeScrollMode(context, currentMode == ScrollMode.complex ? ScrollMode.tile : ScrollMode.complex);
Navigator.pop(context);
_changeScrollMode(
context,
currentMode == ScrollMode.complex ? ScrollMode.tile : ScrollMode.complex,
);
Navigator.pop(context);
},
trailing: Text(currentMode == ScrollMode.complex ? 'Tile' : 'Complex'),
),
ListTile(
leading: const Icon(Icons.brightness_5),
title: const Text('Light'),
onTap: () { _changeTheme(context, true); },
onTap: () {
_changeTheme(context, true);
},
selected: ComplexLayoutApp.of(context)!.lightTheme,
trailing: Radio<bool>(
value: true,
groupValue: ComplexLayoutApp.of(context)!.lightTheme,
onChanged: (bool? value) { _changeTheme(context, value!); },
onChanged: (bool? value) {
_changeTheme(context, value!);
},
),
),
ListTile(
leading: const Icon(Icons.brightness_7),
title: const Text('Dark'),
onTap: () { _changeTheme(context, false); },
onTap: () {
_changeTheme(context, false);
},
selected: !ComplexLayoutApp.of(context)!.lightTheme,
trailing: Radio<bool>(
value: false,
groupValue: ComplexLayoutApp.of(context)!.lightTheme,
onChanged: (bool? value) { _changeTheme(context, value!); },
onChanged: (bool? value) {
_changeTheme(context, value!);
},
),
),
const Divider(),
@ -674,10 +693,14 @@ class GalleryDrawer extends StatelessWidget {
leading: const Icon(Icons.hourglass_empty),
title: const Text('Animate Slowly'),
selected: timeDilation != 1.0,
onTap: () { ComplexLayoutApp.of(context)!.toggleAnimationSpeed(); },
onTap: () {
ComplexLayoutApp.of(context)!.toggleAnimationSpeed();
},
trailing: Checkbox(
value: timeDilation != 1.0,
onChanged: (bool? value) { ComplexLayoutApp.of(context)!.toggleAnimationSpeed(); },
onChanged: (bool? value) {
ComplexLayoutApp.of(context)!.toggleAnimationSpeed();
},
),
),
],
@ -694,10 +717,7 @@ class FancyDrawerHeader extends StatelessWidget {
return Container(
color: Colors.purple,
height: 200.0,
child: const SafeArea(
bottom: false,
child: Placeholder(),
),
child: const SafeArea(bottom: false, child: Placeholder()),
);
}
}

View File

@ -24,17 +24,11 @@ Iterable<PointerEvent> dragInputEvents(
final Offset startLocation = center - totalMove / 2;
// The issue is about 120Hz input on 90Hz refresh rate device.
// We test 90Hz input on 60Hz device here, which shows similar pattern.
final int moveEventCount = totalTime.inMicroseconds * frequency ~/ const Duration(seconds: 1).inMicroseconds;
final int moveEventCount =
totalTime.inMicroseconds * frequency ~/ const Duration(seconds: 1).inMicroseconds;
final Offset movePerEvent = totalMove / moveEventCount.toDouble();
yield PointerAddedEvent(
timeStamp: epoch,
position: startLocation,
);
yield PointerDownEvent(
timeStamp: epoch,
position: startLocation,
pointer: 1,
);
yield PointerAddedEvent(timeStamp: epoch, position: startLocation);
yield PointerDownEvent(timeStamp: epoch, position: startLocation, pointer: 1);
for (int t = 0; t < moveEventCount + 1; t++) {
final Offset position = startLocation + movePerEvent * t.toDouble();
yield PointerMoveEvent(
@ -45,19 +39,10 @@ Iterable<PointerEvent> dragInputEvents(
);
}
final Offset position = startLocation + totalMove;
yield PointerUpEvent(
timeStamp: epoch + totalTime,
position: position,
pointer: 1,
);
yield PointerUpEvent(timeStamp: epoch + totalTime, position: position, pointer: 1);
}
enum TestScenario {
resampleOn90Hz,
resampleOn59Hz,
resampleOff90Hz,
resampleOff59Hz,
}
enum TestScenario { resampleOn90Hz, resampleOn59Hz, resampleOff90Hz, resampleOff59Hz }
class ResampleFlagVariant extends TestVariant<TestScenario> {
ResampleFlagVariant(this.binding);
@ -69,7 +54,7 @@ class ResampleFlagVariant extends TestVariant<TestScenario> {
late TestScenario currentValue;
bool get resample => switch (currentValue) {
TestScenario.resampleOn90Hz || TestScenario.resampleOn59Hz => true,
TestScenario.resampleOn90Hz || TestScenario.resampleOn59Hz => true,
TestScenario.resampleOff90Hz || TestScenario.resampleOff59Hz => false,
};
@ -83,8 +68,8 @@ class ResampleFlagVariant extends TestVariant<TestScenario> {
@override
String describeValue(TestScenario value) {
return switch (value) {
TestScenario.resampleOn90Hz => 'resample on with 90Hz input',
TestScenario.resampleOn59Hz => 'resample on with 59Hz input',
TestScenario.resampleOn90Hz => 'resample on with 90Hz input',
TestScenario.resampleOn59Hz => 'resample on with 59Hz input',
TestScenario.resampleOff90Hz => 'resample off with 90Hz input',
TestScenario.resampleOff59Hz => 'resample off with 59Hz input',
};
@ -108,61 +93,67 @@ class ResampleFlagVariant extends TestVariant<TestScenario> {
Future<void> main() async {
final WidgetsBinding widgetsBinding = IntegrationTestWidgetsFlutterBinding.ensureInitialized();
assert(widgetsBinding is IntegrationTestWidgetsFlutterBinding);
final IntegrationTestWidgetsFlutterBinding binding = widgetsBinding as IntegrationTestWidgetsFlutterBinding;
final IntegrationTestWidgetsFlutterBinding binding =
widgetsBinding as IntegrationTestWidgetsFlutterBinding;
binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.benchmarkLive;
binding.reportData ??= <String, dynamic>{};
final ResampleFlagVariant variant = ResampleFlagVariant(binding);
testWidgets('Smoothness test', (WidgetTester tester) async {
app.main();
await tester.pumpAndSettle();
final Finder scrollerFinder = find.byKey(const ValueKey<String>('complex-scroll'));
final ListView scroller = tester.widget<ListView>(scrollerFinder);
final ScrollController? controller = scroller.controller;
final List<int> frameTimestamp = <int>[];
final List<double> scrollOffset = <double>[];
final List<Duration> delays = <Duration>[];
binding.addPersistentFrameCallback((Duration timeStamp) {
if (controller?.hasClients ?? false) {
// This if is necessary because by the end of the test the widget tree
// is destroyed.
frameTimestamp.add(timeStamp.inMicroseconds);
scrollOffset.add(controller!.offset);
}
});
Duration now() => binding.currentSystemFrameTimeStamp;
Future<void> scroll() async {
// Extra 50ms to avoid timeouts.
final Duration startTime = const Duration(milliseconds: 500) + now();
for (final PointerEvent event in dragInputEvents(
startTime,
tester.getCenter(scrollerFinder),
frequency: variant.frequency,
)) {
await tester.binding.delayed(event.timeStamp - now());
// This now measures how accurate the above delayed is.
final Duration delay = now() - event.timeStamp;
if (delays.length < frameTimestamp.length) {
while (delays.length < frameTimestamp.length - 1) {
delays.add(Duration.zero);
}
delays.add(delay);
} else if (delays.last < delay) {
delays.last = delay;
testWidgets(
'Smoothness test',
(WidgetTester tester) async {
app.main();
await tester.pumpAndSettle();
final Finder scrollerFinder = find.byKey(const ValueKey<String>('complex-scroll'));
final ListView scroller = tester.widget<ListView>(scrollerFinder);
final ScrollController? controller = scroller.controller;
final List<int> frameTimestamp = <int>[];
final List<double> scrollOffset = <double>[];
final List<Duration> delays = <Duration>[];
binding.addPersistentFrameCallback((Duration timeStamp) {
if (controller?.hasClients ?? false) {
// This if is necessary because by the end of the test the widget tree
// is destroyed.
frameTimestamp.add(timeStamp.inMicroseconds);
scrollOffset.add(controller!.offset);
}
tester.binding.handlePointerEventForSource(event, source: TestBindingEventSource.test);
}
}
});
for (int n = 0; n < 5; n++) {
await scroll();
}
variant.result = scrollSummary(scrollOffset, delays, frameTimestamp);
await tester.pumpAndSettle();
scrollOffset.clear();
delays.clear();
await tester.idle();
}, semanticsEnabled: false, variant: variant);
Duration now() => binding.currentSystemFrameTimeStamp;
Future<void> scroll() async {
// Extra 50ms to avoid timeouts.
final Duration startTime = const Duration(milliseconds: 500) + now();
for (final PointerEvent event in dragInputEvents(
startTime,
tester.getCenter(scrollerFinder),
frequency: variant.frequency,
)) {
await tester.binding.delayed(event.timeStamp - now());
// This now measures how accurate the above delayed is.
final Duration delay = now() - event.timeStamp;
if (delays.length < frameTimestamp.length) {
while (delays.length < frameTimestamp.length - 1) {
delays.add(Duration.zero);
}
delays.add(delay);
} else if (delays.last < delay) {
delays.last = delay;
}
tester.binding.handlePointerEventForSource(event, source: TestBindingEventSource.test);
}
}
for (int n = 0; n < 5; n++) {
await scroll();
}
variant.result = scrollSummary(scrollOffset, delays, frameTimestamp);
await tester.pumpAndSettle();
scrollOffset.clear();
delays.clear();
await tester.idle();
},
semanticsEnabled: false,
variant: variant,
);
}
/// Calculates the smoothness measure from `scrollOffset` and `delays` list.
@ -215,15 +206,15 @@ Map<String, dynamic> scrollSummary(
double jankyCount = 0;
double absJerkAvg = 0;
int lostFrame = 0;
for (int i = 1; i < scrollOffset.length-1; i += 1) {
if (frameTimestamp[i+1] - frameTimestamp[i-1] > 40E3 ||
for (int i = 1; i < scrollOffset.length - 1; i += 1) {
if (frameTimestamp[i + 1] - frameTimestamp[i - 1] > 40E3 ||
(i >= delays.length || delays[i] > const Duration(milliseconds: 16))) {
// filter data points from slow frame building or input simulation artifact
lostFrame += 1;
continue;
}
//
final double absJerk = (scrollOffset[i-1] + scrollOffset[i+1] - 2*scrollOffset[i]).abs();
final double absJerk = (scrollOffset[i - 1] + scrollOffset[i + 1] - 2 * scrollOffset[i]).abs();
absJerkAvg += absJerk;
if (absJerk > 0.5) {
jankyCount += 1;

View File

@ -8,9 +8,6 @@ import 'package:integration_test/integration_test_driver.dart' as driver;
Future<void> main() => driver.integrationDriver(
responseDataCallback: (Map<String, dynamic>? data) async {
await driver.writeResponseData(
data,
testOutputFilename: 'scroll_smoothness_test',
);
}
await driver.writeResponseData(data, testOutputFilename: 'scroll_smoothness_test');
},
);

View File

@ -47,26 +47,39 @@ void main() {
expect(
await driver.setSemantics(true),
isTrue,
reason: 'Could not toggle semantics to on because semantics were already '
'on, but the test needs to toggle semantics to measure the initial '
'semantics tree generation in isolation.'
reason:
'Could not toggle semantics to on because semantics were already '
'on, but the test needs to toggle semantics to measure the initial '
'semantics tree generation in isolation.',
);
});
final Iterable<TimelineEvent>? semanticsEvents = timeline.events?.where((TimelineEvent event) => event.name == 'SEMANTICS');
final Iterable<TimelineEvent>? semanticsEvents = timeline.events?.where(
(TimelineEvent event) => event.name == 'SEMANTICS',
);
if (semanticsEvents?.length != 2) {
fail('Expected exactly two "SEMANTICS" events, got ${semanticsEvents?.length}:\n$semanticsEvents');
fail(
'Expected exactly two "SEMANTICS" events, got ${semanticsEvents?.length}:\n$semanticsEvents',
);
}
final Duration semanticsTreeCreation = Duration(microseconds: semanticsEvents!.last.timestampMicros! - semanticsEvents.first.timestampMicros!);
final Duration semanticsTreeCreation = Duration(
microseconds:
semanticsEvents!.last.timestampMicros! - semanticsEvents.first.timestampMicros!,
);
final String jsonEncoded = json.encode(<String, dynamic>{'initialSemanticsTreeCreation': semanticsTreeCreation.inMilliseconds});
File(p.join(testOutputsDirectory, 'complex_layout_semantics_perf.json')).writeAsStringSync(jsonEncoded);
final String jsonEncoded = json.encode(<String, dynamic>{
'initialSemanticsTreeCreation': semanticsTreeCreation.inMilliseconds,
});
File(
p.join(testOutputsDirectory, 'complex_layout_semantics_perf.json'),
).writeAsStringSync(jsonEncoded);
}, timeout: Timeout.none);
});
}
String _adbPath() {
final String? androidHome = Platform.environment['ANDROID_HOME'] ?? Platform.environment['ANDROID_SDK_ROOT'];
final String? androidHome =
Platform.environment['ANDROID_HOME'] ?? Platform.environment['ANDROID_SDK_ROOT'];
if (androidHome == null) {
return 'adb';
} else {

View File

@ -21,16 +21,16 @@ const Duration pauses = Duration(milliseconds: 500);
Future<void> main() async {
final Completer<void> ready = Completer<void>();
runApp(GestureDetector(
onTap: () {
debugPrint('==== MEMORY BENCHMARK ==== TAPPED ====');
ready.complete();
},
behavior: HitTestBehavior.opaque,
child: const IgnorePointer(
child: ComplexLayoutApp(),
runApp(
GestureDetector(
onTap: () {
debugPrint('==== MEMORY BENCHMARK ==== TAPPED ====');
ready.complete();
},
behavior: HitTestBehavior.opaque,
child: const IgnorePointer(child: ComplexLayoutApp()),
),
));
);
await SchedulerBinding.instance.endOfFrame;
debugPrint('==== MEMORY BENCHMARK ==== READY ====');
@ -41,12 +41,7 @@ Future<void> main() async {
await Future<void>.delayed(const Duration(milliseconds: 200));
// remove onTap handler, enable pointer events for app
runApp(GestureDetector(
child: const IgnorePointer(
ignoring: false,
child: ComplexLayoutApp(),
),
));
runApp(GestureDetector(child: const IgnorePointer(ignoring: false, child: ComplexLayoutApp())));
await SchedulerBinding.instance.endOfFrame;
final WidgetController controller = LiveWidgetController(WidgetsBinding.instance);

View File

@ -43,19 +43,28 @@ const String kAnimatedAdvancedBlend = '/animated_advanced_blend';
const String kRRectBlurRouteName = '/rrect_blur';
const String kOpacityPeepholeOneRectRouteName = '$kOpacityPeepholeRouteName/one_big_rect';
const String kOpacityPeepholeColumnOfOpacityRouteName = '$kOpacityPeepholeRouteName/column_of_opacity';
const String kOpacityPeepholeOpacityOfCachedChildRouteName = '$kOpacityPeepholeRouteName/opacity_of_cached_child';
const String kOpacityPeepholeOpacityOfColumnRouteName = '$kOpacityPeepholeRouteName/opacity_of_column';
const String kOpacityPeepholeColumnOfOpacityRouteName =
'$kOpacityPeepholeRouteName/column_of_opacity';
const String kOpacityPeepholeOpacityOfCachedChildRouteName =
'$kOpacityPeepholeRouteName/opacity_of_cached_child';
const String kOpacityPeepholeOpacityOfColumnRouteName =
'$kOpacityPeepholeRouteName/opacity_of_column';
const String kOpacityPeepholeGridOfOpacityRouteName = '$kOpacityPeepholeRouteName/grid_of_opacity';
const String kOpacityPeepholeOpacityOfGridRouteName = '$kOpacityPeepholeRouteName/opacity_of_grid';
const String kOpacityPeepholeOpacityOfColOfRowsRouteName = '$kOpacityPeepholeRouteName/opacity_of_col_of_rows';
const String kOpacityPeepholeFadeTransitionTextRouteName = '$kOpacityPeepholeRouteName/fade_transition_text';
const String kOpacityPeepholeGridOfRectsWithAlphaRouteName = '$kOpacityPeepholeRouteName/grid_of_rects_with_alpha';
const String kOpacityPeepholeGridOfAlphaSaveLayerRectsRouteName = '$kOpacityPeepholeRouteName/grid_of_alpha_savelayer_rects';
const String kOpacityPeepholeColumnOfAlphaSaveLayerRowsOfRectsRouteName = '$kOpacityPeepholeRouteName/column_of_alpha_save_layer_rows_of_rects';
const String kOpacityPeepholeOpacityOfColOfRowsRouteName =
'$kOpacityPeepholeRouteName/opacity_of_col_of_rows';
const String kOpacityPeepholeFadeTransitionTextRouteName =
'$kOpacityPeepholeRouteName/fade_transition_text';
const String kOpacityPeepholeGridOfRectsWithAlphaRouteName =
'$kOpacityPeepholeRouteName/grid_of_rects_with_alpha';
const String kOpacityPeepholeGridOfAlphaSaveLayerRectsRouteName =
'$kOpacityPeepholeRouteName/grid_of_alpha_savelayer_rects';
const String kOpacityPeepholeColumnOfAlphaSaveLayerRowsOfRectsRouteName =
'$kOpacityPeepholeRouteName/column_of_alpha_save_layer_rows_of_rects';
const String kGradientPerfRecreateDynamicRouteName = '$kGradientPerfRouteName/recreate_dynamic';
const String kGradientPerfRecreateConsistentRouteName = '$kGradientPerfRouteName/recreate_consistent';
const String kGradientPerfRecreateConsistentRouteName =
'$kGradientPerfRouteName/recreate_consistent';
const String kGradientPerfStaticConsistentRouteName = '$kGradientPerfRouteName/static_consistent';
const String kScrollableName = '/macrobenchmark_listview';

View File

@ -64,7 +64,8 @@ class MacrobenchmarksApp extends StatelessWidget {
kPostBackdropFilterRouteName: (BuildContext context) => const PostBackdropFilterPage(),
kSimpleAnimationRouteName: (BuildContext context) => const SimpleAnimationPage(),
kPictureCacheRouteName: (BuildContext context) => const PictureCachePage(),
kPictureCacheComplexityScoringRouteName: (BuildContext context) => const PictureCacheComplexityScoringPage(),
kPictureCacheComplexityScoringRouteName:
(BuildContext context) => const PictureCacheComplexityScoringPage(),
kLargeImageChangerRouteName: (BuildContext context) => const LargeImageChangerPage(),
kLargeImagesRouteName: (BuildContext context) => const LargeImagesPage(),
kTextRouteName: (BuildContext context) => const TextPage(),
@ -74,23 +75,30 @@ class MacrobenchmarksApp extends StatelessWidget {
kClipperCacheRouteName: (BuildContext context) => const ClipperCachePage(),
kColorFilterAndFadeRouteName: (BuildContext context) => const ColorFilterAndFadePage(),
kColorFilterCacheRouteName: (BuildContext context) => const ColorFilterCachePage(),
kColorFilterWithUnstableChildName: (BuildContext context) => const ColorFilterWithUnstableChildPage(),
kFadingChildAnimationRouteName: (BuildContext context) => const FilteredChildAnimationPage(FilterType.opacity),
kImageFilteredTransformAnimationRouteName: (BuildContext context) => const FilteredChildAnimationPage(FilterType.rotateFilter),
kMultiWidgetConstructionRouteName: (BuildContext context) => const MultiWidgetConstructTable(10, 20),
kColorFilterWithUnstableChildName:
(BuildContext context) => const ColorFilterWithUnstableChildPage(),
kFadingChildAnimationRouteName:
(BuildContext context) => const FilteredChildAnimationPage(FilterType.opacity),
kImageFilteredTransformAnimationRouteName:
(BuildContext context) => const FilteredChildAnimationPage(FilterType.rotateFilter),
kMultiWidgetConstructionRouteName:
(BuildContext context) => const MultiWidgetConstructTable(10, 20),
kHeavyGridViewRouteName: (BuildContext context) => const HeavyGridViewPage(),
kRasterCacheUseMemory: (BuildContext context) => const RasterCacheUseMemory(),
kShaderMaskCacheRouteName: (BuildContext context) => const ShaderMaskCachePage(),
kSimpleScrollRouteName: (BuildContext context) => const SimpleScroll(),
kAnimationWithMicrotasksRouteName: (BuildContext context) => const AnimationWithMicrotasks(),
kAnimationWithMicrotasksRouteName:
(BuildContext context) => const AnimationWithMicrotasks(),
kAnimatedImageRouteName: (BuildContext context) => const AnimatedImagePage(),
kOpacityPeepholeRouteName: (BuildContext context) => const OpacityPeepholePage(),
...opacityPeepholeRoutes,
kGradientPerfRouteName: (BuildContext context) => const GradientPerfHomePage(),
...gradientPerfRoutes,
kAnimatedComplexOpacityPerfRouteName: (BuildContext context) => const AnimatedComplexOpacity(),
kAnimatedComplexOpacityPerfRouteName:
(BuildContext context) => const AnimatedComplexOpacity(),
kListTextLayoutRouteName: (BuildContext context) => const ColumnOfText(),
kAnimatedComplexImageFilteredPerfRouteName: (BuildContext context) => const AnimatedComplexImageFiltered(),
kAnimatedComplexImageFilteredPerfRouteName:
(BuildContext context) => const AnimatedComplexImageFiltered(),
kAnimatedBlurBackdropFilter: (BuildContext context) => const AnimatedBlurBackdropFilter(),
kSlidersRouteName: (BuildContext context) => const SlidersPage(),
kDrawPointsPageRougeName: (BuildContext context) => const DrawPointsPage(),
@ -98,7 +106,8 @@ class MacrobenchmarksApp extends StatelessWidget {
kDrawAtlasPageRouteName: (BuildContext context) => const DrawAtlasPage(),
kAnimatedAdvancedBlend: (BuildContext context) => const AnimatedAdvancedBlend(),
kRRectBlurRouteName: (BuildContext context) => const RRectBlur(),
kVeryLongPictureScrollingRouteName: (BuildContext context) => const VeryLongPictureScrollingPerf(),
kVeryLongPictureScrollingRouteName:
(BuildContext context) => const VeryLongPictureScrollingPerf(),
},
);
}

View File

@ -19,17 +19,20 @@ class _MultiplyPainter extends CustomPainter {
for (int y = 0; y < yDenominator; y++) {
for (int x = 0; x < xDenominator; x++) {
final Rect rect = Offset(x * width, y * height) & Size(width, height);
final Paint basePaint = Paint()
..color = Color.fromARGB(
(((x + 1) * width) / size.width * 255.0).floor(),
(((y + 1) * height) / size.height * 255.0).floor(),
255,
127);
final Paint basePaint =
Paint()
..color = Color.fromARGB(
(((x + 1) * width) / size.width * 255.0).floor(),
(((y + 1) * height) / size.height * 255.0).floor(),
255,
127,
);
canvas.drawRect(rect, basePaint);
final Paint multiplyPaint = Paint()
..color = _color
..blendMode = BlendMode.multiply;
final Paint multiplyPaint =
Paint()
..color = _color
..blendMode = BlendMode.multiply;
canvas.drawRect(rect, multiplyPaint);
}
}
@ -48,8 +51,12 @@ class AnimatedAdvancedBlend extends StatefulWidget {
State<AnimatedAdvancedBlend> createState() => _AnimatedAdvancedBlendState();
}
class _AnimatedAdvancedBlendState extends State<AnimatedAdvancedBlend> with SingleTickerProviderStateMixin {
late final AnimationController controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 5000));
class _AnimatedAdvancedBlendState extends State<AnimatedAdvancedBlend>
with SingleTickerProviderStateMixin {
late final AnimationController controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 5000),
);
late final Animation<double> animation = controller.drive(Tween<double>(begin: 0.0, end: 1.0));
Color _color = const Color.fromARGB(255, 255, 0, 255);
@ -73,11 +80,7 @@ class _AnimatedAdvancedBlendState extends State<AnimatedAdvancedBlend> with Sing
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: CustomPaint(
painter: _MultiplyPainter(_color),
child: Container(),
),
));
home: Scaffold(body: CustomPaint(painter: _MultiplyPainter(_color), child: Container())),
);
}
}

View File

@ -9,14 +9,18 @@ import 'package:flutter/material.dart';
// dirty children even without explicit repaint boundaries. These intentionally use
// text to ensure we don't measure the opacity peephole case.
class AnimatedBlurBackdropFilter extends StatefulWidget {
const AnimatedBlurBackdropFilter({ super.key });
const AnimatedBlurBackdropFilter({super.key});
@override
State<AnimatedBlurBackdropFilter> createState() => _AnimatedBlurBackdropFilterState();
}
class _AnimatedBlurBackdropFilterState extends State<AnimatedBlurBackdropFilter> with SingleTickerProviderStateMixin {
late final AnimationController controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 5000));
class _AnimatedBlurBackdropFilterState extends State<AnimatedBlurBackdropFilter>
with SingleTickerProviderStateMixin {
late final AnimationController controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 5000),
);
late final Animation<double> animation = controller.drive(Tween<double>(begin: 0.0, end: 1.0));
ui.ImageFilter imageFilter = ui.ImageFilter.blur();
@ -55,10 +59,7 @@ class _AnimatedBlurBackdropFilterState extends State<AnimatedBlurBackdropFilter>
),
],
),
BackdropFilter(
filter: imageFilter,
child: const SizedBox.expand(),
),
BackdropFilter(filter: imageFilter, child: const SizedBox.expand()),
],
),
),
@ -67,7 +68,7 @@ class _AnimatedBlurBackdropFilterState extends State<AnimatedBlurBackdropFilter>
}
class ModeratelyComplexWidget extends StatelessWidget {
const ModeratelyComplexWidget({ super.key });
const ModeratelyComplexWidget({super.key});
@override
Widget build(BuildContext context) {
@ -76,7 +77,10 @@ class ModeratelyComplexWidget extends StatelessWidget {
clipBehavior: Clip.hardEdge,
child: ListTile(
leading: Icon(Icons.abc, size: 24),
title: DecoratedBox(decoration: BoxDecoration(color: Colors.red), child: Text('Hello World')),
title: DecoratedBox(
decoration: BoxDecoration(color: Colors.red),
child: Text('Hello World'),
),
trailing: FlutterLogo(),
),
);

View File

@ -9,14 +9,18 @@ import 'package:flutter/material.dart';
// dirty children even without explicit repaint boundaries. These intentionally use
// text to ensure we don't measure the opacity peephole case.
class AnimatedComplexImageFiltered extends StatefulWidget {
const AnimatedComplexImageFiltered({ super.key });
const AnimatedComplexImageFiltered({super.key});
@override
State<AnimatedComplexImageFiltered> createState() => _AnimatedComplexImageFilteredState();
}
class _AnimatedComplexImageFilteredState extends State<AnimatedComplexImageFiltered> with SingleTickerProviderStateMixin {
late final AnimationController controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 5000));
class _AnimatedComplexImageFilteredState extends State<AnimatedComplexImageFiltered>
with SingleTickerProviderStateMixin {
late final AnimationController controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 5000),
);
late final Animation<double> animation = controller.drive(Tween<double>(begin: 0.0, end: 1.0));
ui.ImageFilter imageFilter = ui.ImageFilter.blur();
@ -44,12 +48,12 @@ class _AnimatedComplexImageFilteredState extends State<AnimatedComplexImageFilte
body: ListView(
children: <Widget>[
for (int i = 0; i < 20; i++)
ImageFiltered(
imageFilter: imageFilter,
child: Center(
child: Transform.scale(scale: 1.01, child: const ModeratelyComplexWidget()),
ImageFiltered(
imageFilter: imageFilter,
child: Center(
child: Transform.scale(scale: 1.01, child: const ModeratelyComplexWidget()),
),
),
),
],
),
),
@ -58,7 +62,7 @@ class _AnimatedComplexImageFilteredState extends State<AnimatedComplexImageFilte
}
class ModeratelyComplexWidget extends StatelessWidget {
const ModeratelyComplexWidget({ super.key });
const ModeratelyComplexWidget({super.key});
@override
Widget build(BuildContext context) {
@ -67,7 +71,10 @@ class ModeratelyComplexWidget extends StatelessWidget {
clipBehavior: Clip.hardEdge,
child: ListTile(
leading: Icon(Icons.abc, size: 24),
title: DecoratedBox(decoration: BoxDecoration(color: Colors.red), child: Text('Hello World')),
title: DecoratedBox(
decoration: BoxDecoration(color: Colors.red),
child: Text('Hello World'),
),
trailing: FlutterLogo(),
),
);

View File

@ -8,14 +8,18 @@ import 'package:flutter/material.dart';
// dirty children even without explicit repaint boundaries. These intentionally use
// text to ensure we don't measure the opacity peephole case.
class AnimatedComplexOpacity extends StatefulWidget {
const AnimatedComplexOpacity({ super.key });
const AnimatedComplexOpacity({super.key});
@override
State<AnimatedComplexOpacity> createState() => _AnimatedComplexOpacityState();
}
class _AnimatedComplexOpacityState extends State<AnimatedComplexOpacity> with SingleTickerProviderStateMixin {
late final AnimationController controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 5000));
class _AnimatedComplexOpacityState extends State<AnimatedComplexOpacity>
with SingleTickerProviderStateMixin {
late final AnimationController controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 5000),
);
late final Animation<double> animation = controller.drive(Tween<double>(begin: 0.0, end: 1.0));
@override
@ -37,9 +41,12 @@ class _AnimatedComplexOpacityState extends State<AnimatedComplexOpacity> with Si
body: ListView(
children: <Widget>[
for (int i = 0; i < 20; i++)
FadeTransition(opacity: animation, child: Center(
child: Transform.scale(scale: 1.01, child: const ModeratelyComplexWidget()),
)),
FadeTransition(
opacity: animation,
child: Center(
child: Transform.scale(scale: 1.01, child: const ModeratelyComplexWidget()),
),
),
],
),
),
@ -48,7 +55,7 @@ class _AnimatedComplexOpacityState extends State<AnimatedComplexOpacity> with Si
}
class ModeratelyComplexWidget extends StatelessWidget {
const ModeratelyComplexWidget({ super.key });
const ModeratelyComplexWidget({super.key});
@override
Widget build(BuildContext context) {
@ -57,7 +64,10 @@ class ModeratelyComplexWidget extends StatelessWidget {
clipBehavior: Clip.hardEdge,
child: ListTile(
leading: Icon(Icons.abc, size: 24),
title: DecoratedBox(decoration: BoxDecoration(color: Colors.red), child: Text('Hello World')),
title: DecoratedBox(
decoration: BoxDecoration(color: Colors.red),
child: Text('Hello World'),
),
trailing: FlutterLogo(),
),
);

View File

@ -12,9 +12,7 @@ class AnimatedImagePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Animated Image'),
),
appBar: AppBar(title: const Text('Animated Image')),
body: Image.asset(
'animated_images/animated_flutter_lgtm.gif',
package: 'flutter_gallery_assets',

View File

@ -11,16 +11,18 @@ import 'package:flutter/material.dart';
/// An animated GIF image with 3 1x1 pixel frames (a red, green, and blue
/// frames). The GIF animates forever, and each frame has a 100ms delay.
const String kAnimatedGif = 'R0lGODlhAQABAKEDAAAA//8AAAD/AP///yH/C05FVFNDQVBFMi'
'4wAwEAAAAh+QQACgD/ACwAAAAAAQABAAACAkwBACH5BAAKAP8A'
'LAAAAAABAAEAAAICVAEAIfkEAAoA/wAsAAAAAAEAAQAAAgJEAQ'
'A7';
const String kAnimatedGif =
'R0lGODlhAQABAKEDAAAA//8AAAD/AP///yH/C05FVFNDQVBFMi'
'4wAwEAAAAh+QQACgD/ACwAAAAAAQABAAACAkwBACH5BAAKAP8A'
'LAAAAAABAAEAAAICVAEAIfkEAAoA/wAsAAAAAAEAAQAAAgJEAQ'
'A7';
/// A 50x50 blue square png
const String kBlueSquare = 'iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAASEl'
'EQVR42u3PMQ0AMAgAsGFjL/4tYQU08JLWQSN/9TsgRERERERERE'
'REREREREREREREREREREREREREREREREREREREREQ2BgNuaUcSj'
'uqqAAAAAElFTkSuQmCC';
const String kBlueSquare =
'iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAASEl'
'EQVR42u3PMQ0AMAgAsGFjL/4tYQU08JLWQSN/9TsgRERERERERE'
'REREREREREREREREREREREREREREREREREREREREQ2BgNuaUcSj'
'uqqAAAAAElFTkSuQmCC';
/// A 10x10 grid of animated looping placeholder gifts that fade into a
/// blue square.
@ -43,6 +45,7 @@ class AnimatedPlaceholderPage extends StatelessWidget {
}
int _key = 0;
/// An image provider that is always unique from other DelayedBase64Images and
/// simulates a delay in loading.
class DelayedBase64Image extends ImageProvider<int> {

View File

@ -30,13 +30,7 @@ class _AnimationWithMicrotasksState extends State<AnimationWithMicrotasks> {
Widget build(BuildContext context) {
return const Scaffold(
backgroundColor: Colors.grey,
body: Center(
child: SizedBox(
width: 200,
height: 100,
child: LinearProgressIndicator(),
),
),
body: Center(child: SizedBox(width: 200, height: 100, child: LinearProgressIndicator())),
);
}
}

View File

@ -36,25 +36,20 @@ class _BackdropFilterPageState extends State<BackdropFilterPage> with TickerProv
Widget addBlur(Widget child, bool shouldBlur) {
if (shouldBlur) {
return ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5),
child: child,
),
child: BackdropFilter(filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), child: child),
);
} else {
return child;
}
}
final Widget txt = addBlur(Container(
padding: const EdgeInsets.all(5),
child: const Text('txt'),
), _blurTexts);
final Widget txt = addBlur(
Container(padding: const EdgeInsets.all(5), child: const Text('txt')),
_blurTexts,
);
Widget col(Widget w, int numRows) {
return Column(
children: List<Widget>.generate(numRows, (int i) => w),
);
return Column(children: List<Widget>.generate(numRows, (int i) => w));
}
Widget grid(Widget w, int numRows, int numCols) {
@ -74,38 +69,45 @@ class _BackdropFilterPageState extends State<BackdropFilterPage> with TickerProv
children: <Widget>[
Expanded(
child: RepaintBoundary(
child: Center(
child: AnimatedBuilder(
animation: animation,
builder: (BuildContext c, Widget? w) {
final int val = (animation.value * 255).round();
return Container(
width: 50,
height: 50,
color: Color.fromARGB(255, val, val, val));
}),
)),
child: Center(
child: AnimatedBuilder(
animation: animation,
builder: (BuildContext c, Widget? w) {
final int val = (animation.value * 255).round();
return Container(
width: 50,
height: 50,
color: Color.fromARGB(255, val, val, val),
);
},
),
),
),
),
const SizedBox(height: 20),
RepaintBoundary(
child: addBlur(grid(txt, 17, 5), _blurGroup),
),
RepaintBoundary(child: addBlur(grid(txt, 17, 5), _blurGroup)),
const SizedBox(height: 20),
ColoredBox(
color: Colors.white,
child:Row(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text('Backdrop per txt:'),
Checkbox(
value: _blurTexts,
onChanged: (bool? v) => setState(() { _blurTexts = v ?? false; }),
onChanged:
(bool? v) => setState(() {
_blurTexts = v ?? false;
}),
),
const SizedBox(width: 10),
const Text('Backdrop grid:'),
Checkbox(
value: _blurGroup,
onChanged: (bool? v) => setState(() { _blurGroup = v ?? false; }),
onChanged:
(bool? v) => setState(() {
_blurGroup = v ?? false;
}),
),
],
),

View File

@ -13,8 +13,7 @@ class ClipperCachePage extends StatefulWidget {
State<ClipperCachePage> createState() => _ClipperCachePageState();
}
class _ClipperCachePageState extends State<ClipperCachePage>
with TickerProviderStateMixin {
class _ClipperCachePageState extends State<ClipperCachePage> with TickerProviderStateMixin {
final double _animateOffset = 100;
final ScrollController _controller = ScrollController();
final bool _isComplex = true;
@ -25,13 +24,21 @@ class _ClipperCachePageState extends State<ClipperCachePage>
super.initState();
_controller.addListener(() {
if (_controller.offset < 10) {
_controller.animateTo(_animateOffset, duration: const Duration(milliseconds: 1000), curve: Curves.ease);
_controller.animateTo(
_animateOffset,
duration: const Duration(milliseconds: 1000),
curve: Curves.ease,
);
} else if (_controller.offset > _animateOffset - 10) {
_controller.animateTo(0, duration: const Duration(milliseconds: 1000), curve: Curves.ease);
}
});
Timer(const Duration(milliseconds: 500), () {
_controller.animateTo(_animateOffset, duration: const Duration(milliseconds: 1000), curve: Curves.ease);
_controller.animateTo(
_animateOffset,
duration: const Duration(milliseconds: 1000),
curve: Curves.ease,
);
});
}
@ -55,18 +62,9 @@ class _ClipperCachePageState extends State<ClipperCachePage>
controller: _controller,
children: <Widget>[
SizedBox(height: _topMargin),
ClipPath(
clipBehavior: Clip.antiAliasWithSaveLayer,
child: _makeChild(0, _isComplex)
),
ClipRect(
clipBehavior: Clip.antiAliasWithSaveLayer,
child: _makeChild(1, _isComplex)
),
ClipRRect(
clipBehavior: Clip.antiAliasWithSaveLayer,
child: _makeChild(2, _isComplex)
),
ClipPath(clipBehavior: Clip.antiAliasWithSaveLayer, child: _makeChild(0, _isComplex)),
ClipRect(clipBehavior: Clip.antiAliasWithSaveLayer, child: _makeChild(1, _isComplex)),
ClipRRect(clipBehavior: Clip.antiAliasWithSaveLayer, child: _makeChild(2, _isComplex)),
const SizedBox(height: 1000),
],
),
@ -76,11 +74,7 @@ class _ClipperCachePageState extends State<ClipperCachePage>
Widget _makeChild(int itemIndex, bool complex) {
final BoxDecoration decoration = BoxDecoration(
color: Colors.white70,
boxShadow: const <BoxShadow>[
BoxShadow(
blurRadius: 5.0,
),
],
boxShadow: const <BoxShadow>[BoxShadow(blurRadius: 5.0)],
borderRadius: BorderRadius.circular(5.0),
);
return RepaintBoundary(

View File

@ -15,18 +15,15 @@ class ColorFilterAndFadePage extends StatefulWidget {
State<ColorFilterAndFadePage> createState() => _ColorFilterAndFadePageState();
}
class _ColorFilterAndFadePageState extends State<ColorFilterAndFadePage> with TickerProviderStateMixin {
class _ColorFilterAndFadePageState extends State<ColorFilterAndFadePage>
with TickerProviderStateMixin {
@override
Widget build(BuildContext context) {
final Widget shadowWidget = _ShadowWidget(
width: 24,
height: 24,
useColorFilter: _useColorFilter,
shadow: const ui.Shadow(
color: Colors.black45,
offset: Offset(0.0, 2.0),
blurRadius: 4.0,
),
shadow: const ui.Shadow(color: Colors.black45, offset: Offset(0.0, 2.0), blurRadius: 4.0),
);
final Widget row = Row(
@ -45,17 +42,18 @@ class _ColorFilterAndFadePageState extends State<ColorFilterAndFadePage> with Ti
],
);
final Widget column = Column(mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
row,
const SizedBox(height: 12),
row,
const SizedBox(height: 12),
row,
const SizedBox(height: 12),
row,
const SizedBox(height: 12),
],
final Widget column = Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
row,
const SizedBox(height: 12),
row,
const SizedBox(height: 12),
row,
const SizedBox(height: 12),
row,
const SizedBox(height: 12),
],
);
final Widget fadeTransition = FadeTransition(
@ -63,31 +61,29 @@ class _ColorFilterAndFadePageState extends State<ColorFilterAndFadePage> with Ti
// This RepaintBoundary is necessary to not let the opacity change
// invalidate the layer raster cache below. This is necessary with
// or without the color filter.
child: RepaintBoundary(
child: column,
),
child: RepaintBoundary(child: column),
);
return Scaffold(
backgroundColor: Colors.lightBlue,
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
fadeTransition,
Container(height: 20),
const Text('Use Color Filter:'),
Checkbox(
value: _useColorFilter,
onChanged: (bool? value) {
setState(() {
_useColorFilter = value ?? false;
});
},
),
],
backgroundColor: Colors.lightBlue,
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
fadeTransition,
Container(height: 20),
const Text('Use Color Filter:'),
Checkbox(
value: _useColorFilter,
onChanged: (bool? value) {
setState(() {
_useColorFilter = value ?? false;
});
},
),
],
),
),
);
}
@ -141,10 +137,7 @@ class _ShadowWidget extends StatelessWidget {
width: width,
height: height,
child: CustomPaint(
painter: _ShadowPainter(
useColorFilter: useColorFilter,
shadow: shadow,
),
painter: _ShadowPainter(useColorFilter: useColorFilter, shadow: shadow),
size: Size(width, height),
isComplex: true,
),
@ -170,7 +163,10 @@ class _ShadowPainter extends CustomPainter {
canvas.saveLayer(null, paint);
canvas.translate(shadow.offset.dx, shadow.offset.dy);
canvas.drawRect(rect, Paint());
canvas.drawRect(rect, Paint()..maskFilter = MaskFilter.blur(BlurStyle.normal, shadow.blurSigma));
canvas.drawRect(
rect,
Paint()..maskFilter = MaskFilter.blur(BlurStyle.normal, shadow.blurSigma),
);
canvas.restore();
canvas.drawRect(rect, Paint()..color = useColorFilter ? Colors.white : Colors.black);

View File

@ -11,15 +11,18 @@ class ColorFilterCachePage extends StatefulWidget {
State<ColorFilterCachePage> createState() => _ColorFilterCachePageState();
}
class _ColorFilterCachePageState extends State<ColorFilterCachePage>
with TickerProviderStateMixin {
class _ColorFilterCachePageState extends State<ColorFilterCachePage> with TickerProviderStateMixin {
final ScrollController _controller = ScrollController();
@override
void initState() {
super.initState();
_controller.addListener(() {
if (_controller.offset < 20) {
_controller.animateTo(150, duration: const Duration(milliseconds: 1000), curve: Curves.ease);
_controller.animateTo(
150,
duration: const Duration(milliseconds: 1000),
curve: Curves.ease,
);
} else if (_controller.offset > 130) {
_controller.animateTo(0, duration: const Duration(milliseconds: 1000), curve: Curves.ease);
}
@ -41,12 +44,11 @@ class _ColorFilterCachePageState extends State<ColorFilterCachePage>
colorFilter: ColorFilter.mode(Colors.green[300]!, BlendMode.luminosity),
child: Container(
clipBehavior: Clip.antiAlias,
decoration: const BoxDecoration(boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.red,
blurRadius: 5.0,
),
], color: Colors.blue, backgroundBlendMode: BlendMode.luminosity),
decoration: const BoxDecoration(
boxShadow: <BoxShadow>[BoxShadow(color: Colors.red, blurRadius: 5.0)],
color: Colors.blue,
backgroundBlendMode: BlendMode.luminosity,
),
child: Column(
children: <Widget>[
const Text('Color Filter Cache Pref Test'),

View File

@ -11,7 +11,8 @@ class ColorFilterWithUnstableChildPage extends StatefulWidget {
State<StatefulWidget> createState() => _ColorFilterWithUnstableChildPageState();
}
class _ColorFilterWithUnstableChildPageState extends State<ColorFilterWithUnstableChildPage> with SingleTickerProviderStateMixin {
class _ColorFilterWithUnstableChildPageState extends State<ColorFilterWithUnstableChildPage>
with SingleTickerProviderStateMixin {
late Animation<double> _offsetY;
late AnimationController _controller;
@ -34,21 +35,27 @@ class _ColorFilterWithUnstableChildPageState extends State<ColorFilterWithUnstab
return AnimatedBuilder(
animation: _offsetY,
builder: (BuildContext context, Widget? child) {
return Stack(children: List<Widget>.generate(50, (int i) => Positioned(
left: 0,
top: (200 * i).toDouble() + _offsetY.value,
child: ColorFiltered(
colorFilter: ColorFilter.mode(Colors.green[300]!, BlendMode.luminosity),
child: RepaintBoundary(
child: Container(
// Slightly change width to invalidate raster cache.
width: 1000 - (_offsetY.value / 100),
height: 100, color: Colors.red,
return Stack(
children: List<Widget>.generate(
50,
(int i) => Positioned(
left: 0,
top: (200 * i).toDouble() + _offsetY.value,
child: ColorFiltered(
colorFilter: ColorFilter.mode(Colors.green[300]!, BlendMode.luminosity),
child: RepaintBoundary(
child: Container(
// Slightly change width to invalidate raster cache.
width: 1000 - (_offsetY.value / 100),
height: 100,
color: Colors.red,
),
),
),
),
)));
}
),
);
},
);
}
}

View File

@ -15,9 +15,7 @@ class CubicBezierPage extends StatelessWidget {
return const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Bezier(Colors.amber, 1.0),
],
children: <Widget>[Bezier(Colors.amber, 1.0)],
),
);
}
@ -47,8 +45,7 @@ class Bezier extends StatelessWidget {
bezier2Path.cubicTo(0.0, 70.55, 42.0, 31.55, 69.91, 14.77);
bezier2Path.cubicTo(97.82, -2.01, 149.24, -20.93, 104.37, 59.39);
paths.add(PathDetail(bezier2Path,
translate: <double>[29.45, 151.0], rotation: -1.5708));
paths.add(PathDetail(bezier2Path, translate: <double>[29.45, 151.0], rotation: -1.5708));
// Path 3
final Path bezier3Path = Path();
@ -56,8 +53,7 @@ class Bezier extends StatelessWidget {
bezier3Path.cubicTo(0.0, 69.48, 44.82, 27.92, 69.91, 13.7);
bezier3Path.cubicTo(95.0, -0.52, 149.24, -22.0, 104.37, 58.32);
paths.add(PathDetail(bezier3Path,
translate: <double>[53.0, 200.48], rotation: -3.14159));
paths.add(PathDetail(bezier3Path, translate: <double>[53.0, 200.48], rotation: -3.14159));
// Path 4
final Path bezier4Path = Path();
@ -65,22 +61,22 @@ class Bezier extends StatelessWidget {
bezier4Path.cubicTo(0.0, 69.48, 43.82, 27.92, 69.91, 13.7);
bezier4Path.cubicTo(96.0, -0.52, 149.24, -22.0, 104.37, 58.32);
paths.add(PathDetail(bezier4Path,
translate: <double>[122.48, 77.0], rotation: -4.71239));
paths.add(PathDetail(bezier4Path, translate: <double>[122.48, 77.0], rotation: -4.71239));
return paths;
}
@override
Widget build(BuildContext context) {
return Stack(children: <Widget>[
CustomPaint(
foregroundPainter:
BezierPainter(Colors.grey, 0.0, _getLogoPath(), false),
size: const Size(100.0, 100.0),
),
AnimatedBezier(color, scale, blur: blur),
]);
return Stack(
children: <Widget>[
CustomPaint(
foregroundPainter: BezierPainter(Colors.grey, 0.0, _getLogoPath(), false),
size: const Size(100.0, 100.0),
),
AnimatedBezier(color, scale, blur: blur),
],
);
}
}
@ -110,17 +106,11 @@ class Point {
double y;
}
class AnimatedBezierState extends State<AnimatedBezier>
with SingleTickerProviderStateMixin {
class AnimatedBezierState extends State<AnimatedBezier> with SingleTickerProviderStateMixin {
late AnimationController controller;
late CurvedAnimation curve;
bool isPlaying = false;
List<List<Point>> pointList = <List<Point>>[
<Point>[],
<Point>[],
<Point>[],
<Point>[],
];
List<List<Point>> pointList = <List<Point>>[<Point>[], <Point>[], <Point>[], <Point>[]];
bool isReversed = false;
List<PathDetail> _playForward() {
@ -169,8 +159,7 @@ class AnimatedBezierState extends State<AnimatedBezier>
bezier2Path.lineTo(p.x, p.y);
}
paths.add(PathDetail(bezier2Path,
translate: <double>[29.45, 151.0], rotation: -1.5708));
paths.add(PathDetail(bezier2Path, translate: <double>[29.45, 151.0], rotation: -1.5708));
// Path 3
final Path bezier3Path = Path();
@ -190,8 +179,7 @@ class AnimatedBezierState extends State<AnimatedBezier>
bezier3Path.lineTo(p.x, p.y);
}
paths.add(PathDetail(bezier3Path,
translate: <double>[53.0, 200.48], rotation: -3.14159));
paths.add(PathDetail(bezier3Path, translate: <double>[53.0, 200.48], rotation: -3.14159));
// Path 4
final Path bezier4Path = Path();
@ -212,8 +200,7 @@ class AnimatedBezierState extends State<AnimatedBezier>
bezier4Path.lineTo(p.x, p.y);
}
paths.add(PathDetail(bezier4Path,
translate: <double>[122.48, 77.0], rotation: -4.71239));
paths.add(PathDetail(bezier4Path, translate: <double>[122.48, 77.0], rotation: -4.71239));
return paths;
}
@ -260,8 +247,7 @@ class AnimatedBezierState extends State<AnimatedBezier>
return <PathDetail>[
PathDetail(path),
PathDetail(bezier2Path, translate: <double>[29.45, 151.0], rotation: -1.5708),
PathDetail(bezier3Path,
translate: <double>[53.0, 200.48], rotation: -3.14159),
PathDetail(bezier3Path, translate: <double>[53.0, 200.48], rotation: -3.14159),
PathDetail(bezier4Path, translate: <double>[122.48, 77.0], rotation: -4.71239),
];
}
@ -308,23 +294,23 @@ class AnimatedBezierState extends State<AnimatedBezier>
@override
void initState() {
super.initState();
controller = AnimationController(
vsync: this, duration: const Duration(milliseconds: 1000));
controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 1000));
// Animations are typically implemented using the AnimatedBuilder widget.
// This code uses a manual listener for historical reasons and will remain
// in order to preserve compatibility with the history of measurements for
// this benchmark.
curve = CurvedAnimation(parent: controller, curve: Curves.linear)
..addListener(() {
setState(() {});
})
..addStatusListener((AnimationStatus status) {
if (status.isCompleted) {
reverseAnimation();
} else if (status.isDismissed) {
playAnimation();
}
});
curve =
CurvedAnimation(parent: controller, curve: Curves.linear)
..addListener(() {
setState(() {});
})
..addStatusListener((AnimationStatus status) {
if (status.isCompleted) {
reverseAnimation();
} else if (status.isDismissed) {
playAnimation();
}
});
playAnimation();
}
@ -338,9 +324,14 @@ class AnimatedBezierState extends State<AnimatedBezier>
@override
Widget build(BuildContext context) {
return CustomPaint(
foregroundPainter: BezierPainter(widget.color,
curve.value * widget.blur, _getLogoPath(), isPlaying),
size: const Size(100.0, 100.0));
foregroundPainter: BezierPainter(
widget.color,
curve.value * widget.blur,
_getLogoPath(),
isPlaying,
),
size: const Size(100.0, 100.0),
);
}
}

View File

@ -38,19 +38,25 @@ class _CullOpacityPageState extends State<CullOpacityPage> with SingleTickerProv
@override
Widget build(BuildContext context) {
return Stack(children: List<Widget>.generate(50, (int i) => Positioned(
left: 0,
top: (200 * i).toDouble() + _offsetY.value,
child: Opacity(
opacity: 0.5,
child: RepaintBoundary(
child: Container(
// Slightly change width to invalidate raster cache.
width: 1000 - (_offsetY.value / 100),
height: 100, color: Colors.red,
return Stack(
children: List<Widget>.generate(
50,
(int i) => Positioned(
left: 0,
top: (200 * i).toDouble() + _offsetY.value,
child: Opacity(
opacity: 0.5,
child: RepaintBoundary(
child: Container(
// Slightly change width to invalidate raster cache.
width: 1000 - (_offsetY.value / 100),
height: 100,
color: Colors.red,
),
),
),
),
),
)));
);
}
}

View File

@ -7,13 +7,13 @@ import 'dart:ui' as ui;
import 'package:flutter/material.dart';
Future<ui.Image> loadImage(String asset) async {
final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromAsset(asset);
final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromAsset(asset);
final ui.Codec codec = await PaintingBinding.instance.instantiateImageCodecWithSize(buffer);
final ui.FrameInfo frameInfo = await codec.getNextFrame();
return frameInfo.image;
}
class DrawAtlasPage extends StatefulWidget {
class DrawAtlasPage extends StatefulWidget {
const DrawAtlasPage({super.key});
@override
@ -28,7 +28,9 @@ class _DrawAtlasPageState extends State<DrawAtlasPage> with SingleTickerProvider
@override
void initState() {
super.initState();
loadImage('packages/flutter_gallery_assets/food/butternut_squash_soup.png').then((ui.Image pending) {
loadImage('packages/flutter_gallery_assets/food/butternut_squash_soup.png').then((
ui.Image pending,
) {
setState(() {
image = pending;
});
@ -48,7 +50,6 @@ class _DrawAtlasPageState extends State<DrawAtlasPage> with SingleTickerProvider
super.dispose();
}
@override
Widget build(BuildContext context) {
if (image == null) {
@ -73,39 +74,75 @@ class VerticesPainter extends CustomPainter {
canvas.translate(0, tick);
canvas.drawAtlas(
image,
<RSTransform>[RSTransform.fromComponents(rotation: 0, scale: 1, anchorX: 0, anchorY: 0, translateX: 0, translateY: 0)],
<RSTransform>[
RSTransform.fromComponents(
rotation: 0,
scale: 1,
anchorX: 0,
anchorY: 0,
translateX: 0,
translateY: 0,
),
],
<Rect>[Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble())],
<Color>[Colors.red],
BlendMode.plus,
null,
Paint()
Paint(),
);
canvas.drawAtlas(
image,
<RSTransform>[RSTransform.fromComponents(rotation: 0, scale: 1, anchorX: 0, anchorY: 0, translateX: 250, translateY: 0)],
<RSTransform>[
RSTransform.fromComponents(
rotation: 0,
scale: 1,
anchorX: 0,
anchorY: 0,
translateX: 250,
translateY: 0,
),
],
<Rect>[Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble())],
<Color>[Colors.green],
BlendMode.plus,
null,
Paint()
Paint(),
);
canvas.drawAtlas(
image,
<RSTransform>[RSTransform.fromComponents(rotation: 0, scale: 1, anchorX: 0, anchorY: 0, translateX: 0, translateY: 250)],
<RSTransform>[
RSTransform.fromComponents(
rotation: 0,
scale: 1,
anchorX: 0,
anchorY: 0,
translateX: 0,
translateY: 250,
),
],
<Rect>[Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble())],
<Color>[Colors.blue],
BlendMode.plus,
null,
Paint()
Paint(),
);
canvas.drawAtlas(
image,
<RSTransform>[RSTransform.fromComponents(rotation: 0, scale: 1, anchorX: 0, anchorY: 0, translateX: 250, translateY: 250)],
<RSTransform>[
RSTransform.fromComponents(
rotation: 0,
scale: 1,
anchorX: 0,
anchorY: 0,
translateX: 250,
translateY: 250,
),
],
<Rect>[Rect.fromLTWH(0, 0, image.width.toDouble(), image.height.toDouble())],
<Color>[Colors.yellow],
BlendMode.plus,
null,
Paint()
Paint(),
);
}

View File

@ -7,7 +7,7 @@ import 'dart:ui';
import 'package:flutter/material.dart';
class DrawPointsPage extends StatefulWidget {
class DrawPointsPage extends StatefulWidget {
const DrawPointsPage({super.key});
@override
@ -36,7 +36,6 @@ class _DrawPointsPageState extends State<DrawPointsPage> with SingleTickerProvid
super.dispose();
}
@override
Widget build(BuildContext context) {
return CustomPaint(
@ -77,11 +76,12 @@ class PointsPainter extends CustomPainter {
data[j] = x;
data[j + 1] = (size.height / (j + 1)) + 200;
}
final Paint paint = Paint()
..color = kColors[i]
..strokeWidth = 5
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke;
final Paint paint =
Paint()
..color = kColors[i]
..strokeWidth = 5
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke;
canvas.drawRawPoints(PointMode.points, data, paint);
}
}

View File

@ -7,13 +7,13 @@ import 'dart:ui' as ui;
import 'package:flutter/material.dart';
Future<ui.Image> loadImage(String asset) async {
final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromAsset(asset);
final ui.ImmutableBuffer buffer = await ui.ImmutableBuffer.fromAsset(asset);
final ui.Codec codec = await PaintingBinding.instance.instantiateImageCodecWithSize(buffer);
final ui.FrameInfo frameInfo = await codec.getNextFrame();
return frameInfo.image;
}
class DrawVerticesPage extends StatefulWidget {
class DrawVerticesPage extends StatefulWidget {
const DrawVerticesPage({super.key});
@override
@ -28,7 +28,9 @@ class _DrawVerticesPageState extends State<DrawVerticesPage> with SingleTickerPr
@override
void initState() {
super.initState();
loadImage('packages/flutter_gallery_assets/food/butternut_squash_soup.png').then((ui.Image pending) {
loadImage('packages/flutter_gallery_assets/food/butternut_squash_soup.png').then((
ui.Image pending,
) {
setState(() {
image = pending;
});
@ -48,7 +50,6 @@ class _DrawVerticesPageState extends State<DrawVerticesPage> with SingleTickerPr
super.dispose();
}
@override
Widget build(BuildContext context) {
if (image == null) {
@ -79,7 +80,7 @@ class VerticesPainter extends CustomPainter {
Offset(250, 0),
Offset(0, 250),
Offset(250, 0),
Offset(250, 250)
Offset(250, 250),
],
textureCoordinates: <Offset>[
Offset.zero,
@ -87,24 +88,37 @@ class VerticesPainter extends CustomPainter {
Offset(image.width.toDouble(), 0),
Offset(0, image.height.toDouble()),
Offset(image.width.toDouble(), 0),
Offset(image.width.toDouble(), image.height.toDouble())
Offset(image.width.toDouble(), image.height.toDouble()),
],
colors: <Color>[
Colors.red,
Colors.blue,
Colors.green,
Colors.red,
Colors.blue,
Colors.green,
]
colors: <Color>[Colors.red, Colors.blue, Colors.green, Colors.red, Colors.blue, Colors.green],
);
canvas.drawVertices(
vertices,
BlendMode.plus,
Paint()
..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Matrix4.identity().storage),
);
canvas.drawVertices(vertices, BlendMode.plus, Paint()..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Matrix4.identity().storage));
canvas.translate(250, 0);
canvas.drawVertices(vertices, BlendMode.plus, Paint()..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Matrix4.identity().storage));
canvas.drawVertices(
vertices,
BlendMode.plus,
Paint()
..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Matrix4.identity().storage),
);
canvas.translate(0, 250);
canvas.drawVertices(vertices, BlendMode.plus, Paint()..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Matrix4.identity().storage));
canvas.drawVertices(
vertices,
BlendMode.plus,
Paint()
..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Matrix4.identity().storage),
);
canvas.translate(-250, 0);
canvas.drawVertices(vertices, BlendMode.plus, Paint()..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Matrix4.identity().storage));
canvas.drawVertices(
vertices,
BlendMode.plus,
Paint()
..shader = ImageShader(image, TileMode.clamp, TileMode.clamp, Matrix4.identity().storage),
);
}
@override

View File

@ -7,12 +7,11 @@ import 'dart:ui';
import 'package:flutter/material.dart';
enum FilterType {
opacity, rotateTransform, rotateFilter,
}
enum FilterType { opacity, rotateTransform, rotateFilter }
class FilteredChildAnimationPage extends StatefulWidget {
const FilteredChildAnimationPage(this.initialFilterType, {
const FilteredChildAnimationPage(
this.initialFilterType, {
super.key,
this.initialComplexChild = true,
this.initialUseRepaintBoundary = true,
@ -26,7 +25,8 @@ class FilteredChildAnimationPage extends StatefulWidget {
State<FilteredChildAnimationPage> createState() => _FilteredChildAnimationPageState();
}
class _FilteredChildAnimationPageState extends State<FilteredChildAnimationPage> with SingleTickerProviderStateMixin {
class _FilteredChildAnimationPageState extends State<FilteredChildAnimationPage>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
final GlobalKey _childKey = GlobalKey(debugLabel: 'child to animate');
Offset _childCenter = Offset.zero;
@ -60,20 +60,16 @@ class _FilteredChildAnimationPageState extends State<FilteredChildAnimationPage>
}
String get _title => switch (_filterType) {
FilterType.opacity => 'Fading Child Animation',
FilterType.opacity => 'Fading Child Animation',
FilterType.rotateTransform => 'Transformed Child Animation',
FilterType.rotateFilter => 'Matrix Filtered Child Animation',
null => 'Static Child',
FilterType.rotateFilter => 'Matrix Filtered Child Animation',
null => 'Static Child',
};
static Widget _makeChild(int rows, int cols, double fontSize, bool complex) {
final BoxDecoration decoration = BoxDecoration(
color: Colors.green,
boxShadow: complex ? <BoxShadow>[
const BoxShadow(
blurRadius: 10.0,
),
] : null,
boxShadow: complex ? <BoxShadow>[const BoxShadow(blurRadius: 10.0)] : null,
borderRadius: BorderRadius.circular(10.0),
);
return Stack(
@ -81,20 +77,21 @@ class _FilteredChildAnimationPageState extends State<FilteredChildAnimationPage>
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List<Widget>.generate(rows, (int r) => Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List<Widget>.generate(cols, (int c) => Container(
decoration: decoration,
child: Text('text', style: TextStyle(fontSize: fontSize)),
)),
)),
),
const Text('child',
style: TextStyle(
color: Colors.blue,
fontSize: 36,
children: List<Widget>.generate(
rows,
(int r) => Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: List<Widget>.generate(
cols,
(int c) => Container(
decoration: decoration,
child: Text('text', style: TextStyle(fontSize: fontSize)),
),
),
),
),
),
const Text('child', style: TextStyle(color: Colors.blue, fontSize: 36)),
],
);
}
@ -109,27 +106,29 @@ class _FilteredChildAnimationPageState extends State<FilteredChildAnimationPage>
Widget Function(BuildContext, Widget?) builder;
switch (filterType) {
case FilterType.opacity:
builder = (BuildContext context, Widget? child) => Opacity(
opacity: (_controller.value * 2.0 - 1.0).abs(),
child: child,
);
builder =
(BuildContext context, Widget? child) =>
Opacity(opacity: (_controller.value * 2.0 - 1.0).abs(), child: child);
case FilterType.rotateTransform:
builder = (BuildContext context, Widget? child) => Transform(
transform: Matrix4.rotationZ(_controller.value * 2.0 * pi),
alignment: Alignment.center,
filterQuality: FilterQuality.low,
child: child,
);
builder =
(BuildContext context, Widget? child) => Transform(
transform: Matrix4.rotationZ(_controller.value * 2.0 * pi),
alignment: Alignment.center,
filterQuality: FilterQuality.low,
child: child,
);
case FilterType.rotateFilter:
builder = (BuildContext context, Widget? child) => ImageFiltered(
imageFilter: ImageFilter.matrix((
Matrix4.identity()
..translate(_childCenter.dx, _childCenter.dy)
..rotateZ(_controller.value * 2.0 * pi)
..translate(- _childCenter.dx, - _childCenter.dy)
).storage),
child: child,
);
builder =
(BuildContext context, Widget? child) => ImageFiltered(
imageFilter: ImageFilter.matrix(
(Matrix4.identity()
..translate(_childCenter.dx, _childCenter.dy)
..rotateZ(_controller.value * 2.0 * pi)
..translate(-_childCenter.dx, -_childCenter.dy))
.storage,
),
child: child,
);
}
return RepaintBoundary(
child: AnimatedBuilder(
@ -143,9 +142,7 @@ class _FilteredChildAnimationPageState extends State<FilteredChildAnimationPage>
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(_title),
),
appBar: AppBar(title: Text(_title)),
body: Center(
child: _animate(
child: Container(
@ -153,9 +150,7 @@ class _FilteredChildAnimationPageState extends State<FilteredChildAnimationPage>
color: Colors.yellow,
width: 300,
height: 300,
child: Center(
child: _makeChild(4, 3, 24.0, _complexChild),
),
child: Center(child: _makeChild(4, 3, 24.0, _complexChild)),
),
protectChild: _useRepaintBoundary,
),

View File

@ -4,48 +4,49 @@
import 'package:flutter/material.dart';
const String textLotsOfText = 'Lorem ipsum dolor sit amet, consectetur '
'adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna '
'aliqua. Odio facilisis mauris sit amet massa. Tellus pellentesque eu '
'tincidunt tortor aliquam nulla facilisi cras fermentum. Sit amet risus nullam '
'eget felis eget nunc. Placerat in egestas erat imperdiet sed. Vestibulum '
'mattis ullamcorper velit sed. At auctor urna nunc id cursus metus aliquam. In '
'nibh mauris cursus mattis. Quis blandit turpis cursus in hac habitasse platea '
'dictumst. Orci a scelerisque purus semper eget duis at tellus. At tempor '
'commodo ullamcorper a lacus. At auctor urna nunc id cursus metus aliquam '
'eleifend. Sagittis aliquam malesuada bibendum arcu vitae elementum. Massa sed '
'elementum tempus egestas sed sed risus. Amet consectetur adipiscing elit ut '
'aliquam purus sit amet luctus. Elementum nisi quis eleifend quam adipiscing '
'vitae. Aliquam sem fringilla ut morbi tincidunt augue. '
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦 '
'😀 😃 😄 😁 😆 😅 😂 🤣 🥲 ☺️ 😊 😇 🙂 🙃 😉 😌 😍 🥰 😘 😗 😙 '
'😚 😋 😛 😝 😜 🤪 🤨 🧐 🤓 😎 🥸 🤩 🥳 😏 😒 😞 😔 😟 😕 🙁 ☹ '
'️😣 😖 😫 😩 🥺 😢 😭 😤 😠 😡 🤬 🤯 😳 🥵 🥶 😱 😨 😰 😥 😓 '
'🤗 🤔 🤭 🤫 🤥 😶 😐 😑 😬 🙄 😯 😦 😧 😮 😲 🥱 😴 🤤 😪 😵 '
'🤐 🥴 🤢 🤮 🤧 😷 🤒 🤕 🤑 🤠 😈 👿 👹 👺 🤡 💩 👻 💀 ☠️ 👽 '
'👾 🤖 🎃 😺 😸 😹 😻 😼 😽 🙀 😿 😾 '
'️😣 😖 😫 😩 🥺 😢 😭 😤 😠 😡 🤬 🤯 😳 🥵 🥶 😱 😨 😰 😥 😓 '
'🤗 🤔 🤭 🤫 🤥 😶 😐 😑 😬 🙄 😯 😦 😧 😮 😲 🥱 😴 🤤 😪 😵 '
'🤐 🥴 🤢 🤮 🤧 😷 🤒 🤕 🤑 🤠 😈 👿 👹 👺 🤡 💩 👻 💀 ☠️ 👽 '
'👾 🤖 🎃 😺 😸 😹 😻 😼 😽 🙀 😿 😾 '
'👋 🤚 🖐 ✋ 🖖 👌 🤌 🤏 ✌️ 🤞 🤟 🤘 🤙 👈 👉 👆 🖕 👇 ☝️ 👍 👎 '
'✊ 👊 🤛 🤜 👏 🙌 👐 🤲 🤝 🙏 ✍️ 💅 🤳 💪 🦾 🦵 🦿 🦶 👣 👂 '
'🦻 👃 🫀 🫁 🧠 🦷 🦴 👀 👁 👅 👄 💋 🩸';
const String textLotsOfText =
'Lorem ipsum dolor sit amet, consectetur '
'adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna '
'aliqua. Odio facilisis mauris sit amet massa. Tellus pellentesque eu '
'tincidunt tortor aliquam nulla facilisi cras fermentum. Sit amet risus nullam '
'eget felis eget nunc. Placerat in egestas erat imperdiet sed. Vestibulum '
'mattis ullamcorper velit sed. At auctor urna nunc id cursus metus aliquam. In '
'nibh mauris cursus mattis. Quis blandit turpis cursus in hac habitasse platea '
'dictumst. Orci a scelerisque purus semper eget duis at tellus. At tempor '
'commodo ullamcorper a lacus. At auctor urna nunc id cursus metus aliquam '
'eleifend. Sagittis aliquam malesuada bibendum arcu vitae elementum. Massa sed '
'elementum tempus egestas sed sed risus. Amet consectetur adipiscing elit ut '
'aliquam purus sit amet luctus. Elementum nisi quis eleifend quam adipiscing '
'vitae. Aliquam sem fringilla ut morbi tincidunt augue. '
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦'
'👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦👨‍👩‍👦 '
'😀 😃 😄 😁 😆 😅 😂 🤣 🥲 ☺️ 😊 😇 🙂 🙃 😉 😌 😍 🥰 😘 😗 😙 '
'😚 😋 😛 😝 😜 🤪 🤨 🧐 🤓 😎 🥸 🤩 🥳 😏 😒 😞 😔 😟 😕 🙁 ☹ '
'️😣 😖 😫 😩 🥺 😢 😭 😤 😠 😡 🤬 🤯 😳 🥵 🥶 😱 😨 😰 😥 😓 '
'🤗 🤔 🤭 🤫 🤥 😶 😐 😑 😬 🙄 😯 😦 😧 😮 😲 🥱 😴 🤤 😪 😵 '
'🤐 🥴 🤢 🤮 🤧 😷 🤒 🤕 🤑 🤠 😈 👿 👹 👺 🤡 💩 👻 💀 ☠️ 👽 '
'👾 🤖 🎃 😺 😸 😹 😻 😼 😽 🙀 😿 😾 '
'️😣 😖 😫 😩 🥺 😢 😭 😤 😠 😡 🤬 🤯 😳 🥵 🥶 😱 😨 😰 😥 😓 '
'🤗 🤔 🤭 🤫 🤥 😶 😐 😑 😬 🙄 😯 😦 😧 😮 😲 🥱 😴 🤤 😪 😵 '
'🤐 🥴 🤢 🤮 🤧 😷 🤒 🤕 🤑 🤠 😈 👿 👹 👺 🤡 💩 👻 💀 ☠️ 👽 '
'👾 🤖 🎃 😺 😸 😹 😻 😼 😽 🙀 😿 😾 '
'👋 🤚 🖐 ✋ 🖖 👌 🤌 🤏 ✌️ 🤞 🤟 🤘 🤙 👈 👉 👆 🖕 👇 ☝️ 👍 👎 '
'✊ 👊 🤛 🤜 👏 🙌 👐 🤲 🤝 🙏 ✍️ 💅 🤳 💪 🦾 🦵 🦿 🦶 👣 👂 '
'🦻 👃 🫀 🫁 🧠 🦷 🦴 👀 👁 👅 👄 💋 🩸';
class TextFieldPage extends StatelessWidget {
const TextFieldPage({super.key});

View File

@ -11,7 +11,8 @@ import '../common.dart';
Map<String, WidgetBuilder> gradientPerfRoutes = <String, WidgetBuilder>{
kGradientPerfRecreateDynamicRouteName: (BuildContext _) => const RecreateDynamicPainterPage(),
kGradientPerfRecreateConsistentRouteName: (BuildContext _) => const RecreateConsistentPainterPage(),
kGradientPerfRecreateConsistentRouteName:
(BuildContext _) => const RecreateConsistentPainterPage(),
kGradientPerfStaticConsistentRouteName: (BuildContext _) => const StaticConsistentPainterPage(),
};
@ -66,7 +67,7 @@ class _PainterPage extends StatefulWidget {
class RecreateDynamicPainterPage extends _PainterPage {
const RecreateDynamicPainterPage({super.key})
: super(title: 'Recreate Dynamic Gradients', factory: makePainter);
: super(title: 'Recreate Dynamic Gradients', factory: makePainter);
static CustomPainter makePainter(double f) {
return RecreatedDynamicGradients(baseFactor: f);
@ -75,7 +76,7 @@ class RecreateDynamicPainterPage extends _PainterPage {
class RecreateConsistentPainterPage extends _PainterPage {
const RecreateConsistentPainterPage({super.key})
: super(title: 'Recreate Same Gradients', factory: makePainter);
: super(title: 'Recreate Same Gradients', factory: makePainter);
static CustomPainter makePainter(double f) {
return RecreatedConsistentGradients(baseFactor: f);
@ -84,7 +85,7 @@ class RecreateConsistentPainterPage extends _PainterPage {
class StaticConsistentPainterPage extends _PainterPage {
const StaticConsistentPainterPage({super.key})
: super(title: 'Reuse Same Gradients', factory: makePainter);
: super(title: 'Reuse Same Gradients', factory: makePainter);
static CustomPainter makePainter(double f) {
return StaticConsistentGradients(baseFactor: f);
@ -110,9 +111,7 @@ class _PainterPageState extends State<_PainterPage> with SingleTickerProviderSta
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
appBar: AppBar(title: Text(widget.title)),
body: Center(
child: AnimatedBuilder(
animation: _controller,
@ -155,16 +154,13 @@ Color color(double factor) {
}
Shader rotatingGradient(double factor, double x, double y, double h) {
final double s = sin(factor * 2 * pi) * h/8;
final double c = cos(factor * 2 * pi) * h/8;
final double s = sin(factor * 2 * pi) * h / 8;
final double c = cos(factor * 2 * pi) * h / 8;
final double cx = x;
final double cy = y + h/2;
final double cy = y + h / 2;
final Offset p0 = Offset(cx + s, cy + c);
final Offset p1 = Offset(cx - s, cy - c);
return ui.Gradient.linear(p0, p1, <Color>[
color(factor),
color(factor + 0.5),
]);
return ui.Gradient.linear(p0, p1, <Color>[color(factor), color(factor + 0.5)]);
}
const int nAcross = 12;
@ -185,8 +181,8 @@ double y(int i, int j) {
}
Shader gradient(double baseFactor, int i, int j) {
final double lineFactor = baseFactor + 1/3 + 0.5 * (j + 1) / (nDown + 1);
final double cellFactor = lineFactor + 1/3 * (i + 1) / (nAcross + 1);
final double lineFactor = baseFactor + 1 / 3 + 0.5 * (j + 1) / (nDown + 1);
final double cellFactor = lineFactor + 1 / 3 * (i + 1) / (nAcross + 1);
return rotatingGradient(cellFactor, x(i, j) + cellW / 2, y(i, j), cellH);
}
@ -240,11 +236,7 @@ class StaticConsistentGradients extends CustomPainter {
final double baseFactor;
static List<List<Shader>> gradients = <List<Shader>>[
for (int j = 0; j < nDown; j++)
<Shader>[
for (int i = 0; i < nAcross; i++)
gradient(0, i, j),
],
for (int j = 0; j < nDown; j++) <Shader>[for (int i = 0; i < nAcross; i++) gradient(0, i, j)],
];
@override

View File

@ -25,10 +25,6 @@ class HeavyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SizedBox(
width: 200,
height: 200,
child: Text('$index: ${_weight.length}'),
);
return SizedBox(width: 200, height: 200, child: Text('$index: ${_weight.length}'));
}
}

View File

@ -18,21 +18,19 @@ class ColumnOfTextState extends State<ColumnOfText> with SingleTickerProviderSta
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 300),
)
..addStatusListener((AnimationStatus status) {
if (status.isCompleted) {
setState(() {
_showText = !_showText;
});
_controller
..reset()
..forward();
}
})
..forward();
_controller =
AnimationController(vsync: this, duration: const Duration(milliseconds: 300))
..addStatusListener((AnimationStatus status) {
if (status.isCompleted) {
setState(() {
_showText = !_showText;
});
_controller
..reset()
..forward();
}
})
..forward();
}
@override
@ -47,22 +45,21 @@ class ColumnOfTextState extends State<ColumnOfText> with SingleTickerProviderSta
child: OverflowBox(
alignment: Alignment.topCenter,
maxHeight: double.infinity,
child: !_showText
? Container()
: Column(
children: List<Widget>.generate(9, (int index) {
return ListTile(
leading: CircleAvatar(
child: Text('G$index'),
),
title: Text(
'Foo contact from $index-th local contact',
overflow: TextOverflow.ellipsis,
),
subtitle: Text('+91 88888 8800$index'),
);
}),
),
child:
!_showText
? Container()
: Column(
children: List<Widget>.generate(9, (int index) {
return ListTile(
leading: CircleAvatar(child: Text('G$index')),
title: Text(
'Foo contact from $index-th local contact',
overflow: TextOverflow.ellipsis,
),
subtitle: Text('+91 88888 8800$index'),
);
}),
),
),
);
}

View File

@ -17,9 +17,21 @@ class MultiWidgetConstructTable extends StatefulWidget {
class _MultiWidgetConstructTableState extends State<MultiWidgetConstructTable>
with SingleTickerProviderStateMixin {
static const List<MaterialColor> colorList = <MaterialColor>[
Colors.pink, Colors.red, Colors.deepOrange, Colors.orange, Colors.amber,
Colors.yellow, Colors.lime, Colors.lightGreen, Colors.green, Colors.teal,
Colors.cyan, Colors.lightBlue, Colors.blue, Colors.indigo, Colors.purple,
Colors.pink,
Colors.red,
Colors.deepOrange,
Colors.orange,
Colors.amber,
Colors.yellow,
Colors.lime,
Colors.lightGreen,
Colors.green,
Colors.teal,
Colors.cyan,
Colors.lightBlue,
Colors.blue,
Colors.indigo,
Colors.purple,
];
int counter = 0;
@ -60,32 +72,27 @@ class _MultiWidgetConstructTableState extends State<MultiWidgetConstructTable>
children: List<TableRow>.generate(
widget.rowCount,
(int row) => TableRow(
children: List<Widget>.generate(
widget.columnCount,
(int column) {
final int label = row * widget.columnCount + column;
// This implementation rebuild the widget tree for every
// frame, and is intentionally designed of poor performance
// for benchmark purposes.
return counter.isEven
? Container(
// This key forces rebuilding the element
key: ValueKey<int>(widgetCounter + label),
color: Color.lerp(
Colors.white, baseColor, label / totalLength),
constraints: BoxConstraints.expand(height: height),
child: Text('${widgetCounter + label}'),
)
: MyContainer(
// This key forces rebuilding the element
key: ValueKey<int>(widgetCounter + label),
color: Color.lerp(
Colors.white, baseColor, label / totalLength)!,
constraints: BoxConstraints.expand(height: height),
child: Text('${widgetCounter + label}'),
);
},
),
children: List<Widget>.generate(widget.columnCount, (int column) {
final int label = row * widget.columnCount + column;
// This implementation rebuild the widget tree for every
// frame, and is intentionally designed of poor performance
// for benchmark purposes.
return counter.isEven
? Container(
// This key forces rebuilding the element
key: ValueKey<int>(widgetCounter + label),
color: Color.lerp(Colors.white, baseColor, label / totalLength),
constraints: BoxConstraints.expand(height: height),
child: Text('${widgetCounter + label}'),
)
: MyContainer(
// This key forces rebuilding the element
key: ValueKey<int>(widgetCounter + label),
color: Color.lerp(Colors.white, baseColor, label / totalLength)!,
constraints: BoxConstraints.expand(height: height),
child: Text('${widgetCounter + label}'),
);
}),
),
),
),
@ -97,17 +104,18 @@ class _MultiWidgetConstructTableState extends State<MultiWidgetConstructTable>
// This class is intended to break the original Widget tree
class MyContainer extends StatelessWidget {
const MyContainer({required this.color, required this.child, required this.constraints, super.key});
const MyContainer({
required this.color,
required this.child,
required this.constraints,
super.key,
});
final Color color;
final Widget child;
final BoxConstraints constraints;
@override
Widget build(BuildContext context) {
return Container(
color: color,
constraints: constraints,
child: child,
);
return Container(color: color, constraints: constraints, child: child);
}
}

View File

@ -44,18 +44,25 @@ int _green(double v) => _red(1 - v);
int _blue(double v) => 0;
class OpacityPeepholeCase {
OpacityPeepholeCase.forValue({required String route, required String name, required ValueBuilder builder})
: this.forAnimation(
route: route,
name: name,
builder: (Animation<double> animation) => AnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget? child) => builder(animation.value),
),
);
OpacityPeepholeCase.forValue({
required String route,
required String name,
required ValueBuilder builder,
}) : this.forAnimation(
route: route,
name: name,
builder:
(Animation<double> animation) => AnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget? child) => builder(animation.value),
),
);
OpacityPeepholeCase.forAnimation({required this.route, required this.name, required AnimationBuilder builder})
: animationBuilder = builder;
OpacityPeepholeCase.forAnimation({
required this.route,
required this.name,
required AnimationBuilder builder,
}) : animationBuilder = builder;
final String route;
final String name;
@ -80,7 +87,7 @@ List<OpacityPeepholeCase> allOpacityPeepholeCases = <OpacityPeepholeCase>[
color: Color.fromARGB(255, _red(v), _green(v), _blue(v)),
),
);
}
},
),
// Tests that a column of Opacity widgets can individually hand their values down to simple children
OpacityPeepholeCase.forValue(
@ -108,32 +115,32 @@ List<OpacityPeepholeCase> allOpacityPeepholeCases = <OpacityPeepholeCase>[
),
// Tests that an Opacity can hand value down to a cached child
OpacityPeepholeCase.forValue(
route: kOpacityPeepholeOpacityOfCachedChildRouteName,
name: 'Opacity of Cached Child',
builder: (double v) {
// ChildV starts as a constant so the same color pattern always appears and the child will be cached
double childV = 0;
return Opacity(
opacity: _opacity(v),
child: RepaintBoundary(
child: SizedBox(
width: 300,
height: 400,
child: Stack(
children: <Widget>[
for (double i = 0; i < 100; i += 10, childV = 1 - childV)
Positioned.fromRelativeRect(
rect: RelativeRect.fromLTRB(i, i, i, i),
child: Container(
color: Color.fromARGB(255, _red(childV), _green(childV), _blue(childV)),
),
route: kOpacityPeepholeOpacityOfCachedChildRouteName,
name: 'Opacity of Cached Child',
builder: (double v) {
// ChildV starts as a constant so the same color pattern always appears and the child will be cached
double childV = 0;
return Opacity(
opacity: _opacity(v),
child: RepaintBoundary(
child: SizedBox(
width: 300,
height: 400,
child: Stack(
children: <Widget>[
for (double i = 0; i < 100; i += 10, childV = 1 - childV)
Positioned.fromRelativeRect(
rect: RelativeRect.fromLTRB(i, i, i, i),
child: Container(
color: Color.fromARGB(255, _red(childV), _green(childV), _blue(childV)),
),
],
),
),
],
),
),
);
}
),
);
},
),
// Tests that an Opacity can hand a value down to a Column of simple non-overlapping children
OpacityPeepholeCase.forValue(
@ -277,11 +284,7 @@ List<OpacityPeepholeCase> allOpacityPeepholeCases = <OpacityPeepholeCase>[
child: const SizedBox(
width: 300,
height: 400,
child: Center(
child: Text('Hello, World',
style: TextStyle(fontSize: 48),
),
),
child: Center(child: Text('Hello, World', style: TextStyle(fontSize: 48))),
),
);
},
@ -414,8 +417,7 @@ class RectGridPainter extends CustomPainter {
}
Map<String, WidgetBuilder> opacityPeepholeRoutes = <String, WidgetBuilder>{
for (OpacityPeepholeCase variant in allOpacityPeepholeCases)
variant.route: variant.buildPage,
for (OpacityPeepholeCase variant in allOpacityPeepholeCases) variant.route: variant.buildPage,
};
class VariantPage extends StatefulWidget {
@ -448,12 +450,8 @@ class VariantPageState extends State<VariantPage> with SingleTickerProviderState
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.variant.name),
),
body: Center(
child: widget.variant.animationBuilder(_controller),
),
appBar: AppBar(title: Text(widget.variant.name)),
body: Center(child: widget.variant.animationBuilder(_controller)),
);
}
}

View File

@ -18,8 +18,7 @@ class _PathTessellationPageState extends State<PathTessellationPage>
@override
void initState() {
super.initState();
_controller =
AnimationController(vsync: this, lowerBound: 1.0, upperBound: 1.3);
_controller = AnimationController(vsync: this, lowerBound: 1.0, upperBound: 1.3);
_controller.addListener(() {
setState(() {});
});
@ -35,14 +34,11 @@ class _PathTessellationPageState extends State<PathTessellationPage>
fit: StackFit.expand,
children: <Widget>[
ListView.builder(
key: const Key(
'list_view'), // this key is used by the driver test,
key: const Key('list_view'), // this key is used by the driver test,
itemBuilder: (BuildContext context, int index) {
return Container(
margin: const EdgeInsets.all(1.0),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
),
decoration: BoxDecoration(color: Colors.white.withOpacity(0.2)),
child: IconRow(iconSize: (30 + 0.5 * (index % 10)) * scale),
);
},
@ -68,23 +64,16 @@ class _PathTessellationPageState extends State<PathTessellationPage>
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
SizedBox(
height: 100,
child: IconRow(iconSize: 55.0 * scale),
),
SizedBox(height: 100, child: IconRow(iconSize: 55.0 * scale)),
MaterialButton(
textColor: Colors.white,
key: const Key(
'animate_button'), // this key is used by the driver test
key: const Key('animate_button'), // this key is used by the driver test
child: const Text('Animate'),
onPressed: () {
if (_controller.isAnimating) {
_controller.stop();
} else {
_controller.repeat(
period: const Duration(seconds: 1),
reverse: true,
);
_controller.repeat(period: const Duration(seconds: 1), reverse: true);
}
},
),
@ -100,10 +89,7 @@ class _PathTessellationPageState extends State<PathTessellationPage>
}
class IconRow extends StatelessWidget {
const IconRow({
super.key,
required this.iconSize,
});
const IconRow({super.key, required this.iconSize});
final double iconSize;
@ -114,38 +100,23 @@ class IconRow extends StatelessWidget {
children: <Widget>[
SizedBox.square(
dimension: iconSize,
child: CustomPaint(
painter: _SettingsIconPainter(),
willChange: true,
),
child: CustomPaint(painter: _SettingsIconPainter(), willChange: true),
),
SizedBox.square(
dimension: iconSize,
child: CustomPaint(
painter: _CameraIconPainter(),
willChange: true,
),
child: CustomPaint(painter: _CameraIconPainter(), willChange: true),
),
SizedBox.square(
dimension: iconSize,
child: CustomPaint(
painter: _CalendarIconPainter(),
willChange: true,
),
child: CustomPaint(painter: _CalendarIconPainter(), willChange: true),
),
SizedBox.square(
dimension: iconSize,
child: CustomPaint(
painter: _ConversationIconPainter(),
willChange: true,
),
child: CustomPaint(painter: _ConversationIconPainter(), willChange: true),
),
SizedBox.square(
dimension: iconSize,
child: CustomPaint(
painter: _GeometryIconPainter(),
willChange: true,
),
child: CustomPaint(painter: _GeometryIconPainter(), willChange: true),
),
],
);
@ -175,8 +146,14 @@ Path _pathFromString(String pathString) {
path.lineTo(arguments[0], arguments[1]);
current = Offset(arguments[0], arguments[1]);
case 'C':
path.cubicTo(arguments[0], arguments[1], arguments[2], arguments[3],
arguments[4], arguments[5]);
path.cubicTo(
arguments[0],
arguments[1],
arguments[2],
arguments[3],
arguments[4],
arguments[5],
);
current = Offset(arguments[4], arguments[5]);
case 'H':
path.lineTo(arguments[0], current.dy);
@ -206,8 +183,7 @@ Path _pathFromString(String pathString) {
class _SettingsIconPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final Matrix4 scale =
Matrix4.diagonal3Values(size.width / 20, size.height / 20, 1.0);
final Matrix4 scale = Matrix4.diagonal3Values(size.width / 20, size.height / 20, 1.0);
Path path;
path = _path1.transform(scale.storage)..fillType = PathFillType.evenOdd;
@ -221,11 +197,14 @@ class _SettingsIconPainter extends CustomPainter {
}
static final Path _path1 = _pathFromString(
'M8.3252 2.675L7.7877 4.0625L5.93771 5.1125L4.4627 4.8875C4.2171 4.85416 3.96713 4.89459 3.74456 5.00365C3.52199 5.11271 3.33686 5.28548 3.21271 5.5L2.7127 6.375C2.58458 6.59294 2.52555 6.8446 2.5434 7.09678C2.56126 7.34895 2.65516 7.58979 2.8127 7.7875L3.7502 8.95V11.05L2.8377 12.2125C2.68016 12.4102 2.58626 12.651 2.5684 12.9032C2.55055 13.1554 2.60958 13.4071 2.73771 13.625L3.2377 14.5C3.36186 14.7145 3.54699 14.8873 3.76956 14.9963C3.99213 15.1054 4.2421 15.1458 4.4877 15.1125L5.96271 14.8875L7.7877 15.9375L8.3252 17.325C8.41585 17.5599 8.57534 17.762 8.78277 17.9047C8.9902 18.0475 9.2359 18.1243 9.48771 18.125H10.5377C10.7895 18.1243 11.0352 18.0475 11.2426 17.9047C11.4501 17.762 11.6096 17.5599 11.7002 17.325L12.2377 15.9375L14.0627 14.8875L15.5377 15.1125C15.7833 15.1458 16.0333 15.1054 16.2559 14.9963C16.4784 14.8873 16.6636 14.7145 16.7877 14.5L17.2877 13.625C17.4158 13.4071 17.4749 13.1554 17.457 12.9032C17.4392 12.651 17.3453 12.4102 17.1877 12.2125L16.2502 11.05V8.95L17.1627 7.7875C17.3203 7.58979 17.4142 7.34895 17.432 7.09678C17.4499 6.8446 17.3908 6.59294 17.2627 6.375L16.7627 5.5C16.6386 5.28548 16.4534 5.11271 16.2309 5.00365C16.0083 4.89459 15.7583 4.85416 15.5127 4.8875L14.0377 5.1125L12.2127 4.0625L11.6752 2.675C11.5846 2.44008 11.4251 2.23801 11.2176 2.09527C11.0102 1.95252 10.7645 1.87574 10.5127 1.875H9.48771C9.2359 1.87574 8.9902 1.95252 8.78277 2.09527C8.57534 2.23801 8.41585 2.44008 8.3252 2.675ZM10 12.5C11.3807 12.5 12.5 11.3807 12.5 10C12.5 8.61929 11.3807 7.5 10 7.5C8.61929 7.5 7.5 8.61929 7.5 10C7.5 11.3807 8.61929 12.5 10 12.5Z');
'M8.3252 2.675L7.7877 4.0625L5.93771 5.1125L4.4627 4.8875C4.2171 4.85416 3.96713 4.89459 3.74456 5.00365C3.52199 5.11271 3.33686 5.28548 3.21271 5.5L2.7127 6.375C2.58458 6.59294 2.52555 6.8446 2.5434 7.09678C2.56126 7.34895 2.65516 7.58979 2.8127 7.7875L3.7502 8.95V11.05L2.8377 12.2125C2.68016 12.4102 2.58626 12.651 2.5684 12.9032C2.55055 13.1554 2.60958 13.4071 2.73771 13.625L3.2377 14.5C3.36186 14.7145 3.54699 14.8873 3.76956 14.9963C3.99213 15.1054 4.2421 15.1458 4.4877 15.1125L5.96271 14.8875L7.7877 15.9375L8.3252 17.325C8.41585 17.5599 8.57534 17.762 8.78277 17.9047C8.9902 18.0475 9.2359 18.1243 9.48771 18.125H10.5377C10.7895 18.1243 11.0352 18.0475 11.2426 17.9047C11.4501 17.762 11.6096 17.5599 11.7002 17.325L12.2377 15.9375L14.0627 14.8875L15.5377 15.1125C15.7833 15.1458 16.0333 15.1054 16.2559 14.9963C16.4784 14.8873 16.6636 14.7145 16.7877 14.5L17.2877 13.625C17.4158 13.4071 17.4749 13.1554 17.457 12.9032C17.4392 12.651 17.3453 12.4102 17.1877 12.2125L16.2502 11.05V8.95L17.1627 7.7875C17.3203 7.58979 17.4142 7.34895 17.432 7.09678C17.4499 6.8446 17.3908 6.59294 17.2627 6.375L16.7627 5.5C16.6386 5.28548 16.4534 5.11271 16.2309 5.00365C16.0083 4.89459 15.7583 4.85416 15.5127 4.8875L14.0377 5.1125L12.2127 4.0625L11.6752 2.675C11.5846 2.44008 11.4251 2.23801 11.2176 2.09527C11.0102 1.95252 10.7645 1.87574 10.5127 1.875H9.48771C9.2359 1.87574 8.9902 1.95252 8.78277 2.09527C8.57534 2.23801 8.41585 2.44008 8.3252 2.675ZM10 12.5C11.3807 12.5 12.5 11.3807 12.5 10C12.5 8.61929 11.3807 7.5 10 7.5C8.61929 7.5 7.5 8.61929 7.5 10C7.5 11.3807 8.61929 12.5 10 12.5Z',
);
static final Path _path2 = _pathFromString(
'M9.48771 1.25L9.48586 1.25001C9.10816 1.25112 8.7396 1.36628 8.42845 1.5804C8.11747 1.79441 7.87833 2.0973 7.74232 2.44945L7.2854 3.62894L5.81769 4.46197L4.55695 4.26965L4.54677 4.26818C4.17836 4.21818 3.80341 4.27882 3.46955 4.44241C3.13569 4.606 2.858 4.86515 2.67177 5.18693L2.17177 6.06191C1.98107 6.38797 1.89329 6.76406 1.91997 7.14092C1.94675 7.51918 2.08759 7.88043 2.32392 8.177L3.12521 9.17062V10.834L2.34736 11.825C2.11197 12.1212 1.97169 12.4817 1.94497 12.8591C1.91828 13.236 2.00608 13.6121 2.1968 13.9381L2.69505 14.8101L2.69677 14.8131C2.883 15.1349 3.16069 15.394 3.49455 15.5576C3.82841 15.7212 4.20336 15.7818 4.57177 15.7318L5.84067 15.5383L7.28466 16.3691L7.28539 16.3711L7.74211 17.55C7.87812 17.9021 8.11745 18.2056 8.42843 18.4196C8.73958 18.6337 9.10814 18.7489 9.48584 18.75L9.48769 18.75L10.5145 18.75C10.8922 18.7489 11.2608 18.6337 11.5719 18.4196C11.8829 18.2056 12.1473 17.9021 12.2833 17.55L12.7408 16.3691L14.1847 15.5383L15.4434 15.7304L15.4536 15.7318C15.822 15.7818 16.197 15.7212 16.5309 15.5576C16.8647 15.394 17.1424 15.1349 17.3286 14.8131L17.3304 14.8101L17.8287 13.9381C18.0193 13.612 18.1071 13.2359 18.0804 12.8591C18.0537 12.4808 17.9128 12.1196 17.6765 11.823L16.8752 10.8294V9.166L17.6515 8.177L17.6531 8.17502C17.8884 7.87883 18.0287 7.51834 18.0554 7.14092C18.0821 6.76407 17.9943 6.38798 17.8036 6.06192L17.3054 5.18991L17.3036 5.18693C17.1174 4.86515 16.8397 4.606 16.5059 4.44241C16.172 4.27882 15.797 4.21809 15.4286 4.2681L14.1597 4.46166L12.7158 3.63087L12.258 2.44923C12.122 2.09718 11.8829 1.79437 11.572 1.5804C11.2608 1.36628 10.8923 1.25112 10.5146 1.25L9.48771 1.25ZM10.5116 2.5H9.48879C9.36315 2.50053 9.24059 2.5389 9.13708 2.61013C9.03337 2.68151 8.95363 2.78254 8.9083 2.9L8.3705 4.28827C8.31845 4.42266 8.22154 4.53492 8.09621 4.60606L6.24621 5.65606C6.12411 5.72535 5.98224 5.75153 5.84346 5.73036L4.37442 5.50627C4.25298 5.49062 4.12958 5.51099 4.01957 5.5649C3.90871 5.61922 3.81643 5.70515 3.75436 5.81183L3.25154 6.69178C3.18747 6.80075 3.15792 6.92655 3.16684 7.05264C3.17574 7.17824 3.22235 7.2982 3.30057 7.39684L4.23671 8.55766C4.32633 8.66878 4.37521 8.80724 4.37521 8.95V11.05C4.37521 11.1899 4.32824 11.3258 4.24184 11.4359L3.32651 12.602C3.24773 12.7009 3.20077 12.8213 3.19184 12.9474C3.18292 13.0735 3.21243 13.1993 3.27649 13.3083L3.2804 13.3149L3.77864 14.1869L3.77933 14.1881C3.8414 14.2948 3.93369 14.3808 4.04457 14.4351C4.15457 14.489 4.27796 14.5094 4.39939 14.4937L5.86846 14.2696C6.00848 14.2483 6.15161 14.2751 6.27439 14.3458L8.09939 15.3958C8.22322 15.467 8.3189 15.5785 8.3705 15.7117L8.908 17.0992C8.95333 17.2167 9.03337 17.3185 9.13708 17.3899C9.24061 17.4611 9.36321 17.4995 9.48887 17.5H10.5365C10.6622 17.4995 10.7848 17.4611 10.8883 17.3899C10.992 17.3185 11.0718 17.2175 11.1171 17.1L11.6549 15.7117C11.7065 15.5785 11.8022 15.467 11.926 15.3958L13.751 14.3458C13.8738 14.2751 14.0169 14.2483 14.157 14.2696L15.626 14.4937C15.7475 14.5094 15.8708 14.489 15.9808 14.4351C16.0917 14.3808 16.184 14.2949 16.2461 14.1882L16.2468 14.1869L16.7489 13.3082C16.8129 13.1993 16.8425 13.0735 16.8336 12.9474C16.8247 12.8218 16.7781 12.7019 16.6999 12.6032L16.6989 12.602L15.7637 11.4423C15.6741 11.3312 15.6252 11.1928 15.6252 11.05V8.95C15.6252 8.81006 15.6722 8.67418 15.7586 8.5641L16.6711 7.4016L16.6739 7.398C16.7527 7.29915 16.7996 7.17873 16.8086 7.05264C16.8175 6.92655 16.788 6.80072 16.7239 6.69175L16.72 6.68511L16.2218 5.81307L16.2211 5.81187C16.159 5.70517 16.0667 5.61923 15.9558 5.5649C15.8458 5.51099 15.7224 5.49062 15.601 5.50627L14.132 5.73036C13.9919 5.75172 13.8488 5.72488 13.726 5.65424L11.901 4.60424C11.7772 4.533 11.6815 4.42148 11.6299 4.28827L11.0924 2.90077C11.0471 2.78331 10.967 2.68151 10.8633 2.61013C10.7598 2.5389 10.6373 2.50053 10.5116 2.5Z');
'M9.48771 1.25L9.48586 1.25001C9.10816 1.25112 8.7396 1.36628 8.42845 1.5804C8.11747 1.79441 7.87833 2.0973 7.74232 2.44945L7.2854 3.62894L5.81769 4.46197L4.55695 4.26965L4.54677 4.26818C4.17836 4.21818 3.80341 4.27882 3.46955 4.44241C3.13569 4.606 2.858 4.86515 2.67177 5.18693L2.17177 6.06191C1.98107 6.38797 1.89329 6.76406 1.91997 7.14092C1.94675 7.51918 2.08759 7.88043 2.32392 8.177L3.12521 9.17062V10.834L2.34736 11.825C2.11197 12.1212 1.97169 12.4817 1.94497 12.8591C1.91828 13.236 2.00608 13.6121 2.1968 13.9381L2.69505 14.8101L2.69677 14.8131C2.883 15.1349 3.16069 15.394 3.49455 15.5576C3.82841 15.7212 4.20336 15.7818 4.57177 15.7318L5.84067 15.5383L7.28466 16.3691L7.28539 16.3711L7.74211 17.55C7.87812 17.9021 8.11745 18.2056 8.42843 18.4196C8.73958 18.6337 9.10814 18.7489 9.48584 18.75L9.48769 18.75L10.5145 18.75C10.8922 18.7489 11.2608 18.6337 11.5719 18.4196C11.8829 18.2056 12.1473 17.9021 12.2833 17.55L12.7408 16.3691L14.1847 15.5383L15.4434 15.7304L15.4536 15.7318C15.822 15.7818 16.197 15.7212 16.5309 15.5576C16.8647 15.394 17.1424 15.1349 17.3286 14.8131L17.3304 14.8101L17.8287 13.9381C18.0193 13.612 18.1071 13.2359 18.0804 12.8591C18.0537 12.4808 17.9128 12.1196 17.6765 11.823L16.8752 10.8294V9.166L17.6515 8.177L17.6531 8.17502C17.8884 7.87883 18.0287 7.51834 18.0554 7.14092C18.0821 6.76407 17.9943 6.38798 17.8036 6.06192L17.3054 5.18991L17.3036 5.18693C17.1174 4.86515 16.8397 4.606 16.5059 4.44241C16.172 4.27882 15.797 4.21809 15.4286 4.2681L14.1597 4.46166L12.7158 3.63087L12.258 2.44923C12.122 2.09718 11.8829 1.79437 11.572 1.5804C11.2608 1.36628 10.8923 1.25112 10.5146 1.25L9.48771 1.25ZM10.5116 2.5H9.48879C9.36315 2.50053 9.24059 2.5389 9.13708 2.61013C9.03337 2.68151 8.95363 2.78254 8.9083 2.9L8.3705 4.28827C8.31845 4.42266 8.22154 4.53492 8.09621 4.60606L6.24621 5.65606C6.12411 5.72535 5.98224 5.75153 5.84346 5.73036L4.37442 5.50627C4.25298 5.49062 4.12958 5.51099 4.01957 5.5649C3.90871 5.61922 3.81643 5.70515 3.75436 5.81183L3.25154 6.69178C3.18747 6.80075 3.15792 6.92655 3.16684 7.05264C3.17574 7.17824 3.22235 7.2982 3.30057 7.39684L4.23671 8.55766C4.32633 8.66878 4.37521 8.80724 4.37521 8.95V11.05C4.37521 11.1899 4.32824 11.3258 4.24184 11.4359L3.32651 12.602C3.24773 12.7009 3.20077 12.8213 3.19184 12.9474C3.18292 13.0735 3.21243 13.1993 3.27649 13.3083L3.2804 13.3149L3.77864 14.1869L3.77933 14.1881C3.8414 14.2948 3.93369 14.3808 4.04457 14.4351C4.15457 14.489 4.27796 14.5094 4.39939 14.4937L5.86846 14.2696C6.00848 14.2483 6.15161 14.2751 6.27439 14.3458L8.09939 15.3958C8.22322 15.467 8.3189 15.5785 8.3705 15.7117L8.908 17.0992C8.95333 17.2167 9.03337 17.3185 9.13708 17.3899C9.24061 17.4611 9.36321 17.4995 9.48887 17.5H10.5365C10.6622 17.4995 10.7848 17.4611 10.8883 17.3899C10.992 17.3185 11.0718 17.2175 11.1171 17.1L11.6549 15.7117C11.7065 15.5785 11.8022 15.467 11.926 15.3958L13.751 14.3458C13.8738 14.2751 14.0169 14.2483 14.157 14.2696L15.626 14.4937C15.7475 14.5094 15.8708 14.489 15.9808 14.4351C16.0917 14.3808 16.184 14.2949 16.2461 14.1882L16.2468 14.1869L16.7489 13.3082C16.8129 13.1993 16.8425 13.0735 16.8336 12.9474C16.8247 12.8218 16.7781 12.7019 16.6999 12.6032L16.6989 12.602L15.7637 11.4423C15.6741 11.3312 15.6252 11.1928 15.6252 11.05V8.95C15.6252 8.81006 15.6722 8.67418 15.7586 8.5641L16.6711 7.4016L16.6739 7.398C16.7527 7.29915 16.7996 7.17873 16.8086 7.05264C16.8175 6.92655 16.788 6.80072 16.7239 6.69175L16.72 6.68511L16.2218 5.81307L16.2211 5.81187C16.159 5.70517 16.0667 5.61923 15.9558 5.5649C15.8458 5.51099 15.7224 5.49062 15.601 5.50627L14.132 5.73036C13.9919 5.75172 13.8488 5.72488 13.726 5.65424L11.901 4.60424C11.7772 4.533 11.6815 4.42148 11.6299 4.28827L11.0924 2.90077C11.0471 2.78331 10.967 2.68151 10.8633 2.61013C10.7598 2.5389 10.6373 2.50053 10.5116 2.5Z',
);
static final Path _path3 = _pathFromString(
'M10.0002 6.875C9.1714 6.875 8.37655 7.20424 7.7905 7.79029C7.20445 8.37635 6.87521 9.1712 6.87521 10C6.87521 10.6181 7.05848 11.2223 7.40186 11.7362C7.74524 12.2501 8.2333 12.6506 8.80432 12.8871C9.37534 13.1237 10.0037 13.1855 10.6099 13.065C11.2161 12.9444 11.7729 12.6467 12.2099 12.2097C12.647 11.7727 12.9446 11.2159 13.0652 10.6097C13.1857 10.0035 13.1239 9.37514 12.8873 8.80412C12.6508 8.2331 12.2503 7.74504 11.7364 7.40166C11.2225 7.05828 10.6183 6.875 10.0002 6.875ZM10.0002 8.125C9.50292 8.125 9.02601 8.32255 8.67438 8.67418C8.32275 9.02581 8.12521 9.50272 8.12521 10C8.12521 10.3708 8.23517 10.7334 8.4412 11.0417C8.64723 11.35 8.94006 11.5904 9.28267 11.7323C9.62529 11.8742 10.0023 11.9113 10.366 11.839C10.7297 11.7666 11.0638 11.5881 11.326 11.3258C11.5883 11.0636 11.7668 10.7295 11.8392 10.3658C11.9115 10.0021 11.8744 9.62508 11.7325 9.28247C11.5906 8.93986 11.3502 8.64703 11.0419 8.441C10.7336 8.23497 10.371 8.125 10.0002 8.125Z');
'M10.0002 6.875C9.1714 6.875 8.37655 7.20424 7.7905 7.79029C7.20445 8.37635 6.87521 9.1712 6.87521 10C6.87521 10.6181 7.05848 11.2223 7.40186 11.7362C7.74524 12.2501 8.2333 12.6506 8.80432 12.8871C9.37534 13.1237 10.0037 13.1855 10.6099 13.065C11.2161 12.9444 11.7729 12.6467 12.2099 12.2097C12.647 11.7727 12.9446 11.2159 13.0652 10.6097C13.1857 10.0035 13.1239 9.37514 12.8873 8.80412C12.6508 8.2331 12.2503 7.74504 11.7364 7.40166C11.2225 7.05828 10.6183 6.875 10.0002 6.875ZM10.0002 8.125C9.50292 8.125 9.02601 8.32255 8.67438 8.67418C8.32275 9.02581 8.12521 9.50272 8.12521 10C8.12521 10.3708 8.23517 10.7334 8.4412 11.0417C8.64723 11.35 8.94006 11.5904 9.28267 11.7323C9.62529 11.8742 10.0023 11.9113 10.366 11.839C10.7297 11.7666 11.0638 11.5881 11.326 11.3258C11.5883 11.0636 11.7668 10.7295 11.8392 10.3658C11.9115 10.0021 11.8744 9.62508 11.7325 9.28247C11.5906 8.93986 11.3502 8.64703 11.0419 8.441C10.7336 8.23497 10.371 8.125 10.0002 8.125Z',
);
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
@ -236,8 +215,7 @@ class _SettingsIconPainter extends CustomPainter {
class _CameraIconPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final Matrix4 scale =
Matrix4.diagonal3Values(size.width / 20, size.height / 20, 1.0);
final Matrix4 scale = Matrix4.diagonal3Values(size.width / 20, size.height / 20, 1.0);
Path path;
path = _path1.transform(scale.storage)..fillType = PathFillType.evenOdd;
@ -248,9 +226,11 @@ class _CameraIconPainter extends CustomPainter {
}
static final Path _path1 = _pathFromString(
'M3.26366 17H16.7363C17.4857 17 18.0503 16.8123 18.4302 16.4369C18.8101 16.0615 19 15.5035 19 14.7631V7.01229C19 6.27188 18.8101 5.71397 18.4302 5.33855C18.0503 4.96313 17.4857 4.77542 16.7363 4.77542H14.6132C14.4154 4.77542 14.2567 4.76238 14.137 4.73631C14.0173 4.70503 13.9107 4.65549 13.817 4.58771C13.7233 4.51471 13.6219 4.41825 13.5126 4.29832L12.9115 3.61788C12.7242 3.41453 12.5212 3.26071 12.3027 3.15642C12.0893 3.05214 11.7953 3 11.4206 3H8.50911C8.13443 3 7.83781 3.05214 7.61925 3.15642C7.4059 3.26071 7.20555 3.41453 7.01821 3.61788L6.41717 4.29832C6.24545 4.48082 6.09193 4.60596 5.95663 4.67374C5.82134 4.74153 5.61058 4.77542 5.32437 4.77542H3.26366C2.50911 4.77542 1.94189 4.96313 1.56201 5.33855C1.18734 5.71397 1 6.27188 1 7.01229V14.7631C1 15.5035 1.18734 16.0615 1.56201 16.4369C1.94189 16.8123 2.50911 17 3.26366 17ZM3.27927 15.9207C2.89419 15.9207 2.59757 15.819 2.38942 15.6156C2.18647 15.4123 2.085 15.1099 2.085 14.7084V7.07486C2.085 6.67337 2.18647 6.37095 2.38942 6.1676C2.59757 5.95903 2.89419 5.85475 3.27927 5.85475H5.57415C5.9072 5.85475 6.1752 5.81825 6.37814 5.74525C6.58109 5.67225 6.77624 5.53147 6.96357 5.32291L7.55681 4.6581C7.76496 4.42346 7.9497 4.26965 8.11101 4.19665C8.27233 4.12365 8.50911 4.08715 8.82134 4.08715H11.1084C11.4258 4.08715 11.6626 4.12365 11.8187 4.19665C11.9801 4.26965 12.1648 4.42346 12.3729 4.6581L12.9662 5.32291C13.1535 5.53147 13.3487 5.67225 13.5516 5.74525C13.7546 5.81825 14.0225 5.85475 14.3556 5.85475H16.7207C17.1058 5.85475 17.4024 5.95903 17.6106 6.1676C17.8187 6.37095 17.9228 6.67337 17.9228 7.07486V14.7084C17.9228 15.1099 17.8187 15.4123 17.6106 15.6156C17.4024 15.819 17.1058 15.9207 16.7207 15.9207H3.27927ZM10 14.8101C10.7493 14.8101 11.4284 14.6302 12.0373 14.2704C12.6461 13.9054 13.1301 13.4179 13.4892 12.8078C13.8534 12.1926 14.0356 11.5095 14.0356 10.7587C14.0356 10.0078 13.8534 9.32477 13.4892 8.7095C13.1301 8.09423 12.6461 7.6067 12.0373 7.24693C11.4284 6.88194 10.7493 6.69944 10 6.69944C9.25585 6.69944 8.57676 6.88194 7.96271 7.24693C7.35386 7.6067 6.8673 8.09423 6.50304 8.7095C6.14397 9.32477 5.96444 10.0078 5.96444 10.7587C5.96444 11.5095 6.14397 12.1926 6.50304 12.8078C6.8673 13.4179 7.35386 13.9054 7.96271 14.2704C8.57676 14.6302 9.25585 14.8101 10 14.8101ZM10 13.7855C9.4484 13.7855 8.94363 13.6499 8.48569 13.3788C8.03296 13.1076 7.66869 12.7426 7.39289 12.2838C7.12229 11.825 6.98699 11.3166 6.98699 10.7587C6.98699 10.1955 7.12229 9.68454 7.39289 9.2257C7.66349 8.76685 8.02775 8.40447 8.48569 8.13855C8.94363 7.86741 9.4484 7.73184 10 7.73184C10.5568 7.73184 11.0616 7.86741 11.5143 8.13855C11.9722 8.40447 12.3365 8.76685 12.6071 9.2257C12.8829 9.68454 13.0208 10.1955 13.0208 10.7587C13.0208 11.3166 12.8829 11.825 12.6071 12.2838C12.3365 12.7426 11.9722 13.1076 11.5143 13.3788C11.0616 13.6499 10.5568 13.7855 10 13.7855ZM14.3556 8.04469C14.3556 8.30019 14.4467 8.51657 14.6288 8.69385C14.8109 8.86592 15.0269 8.95196 15.2767 8.95196C15.516 8.94674 15.7242 8.8581 15.9011 8.68603C16.0833 8.50875 16.1743 8.29497 16.1743 8.04469C16.1743 7.79963 16.0833 7.58845 15.9011 7.41117C15.7242 7.22868 15.516 7.13743 15.2767 7.13743C15.0269 7.13743 14.8109 7.22868 14.6288 7.41117C14.4467 7.58845 14.3556 7.79963 14.3556 8.04469Z');
'M3.26366 17H16.7363C17.4857 17 18.0503 16.8123 18.4302 16.4369C18.8101 16.0615 19 15.5035 19 14.7631V7.01229C19 6.27188 18.8101 5.71397 18.4302 5.33855C18.0503 4.96313 17.4857 4.77542 16.7363 4.77542H14.6132C14.4154 4.77542 14.2567 4.76238 14.137 4.73631C14.0173 4.70503 13.9107 4.65549 13.817 4.58771C13.7233 4.51471 13.6219 4.41825 13.5126 4.29832L12.9115 3.61788C12.7242 3.41453 12.5212 3.26071 12.3027 3.15642C12.0893 3.05214 11.7953 3 11.4206 3H8.50911C8.13443 3 7.83781 3.05214 7.61925 3.15642C7.4059 3.26071 7.20555 3.41453 7.01821 3.61788L6.41717 4.29832C6.24545 4.48082 6.09193 4.60596 5.95663 4.67374C5.82134 4.74153 5.61058 4.77542 5.32437 4.77542H3.26366C2.50911 4.77542 1.94189 4.96313 1.56201 5.33855C1.18734 5.71397 1 6.27188 1 7.01229V14.7631C1 15.5035 1.18734 16.0615 1.56201 16.4369C1.94189 16.8123 2.50911 17 3.26366 17ZM3.27927 15.9207C2.89419 15.9207 2.59757 15.819 2.38942 15.6156C2.18647 15.4123 2.085 15.1099 2.085 14.7084V7.07486C2.085 6.67337 2.18647 6.37095 2.38942 6.1676C2.59757 5.95903 2.89419 5.85475 3.27927 5.85475H5.57415C5.9072 5.85475 6.1752 5.81825 6.37814 5.74525C6.58109 5.67225 6.77624 5.53147 6.96357 5.32291L7.55681 4.6581C7.76496 4.42346 7.9497 4.26965 8.11101 4.19665C8.27233 4.12365 8.50911 4.08715 8.82134 4.08715H11.1084C11.4258 4.08715 11.6626 4.12365 11.8187 4.19665C11.9801 4.26965 12.1648 4.42346 12.3729 4.6581L12.9662 5.32291C13.1535 5.53147 13.3487 5.67225 13.5516 5.74525C13.7546 5.81825 14.0225 5.85475 14.3556 5.85475H16.7207C17.1058 5.85475 17.4024 5.95903 17.6106 6.1676C17.8187 6.37095 17.9228 6.67337 17.9228 7.07486V14.7084C17.9228 15.1099 17.8187 15.4123 17.6106 15.6156C17.4024 15.819 17.1058 15.9207 16.7207 15.9207H3.27927ZM10 14.8101C10.7493 14.8101 11.4284 14.6302 12.0373 14.2704C12.6461 13.9054 13.1301 13.4179 13.4892 12.8078C13.8534 12.1926 14.0356 11.5095 14.0356 10.7587C14.0356 10.0078 13.8534 9.32477 13.4892 8.7095C13.1301 8.09423 12.6461 7.6067 12.0373 7.24693C11.4284 6.88194 10.7493 6.69944 10 6.69944C9.25585 6.69944 8.57676 6.88194 7.96271 7.24693C7.35386 7.6067 6.8673 8.09423 6.50304 8.7095C6.14397 9.32477 5.96444 10.0078 5.96444 10.7587C5.96444 11.5095 6.14397 12.1926 6.50304 12.8078C6.8673 13.4179 7.35386 13.9054 7.96271 14.2704C8.57676 14.6302 9.25585 14.8101 10 14.8101ZM10 13.7855C9.4484 13.7855 8.94363 13.6499 8.48569 13.3788C8.03296 13.1076 7.66869 12.7426 7.39289 12.2838C7.12229 11.825 6.98699 11.3166 6.98699 10.7587C6.98699 10.1955 7.12229 9.68454 7.39289 9.2257C7.66349 8.76685 8.02775 8.40447 8.48569 8.13855C8.94363 7.86741 9.4484 7.73184 10 7.73184C10.5568 7.73184 11.0616 7.86741 11.5143 8.13855C11.9722 8.40447 12.3365 8.76685 12.6071 9.2257C12.8829 9.68454 13.0208 10.1955 13.0208 10.7587C13.0208 11.3166 12.8829 11.825 12.6071 12.2838C12.3365 12.7426 11.9722 13.1076 11.5143 13.3788C11.0616 13.6499 10.5568 13.7855 10 13.7855ZM14.3556 8.04469C14.3556 8.30019 14.4467 8.51657 14.6288 8.69385C14.8109 8.86592 15.0269 8.95196 15.2767 8.95196C15.516 8.94674 15.7242 8.8581 15.9011 8.68603C16.0833 8.50875 16.1743 8.29497 16.1743 8.04469C16.1743 7.79963 16.0833 7.58845 15.9011 7.41117C15.7242 7.22868 15.516 7.13743 15.2767 7.13743C15.0269 7.13743 14.8109 7.22868 14.6288 7.41117C14.4467 7.58845 14.3556 7.79963 14.3556 8.04469Z',
);
static final Path _path2 = _pathFromString(
'M2.30754 15.6907C2.51782 15.8969 2.81748 16 3.20651 16H16.7856C17.1746 16 17.4743 15.8969 17.6846 15.6907C17.8949 15.4845 18 15.1778 18 14.7707V7.02974C18 6.6226 17.8949 6.31593 17.6846 6.10972C17.4743 5.89822 17.1746 5.79247 16.7856 5.79247H14.3963C14.0598 5.79247 13.7891 5.75545 13.584 5.68143C13.379 5.6074 13.1819 5.46464 12.9926 5.25314L12.3933 4.57898C12.183 4.34104 11.9964 4.18506 11.8334 4.11104C11.6757 4.03701 11.4365 4 11.1158 4H8.80532C8.4899 4 8.2507 4.03701 8.08773 4.11104C7.92476 4.18506 7.73813 4.34104 7.52785 4.57898L6.92854 5.25314C6.73928 5.46464 6.54214 5.6074 6.33711 5.68143C6.13208 5.75545 5.86134 5.79247 5.52489 5.79247H3.20651C2.81748 5.79247 2.51782 5.89822 2.30754 6.10972C2.10251 6.31593 2 6.6226 2 7.02974V14.7707C2 15.1778 2.10251 15.4845 2.30754 15.6907ZM9.99547 14C9.99547 14 8.76994 13.8432 8.23868 13.5297C7.71345 13.2162 7.29086 12.7941 6.97089 12.2636C6.65696 11.733 6.5 11.1451 6.5 10.5C6.5 9.84884 6.65696 9.25797 6.97089 8.72739C7.28482 8.19681 7.70742 7.77778 8.23868 7.47028C8.76994 7.15676 9.35554 7 9.99547 7C10.6414 7 11.7523 7.47028 11.7523 7.47028C11.7523 7.47028 12.7061 8.19681 13.0201 8.72739C13.34 9.25797 13.5 9.84884 13.5 10.5C13.5 11.1451 13.34 11.733 13.0201 12.2636C12.7061 12.7941 12.2835 13.2162 11.7523 13.5297C11.227 13.8432 9.99547 14 9.99547 14Z');
'M2.30754 15.6907C2.51782 15.8969 2.81748 16 3.20651 16H16.7856C17.1746 16 17.4743 15.8969 17.6846 15.6907C17.8949 15.4845 18 15.1778 18 14.7707V7.02974C18 6.6226 17.8949 6.31593 17.6846 6.10972C17.4743 5.89822 17.1746 5.79247 16.7856 5.79247H14.3963C14.0598 5.79247 13.7891 5.75545 13.584 5.68143C13.379 5.6074 13.1819 5.46464 12.9926 5.25314L12.3933 4.57898C12.183 4.34104 11.9964 4.18506 11.8334 4.11104C11.6757 4.03701 11.4365 4 11.1158 4H8.80532C8.4899 4 8.2507 4.03701 8.08773 4.11104C7.92476 4.18506 7.73813 4.34104 7.52785 4.57898L6.92854 5.25314C6.73928 5.46464 6.54214 5.6074 6.33711 5.68143C6.13208 5.75545 5.86134 5.79247 5.52489 5.79247H3.20651C2.81748 5.79247 2.51782 5.89822 2.30754 6.10972C2.10251 6.31593 2 6.6226 2 7.02974V14.7707C2 15.1778 2.10251 15.4845 2.30754 15.6907ZM9.99547 14C9.99547 14 8.76994 13.8432 8.23868 13.5297C7.71345 13.2162 7.29086 12.7941 6.97089 12.2636C6.65696 11.733 6.5 11.1451 6.5 10.5C6.5 9.84884 6.65696 9.25797 6.97089 8.72739C7.28482 8.19681 7.70742 7.77778 8.23868 7.47028C8.76994 7.15676 9.35554 7 9.99547 7C10.6414 7 11.7523 7.47028 11.7523 7.47028C11.7523 7.47028 12.7061 8.19681 13.0201 8.72739C13.34 9.25797 13.5 9.84884 13.5 10.5C13.5 11.1451 13.34 11.733 13.0201 12.2636C12.7061 12.7941 12.2835 13.2162 11.7523 13.5297C11.227 13.8432 9.99547 14 9.99547 14Z',
);
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
@ -261,8 +241,7 @@ class _CameraIconPainter extends CustomPainter {
class _CalendarIconPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final Matrix4 scale =
Matrix4.diagonal3Values(size.width / 20, size.height / 20, 1.0);
final Matrix4 scale = Matrix4.diagonal3Values(size.width / 20, size.height / 20, 1.0);
Path path;
path = _path1.transform(scale.storage)..fillType = PathFillType.evenOdd;
@ -273,9 +252,11 @@ class _CalendarIconPainter extends CustomPainter {
}
static final Path _path1 = _pathFromString(
'M16.7812 6.85938H3.28125V4.5L5 3H15L16.7812 4.5V6.85938Z');
'M16.7812 6.85938H3.28125V4.5L5 3H15L16.7812 4.5V6.85938Z',
);
static final Path _path2 = _pathFromString(
'M6.5606 11.2462C7.07732 11.2462 7.4962 10.8273 7.4962 10.3106C7.4962 9.79388 7.07732 9.375 6.5606 9.375C6.04388 9.375 5.625 9.79388 5.625 10.3106C5.625 10.8273 6.04388 11.2462 6.5606 11.2462ZM7.4962 13.4356C7.4962 13.9523 7.07732 14.3712 6.5606 14.3712C6.04388 14.3712 5.625 13.9523 5.625 13.4356C5.625 12.9189 6.04388 12.5 6.5606 12.5C7.07732 12.5 7.4962 12.9189 7.4962 13.4356ZM10.0005 11.2462C10.5173 11.2462 10.9361 10.8273 10.9361 10.3106C10.9361 9.79388 10.5173 9.375 10.0005 9.375C9.48382 9.375 9.06494 9.79388 9.06494 10.3106C9.06494 10.8273 9.48382 11.2462 10.0005 11.2462ZM10.9361 13.4356C10.9361 13.9523 10.5173 14.3712 10.0005 14.3712C9.48382 14.3712 9.06494 13.9523 9.06494 13.4356C9.06494 12.9189 9.48382 12.5 10.0005 12.5C10.5173 12.5 10.9361 12.9189 10.9361 13.4356ZM13.4356 11.2462C13.9523 11.2462 14.3712 10.8273 14.3712 10.3106C14.3712 9.79388 13.9523 9.375 13.4356 9.375C12.9189 9.375 12.5 9.79388 12.5 10.3106C12.5 10.8273 12.9189 11.2462 13.4356 11.2462ZM17.5 5.625C17.5 3.89911 16.1009 2.5 14.375 2.5H5.625C3.89911 2.5 2.5 3.89911 2.5 5.625V14.375C2.5 16.1009 3.89911 17.5 5.625 17.5H14.375C16.1009 17.5 17.5 16.1009 17.5 14.375V5.625ZM3.75 7.5H16.25V14.375C16.25 15.4105 15.4105 16.25 14.375 16.25H5.625C4.58947 16.25 3.75 15.4105 3.75 14.375V7.5ZM5.625 3.75H14.375C15.4105 3.75 16.25 4.58947 16.25 5.625V6.25H3.75V5.625C3.75 4.58947 4.58947 3.75 5.625 3.75Z');
'M6.5606 11.2462C7.07732 11.2462 7.4962 10.8273 7.4962 10.3106C7.4962 9.79388 7.07732 9.375 6.5606 9.375C6.04388 9.375 5.625 9.79388 5.625 10.3106C5.625 10.8273 6.04388 11.2462 6.5606 11.2462ZM7.4962 13.4356C7.4962 13.9523 7.07732 14.3712 6.5606 14.3712C6.04388 14.3712 5.625 13.9523 5.625 13.4356C5.625 12.9189 6.04388 12.5 6.5606 12.5C7.07732 12.5 7.4962 12.9189 7.4962 13.4356ZM10.0005 11.2462C10.5173 11.2462 10.9361 10.8273 10.9361 10.3106C10.9361 9.79388 10.5173 9.375 10.0005 9.375C9.48382 9.375 9.06494 9.79388 9.06494 10.3106C9.06494 10.8273 9.48382 11.2462 10.0005 11.2462ZM10.9361 13.4356C10.9361 13.9523 10.5173 14.3712 10.0005 14.3712C9.48382 14.3712 9.06494 13.9523 9.06494 13.4356C9.06494 12.9189 9.48382 12.5 10.0005 12.5C10.5173 12.5 10.9361 12.9189 10.9361 13.4356ZM13.4356 11.2462C13.9523 11.2462 14.3712 10.8273 14.3712 10.3106C14.3712 9.79388 13.9523 9.375 13.4356 9.375C12.9189 9.375 12.5 9.79388 12.5 10.3106C12.5 10.8273 12.9189 11.2462 13.4356 11.2462ZM17.5 5.625C17.5 3.89911 16.1009 2.5 14.375 2.5H5.625C3.89911 2.5 2.5 3.89911 2.5 5.625V14.375C2.5 16.1009 3.89911 17.5 5.625 17.5H14.375C16.1009 17.5 17.5 16.1009 17.5 14.375V5.625ZM3.75 7.5H16.25V14.375C16.25 15.4105 15.4105 16.25 14.375 16.25H5.625C4.58947 16.25 3.75 15.4105 3.75 14.375V7.5ZM5.625 3.75H14.375C15.4105 3.75 16.25 4.58947 16.25 5.625V6.25H3.75V5.625C3.75 4.58947 4.58947 3.75 5.625 3.75Z',
);
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
@ -286,8 +267,7 @@ class _CalendarIconPainter extends CustomPainter {
class _ConversationIconPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final Matrix4 scale =
Matrix4.diagonal3Values(size.width / 20, size.height / 20, 1.0);
final Matrix4 scale = Matrix4.diagonal3Values(size.width / 20, size.height / 20, 1.0);
Path path;
path = _path1.transform(scale.storage)..fillType = PathFillType.evenOdd;
@ -298,9 +278,11 @@ class _ConversationIconPainter extends CustomPainter {
}
static final Path _path1 = _pathFromString(
'M14.4141 8.33333C14.4141 11.555 11.8024 14.1667 8.58073 14.1667C7.64487 14.1667 6.76047 13.9463 5.97663 13.5546L2.65625 14.4661L3.70864 11.5424C3.10106 10.6218 2.7474 9.51887 2.7474 8.33333C2.7474 5.11167 5.35907 2.5 8.58073 2.5C11.8024 2.5 14.4141 5.11167 14.4141 8.33333Z');
'M14.4141 8.33333C14.4141 11.555 11.8024 14.1667 8.58073 14.1667C7.64487 14.1667 6.76047 13.9463 5.97663 13.5546L2.65625 14.4661L3.70864 11.5424C3.10106 10.6218 2.7474 9.51887 2.7474 8.33333C2.7474 5.11167 5.35907 2.5 8.58073 2.5C11.8024 2.5 14.4141 5.11167 14.4141 8.33333Z',
);
static final Path _path2 = _pathFromString(
'M8.5382 1.81665C4.84709 1.81665 1.85486 4.80888 1.85486 8.49998C1.85486 9.65241 2.1471 10.7384 2.66182 11.686L1.89645 13.6887C1.5494 14.5968 2.38481 15.5128 3.32097 15.2506L5.74289 14.5723C6.59409 14.9647 7.54146 15.1833 8.5382 15.1833C12.2293 15.1833 15.2215 12.1911 15.2215 8.49998C15.2215 4.80888 12.2293 1.81665 8.5382 1.81665ZM3.22153 8.49998C3.22153 5.56367 5.60188 3.18332 8.5382 3.18332C11.4745 3.18332 13.8549 5.56367 13.8549 8.49998C13.8549 11.4363 11.4745 13.8167 8.5382 13.8167C7.66578 13.8167 6.84431 13.607 6.11952 13.2361L5.88143 13.1142L3.30309 13.8364L4.17436 11.5565L3.99903 11.2698C3.5059 10.4636 3.22153 9.51607 3.22153 8.49998ZM16.5636 7.07206L16.1464 6.61586L16.2475 7.22577C16.317 7.64558 16.3533 8.07677 16.3533 8.51656C16.3533 8.69251 16.3475 8.86707 16.3361 9.04007L16.3328 9.08869L16.3542 9.13249C16.6951 9.83163 16.8175 10.5975 16.8175 11.5C16.8175 12.5161 16.5332 13.4636 16.04 14.2698L15.8647 14.5565L16.736 16.8363L14.1576 16.1142L13.9195 16.2361C13.1948 16.607 12.3733 16.8166 11.5009 16.8166C10.5879 16.8166 9.87033 16.6947 9.19041 16.3496L9.14498 16.3266L9.09417 16.3303C8.90419 16.3441 8.71231 16.3511 8.51875 16.3511C8.10958 16.3511 7.70785 16.3197 7.31582 16.2593L6.72389 16.1681L7.16334 16.575C8.31731 17.6436 9.75888 18.1833 11.5009 18.1833C12.4976 18.1833 13.445 17.9647 14.2962 17.5723L16.7181 18.2506C17.6543 18.5128 18.4897 17.5968 18.1426 16.6887L17.3772 14.6859C17.892 13.7384 18.1842 12.6524 18.1842 11.5C18.1842 9.75761 17.6387 8.24759 16.5636 7.07206Z');
'M8.5382 1.81665C4.84709 1.81665 1.85486 4.80888 1.85486 8.49998C1.85486 9.65241 2.1471 10.7384 2.66182 11.686L1.89645 13.6887C1.5494 14.5968 2.38481 15.5128 3.32097 15.2506L5.74289 14.5723C6.59409 14.9647 7.54146 15.1833 8.5382 15.1833C12.2293 15.1833 15.2215 12.1911 15.2215 8.49998C15.2215 4.80888 12.2293 1.81665 8.5382 1.81665ZM3.22153 8.49998C3.22153 5.56367 5.60188 3.18332 8.5382 3.18332C11.4745 3.18332 13.8549 5.56367 13.8549 8.49998C13.8549 11.4363 11.4745 13.8167 8.5382 13.8167C7.66578 13.8167 6.84431 13.607 6.11952 13.2361L5.88143 13.1142L3.30309 13.8364L4.17436 11.5565L3.99903 11.2698C3.5059 10.4636 3.22153 9.51607 3.22153 8.49998ZM16.5636 7.07206L16.1464 6.61586L16.2475 7.22577C16.317 7.64558 16.3533 8.07677 16.3533 8.51656C16.3533 8.69251 16.3475 8.86707 16.3361 9.04007L16.3328 9.08869L16.3542 9.13249C16.6951 9.83163 16.8175 10.5975 16.8175 11.5C16.8175 12.5161 16.5332 13.4636 16.04 14.2698L15.8647 14.5565L16.736 16.8363L14.1576 16.1142L13.9195 16.2361C13.1948 16.607 12.3733 16.8166 11.5009 16.8166C10.5879 16.8166 9.87033 16.6947 9.19041 16.3496L9.14498 16.3266L9.09417 16.3303C8.90419 16.3441 8.71231 16.3511 8.51875 16.3511C8.10958 16.3511 7.70785 16.3197 7.31582 16.2593L6.72389 16.1681L7.16334 16.575C8.31731 17.6436 9.75888 18.1833 11.5009 18.1833C12.4976 18.1833 13.445 17.9647 14.2962 17.5723L16.7181 18.2506C17.6543 18.5128 18.4897 17.5968 18.1426 16.6887L17.3772 14.6859C17.892 13.7384 18.1842 12.6524 18.1842 11.5C18.1842 9.75761 17.6387 8.24759 16.5636 7.07206Z',
);
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
@ -312,24 +294,23 @@ class _GeometryIconPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size canvasSize) {
const Size size = Size(20, 20);
canvas.scale(
canvasSize.width / size.width, canvasSize.height / size.height);
canvas.scale(canvasSize.width / size.width, canvasSize.height / size.height);
final Paint paint = Paint()..color = const Color(0xFFF84F39);
final Rect frame = Offset.zero & size;
canvas.drawDRRect(
RRect.fromRectAndRadius(frame, const Radius.elliptical(5, 4)),
RRect.fromRectAndRadius(
frame.deflate(1), const Radius.elliptical(4, 3)),
paint);
RRect.fromRectAndRadius(frame, const Radius.elliptical(5, 4)),
RRect.fromRectAndRadius(frame.deflate(1), const Radius.elliptical(4, 3)),
paint,
);
canvas.drawRRect(
RRect.fromRectAndRadius(
const Rect.fromLTWH(3, 3, 6, 6), const Radius.elliptical(2, 1)),
paint);
RRect.fromRectAndRadius(const Rect.fromLTWH(3, 3, 6, 6), const Radius.elliptical(2, 1)),
paint,
);
canvas.drawRRect(
RRect.fromRectAndRadius(
const Rect.fromLTWH(11, 11, 6, 6), const Radius.elliptical(2, 1)),
paint);
RRect.fromRectAndRadius(const Rect.fromLTWH(11, 11, 6, 6), const Radius.elliptical(2, 1)),
paint,
);
canvas.drawCircle(const Offset(14, 6), 3, paint);
canvas.drawCircle(const Offset(6, 14), 3, paint);
}

View File

@ -19,25 +19,24 @@ class PictureCachePage extends StatelessWidget {
// pinned: true,
// expandedHeight: 50.0,
// forceElevated: innerBoxIsScrolled,
bottom: TabBar(
tabs: kTabNames.map((String name) => Tab(text: name)).toList(),
),
bottom: TabBar(tabs: kTabNames.map((String name) => Tab(text: name)).toList()),
),
body: TabBarView(
key: const Key('tabbar_view'), // this key is used by the driver test
children: kTabNames.map((String name) {
return SafeArea(
top: false,
bottom: false,
child: Builder(
builder: (BuildContext context) {
return ListView.builder(
itemBuilder: (BuildContext context, int index) => ListItem(index: index),
);
},
),
);
}).toList(),
children:
kTabNames.map((String name) {
return SafeArea(
top: false,
bottom: false,
child: Builder(
builder: (BuildContext context) {
return ListView.builder(
itemBuilder: (BuildContext context, int index) => ListItem(index: index),
);
},
),
);
}).toList(),
),
),
);
@ -56,35 +55,21 @@ class ListItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
final List<Widget> contents = <Widget>[
const SizedBox(
height: 15,
),
const SizedBox(height: 15),
_buildUserInfo(),
const SizedBox(
height: 10,
),
const SizedBox(height: 10),
];
if (index % 3 != 0) {
contents.add(_buildImageContent());
} else {
contents.addAll(<Widget>[
Padding(
padding: const EdgeInsets.only(left: 40, right: 15),
child: _buildContentText(),
),
const SizedBox(
height: 10,
),
Padding(
padding: const EdgeInsets.only(left: 40, right: 15),
child: _buildBottomRow(),
),
Padding(padding: const EdgeInsets.only(left: 40, right: 15), child: _buildContentText()),
const SizedBox(height: 10),
Padding(padding: const EdgeInsets.only(left: 40, right: 15), child: _buildBottomRow()),
]);
}
contents.addAll(<Widget>[
const SizedBox(
height: 13,
),
const SizedBox(height: 13),
buildDivider(0.5, const EdgeInsets.only(left: 40, right: 15)),
]);
return MaterialButton(
@ -112,21 +97,14 @@ class ListItem extends StatelessWidget {
Widget _buildImageContent() {
return Row(
children: <Widget>[
const SizedBox(
width: 40,
),
const SizedBox(width: 40),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 30),
child: _buildContentText(),
),
const SizedBox(
height: 10,
),
Padding(padding: const EdgeInsets.only(right: 30), child: _buildContentText()),
const SizedBox(height: 10),
_buildBottomRow(),
],
),
@ -138,9 +116,7 @@ class ListItem extends StatelessWidget {
width: 110,
height: 70,
),
const SizedBox(
width: 15,
),
const SizedBox(width: 15),
],
);
}
@ -148,9 +124,7 @@ class ListItem extends StatelessWidget {
Widget _buildContentText() {
return const Text(
kMockChineseTitle,
style: TextStyle(
fontSize: 16,
),
style: TextStyle(fontSize: 16),
maxLines: 2,
overflow: TextOverflow.ellipsis,
);
@ -160,9 +134,7 @@ class ListItem extends StatelessWidget {
return Row(
children: <Widget>[
Container(
padding: const EdgeInsets.symmetric(
horizontal: 7,
),
padding: const EdgeInsets.symmetric(horizontal: 7),
height: 16,
alignment: Alignment.center,
decoration: BoxDecoration(
@ -171,48 +143,27 @@ class ListItem extends StatelessWidget {
),
child: Row(
children: <Widget>[
const SizedBox(
width: 3,
),
const SizedBox(width: 3),
Text(
'hot:${_convertCountToStr(kMockCount)}',
style: const TextStyle(
color: Color(0xFFE5645F),
fontSize: 11,
),
style: const TextStyle(color: Color(0xFFE5645F), fontSize: 11),
),
],
),
),
const SizedBox(
width: 9,
),
const Text(
'ans:$kMockCount',
style: TextStyle(
color: Color(0xFF999999),
fontSize: 11,
),
),
const SizedBox(
width: 9,
),
const Text(
'like:$kMockCount',
style: TextStyle(
color: Color(0xFF999999),
fontSize: 11,
),
),
const SizedBox(width: 9),
const Text('ans:$kMockCount', style: TextStyle(color: Color(0xFF999999), fontSize: 11)),
const SizedBox(width: 9),
const Text('like:$kMockCount', style: TextStyle(color: Color(0xFF999999), fontSize: 11)),
],
);
}
String _convertCountToStr(int count) {
return switch (count) {
< 10000 => count.toString(),
< 10000 => count.toString(),
< 100000 => '${(count / 10000).toStringAsPrecision(2)}w',
_ => '${(count / 10000).floor()}w',
_ => '${(count / 10000).floor()}w',
};
}
@ -221,42 +172,26 @@ class ListItem extends StatelessWidget {
onTap: () {},
child: Row(
children: <Widget>[
Container(
width: 40, alignment: Alignment.center, child: _buildRankText()),
const CircleAvatar(
radius: 11.5,
),
const SizedBox(
width: 6,
),
Container(width: 40, alignment: Alignment.center, child: _buildRankText()),
const CircleAvatar(radius: 11.5),
const SizedBox(width: 6),
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 250),
child: const Text(
kMockName,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
),
style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
),
),
const SizedBox(
width: 4,
),
const SizedBox(
width: 15,
),
const SizedBox(width: 4),
const SizedBox(width: 15),
],
),
);
}
Widget buildDivider(double height, EdgeInsets padding) {
return Container(
padding: padding,
height: height,
color: const Color(0xFFF5F5F5),
);
return Container(padding: padding, height: height, color: const Color(0xFFF5F5F5));
}
}

View File

@ -19,15 +19,14 @@ class PictureCacheComplexityScoringPage extends StatelessWidget {
// pinned: true,
// expandedHeight: 50.0,
// forceElevated: innerBoxIsScrolled,
bottom: TabBar(
tabs: kTabNames.map((String name) => Tab(text: name)).toList(),
),
bottom: TabBar(tabs: kTabNames.map((String name) => Tab(text: name)).toList()),
),
body: TabBarView(
key: const Key('tabbar_view_complexity'), // this key is used by the driver test
children: kTabNames.map((String name) {
return _buildComplexityScoringWidgets(name);
}).toList(),
children:
kTabNames.map((String name) {
return _buildComplexityScoringWidgets(name);
}).toList(),
),
),
);
@ -38,10 +37,12 @@ class PictureCacheComplexityScoringPage extends StatelessWidget {
//
// Eventually we can extend this to add new test cases based on the tab name.
Widget _buildComplexityScoringWidgets(String name) {
return Column(children: <Widget>[
Slider(value: 50, label: 'Slider 1', onChanged: (double _) {}, max: 100, divisions: 10,),
Slider(value: 50, label: 'Slider 2', onChanged: (double _) {}, max: 100, divisions: 10,),
Slider(value: 50, label: 'Slider 3', onChanged: (double _) {}, max: 100, divisions: 10,),
]);
return Column(
children: <Widget>[
Slider(value: 50, label: 'Slider 1', onChanged: (double _) {}, max: 100, divisions: 10),
Slider(value: 50, label: 'Slider 2', onChanged: (double _) {}, max: 100, divisions: 10),
Slider(value: 50, label: 'Slider 3', onChanged: (double _) {}, max: 100, divisions: 10),
],
);
}
}

View File

@ -13,7 +13,8 @@ class PostBackdropFilterPage extends StatefulWidget {
State<PostBackdropFilterPage> createState() => _PostBackdropFilterPageState();
}
class _PostBackdropFilterPageState extends State<PostBackdropFilterPage> with TickerProviderStateMixin {
class _PostBackdropFilterPageState extends State<PostBackdropFilterPage>
with TickerProviderStateMixin {
bool _includeBackdropFilter = false;
late AnimationController animation;
@ -60,17 +61,20 @@ class _PostBackdropFilterPageState extends State<PostBackdropFilterPage> with Ti
children: <Widget>[
Expanded(
child: RepaintBoundary(
child: Center(
child: AnimatedBuilder(
animation: animation,
builder: (BuildContext c, Widget? w) {
final int val = (animation.value * 255).round();
return Container(
width: 50,
height: 50,
color: Color.fromARGB(255, val, val, val));
}),
)),
child: Center(
child: AnimatedBuilder(
animation: animation,
builder: (BuildContext c, Widget? w) {
final int val = (animation.value * 255).round();
return Container(
width: 50,
height: 50,
color: Color.fromARGB(255, val, val, val),
);
},
),
),
),
),
getConditionalBackdrop(),
RepaintBoundary(
@ -83,12 +87,18 @@ class _PostBackdropFilterPageState extends State<PostBackdropFilterPage> with Ti
Checkbox(
key: const Key('bdf-checkbox'), // this key is used by the driver test
value: _includeBackdropFilter,
onChanged: (bool? v) => setState(() { _includeBackdropFilter = v ?? false; }),
onChanged:
(bool? v) => setState(() {
_includeBackdropFilter = v ?? false;
}),
),
MaterialButton(
key: const Key('bdf-animate'), // this key is used by the driver test
child: const Text('Animate'),
onPressed: () => setState(() { animation.repeat(); }),
onPressed:
() => setState(() {
animation.repeat();
}),
),
],
),

View File

@ -13,8 +13,7 @@ class RasterCacheUseMemory extends StatefulWidget {
State<RasterCacheUseMemory> createState() => _RasterCacheUseMemoryState();
}
class _RasterCacheUseMemoryState extends State<RasterCacheUseMemory>
with TickerProviderStateMixin {
class _RasterCacheUseMemoryState extends State<RasterCacheUseMemory> with TickerProviderStateMixin {
final ScrollController _controller = ScrollController();
@override
@ -22,16 +21,13 @@ class _RasterCacheUseMemoryState extends State<RasterCacheUseMemory>
super.initState();
_controller.addListener(() {
if (_controller.offset < 5) {
_controller.animateTo(20,
duration: const Duration(milliseconds: 1000), curve: Curves.ease);
_controller.animateTo(20, duration: const Duration(milliseconds: 1000), curve: Curves.ease);
} else if (_controller.offset >= 19) {
_controller.animateTo(0,
duration: const Duration(milliseconds: 1000), curve: Curves.ease);
_controller.animateTo(0, duration: const Duration(milliseconds: 1000), curve: Curves.ease);
}
});
Timer(const Duration(milliseconds: 1000), () {
_controller.animateTo(150,
duration: const Duration(milliseconds: 1000), curve: Curves.ease);
_controller.animateTo(150, duration: const Duration(milliseconds: 1000), curve: Curves.ease);
});
}
@ -44,17 +40,8 @@ class _RasterCacheUseMemoryState extends State<RasterCacheUseMemory>
children: <Widget>[
RepaintBoundary(
child: ImageFiltered(
imageFilter: ImageFilter.blur(
sigmaX: 4,
sigmaY: 4,
),
child: RepaintBoundary(
child: Container(
width: 50,
height: 50,
color: Colors.red,
),
),
imageFilter: ImageFilter.blur(sigmaX: 4, sigmaY: 4),
child: RepaintBoundary(child: Container(width: 50, height: 50, color: Colors.red)),
),
),
ShaderMask(
@ -72,50 +59,32 @@ class _RasterCacheUseMemoryState extends State<RasterCacheUseMemory>
child: Column(
children: <Widget>[
ImageFiltered(
imageFilter: ImageFilter.blur(
sigmaX: 4,
sigmaY: 4,
),
imageFilter: ImageFilter.blur(sigmaX: 4, sigmaY: 4),
child: Row(
children: <Widget>[
ImageFiltered(
imageFilter: ImageFilter.blur(
sigmaX: 4,
sigmaY: 4,
),
imageFilter: ImageFilter.blur(sigmaX: 4, sigmaY: 4),
child: RepaintBoundary(
child: Container(
margin: const EdgeInsets.fromLTRB(10, 5, 10, 5),
decoration: BoxDecoration(
color: Colors.white70,
boxShadow: const <BoxShadow>[
BoxShadow(
blurRadius: 5.0,
),
],
boxShadow: const <BoxShadow>[BoxShadow(blurRadius: 5.0)],
borderRadius: BorderRadius.circular(5.0),
),
child: const FlutterLogo(
size: 50,
),
child: const FlutterLogo(size: 50),
),
),
)
),
],
),
)
),
],
),
),
),
const RepaintBoundary(
child: FlutterLogo(
size: 50,
),
),
Container(
height: 800,
),
const RepaintBoundary(child: FlutterLogo(size: 50)),
Container(height: 800),
],
),
);

View File

@ -14,16 +14,14 @@ class RRectBlur extends StatefulWidget {
State<RRectBlur> createState() => _RRectBlurPageState();
}
class _RRectBlurPageState extends State<RRectBlur>
with SingleTickerProviderStateMixin {
class _RRectBlurPageState extends State<RRectBlur> with SingleTickerProviderStateMixin {
late final AnimationController controller;
double tick = 0.0;
@override
void initState() {
super.initState();
controller =
AnimationController(vsync: this, duration: const Duration(hours: 1));
controller = AnimationController(vsync: this, duration: const Duration(hours: 1));
controller.addListener(() {
setState(() {
tick += 1;
@ -75,22 +73,15 @@ class PointsPainter extends CustomPainter {
const double freq = 0.25;
const int circleCount = 40;
for (int i = 0; i < circleCount; ++i) {
final double radius =
25 * cos(i + (1.0 * 2.0 * 3.1415 * tick) / 60.0) +
25;
final Paint paint = Paint()
..style = PaintingStyle.fill
..filterQuality = FilterQuality.low
..maskFilter = MaskFilter.blur(BlurStyle.normal, radius);
final double yval =
halfHeight * sin(i + (freq * 2.0 * 3.1415 * tick) / 60.0) +
halfHeight;
final double radius = 25 * cos(i + (1.0 * 2.0 * 3.1415 * tick) / 60.0) + 25;
final Paint paint =
Paint()
..style = PaintingStyle.fill
..filterQuality = FilterQuality.low
..maskFilter = MaskFilter.blur(BlurStyle.normal, radius);
final double yval = halfHeight * sin(i + (freq * 2.0 * 3.1415 * tick) / 60.0) + halfHeight;
final double xval = (i.toDouble() / circleCount) * size.width;
canvas.drawCircle(
Offset(xval, yval),
50,
paint..color = kColors[i % kColors.length],
);
canvas.drawCircle(Offset(xval, yval), 50, paint..color = kColors[i % kColors.length]);
}
}

View File

@ -12,8 +12,7 @@ class ShaderMaskCachePage extends StatefulWidget {
State<ShaderMaskCachePage> createState() => _ShaderMaskCachePageState();
}
class _ShaderMaskCachePageState extends State<ShaderMaskCachePage>
with TickerProviderStateMixin {
class _ShaderMaskCachePageState extends State<ShaderMaskCachePage> with TickerProviderStateMixin {
final ScrollController _controller = ScrollController();
@override
@ -21,7 +20,11 @@ class _ShaderMaskCachePageState extends State<ShaderMaskCachePage>
super.initState();
_controller.addListener(() {
if (_controller.offset < 10) {
_controller.animateTo(100, duration: const Duration(milliseconds: 1000), curve: Curves.ease);
_controller.animateTo(
100,
duration: const Duration(milliseconds: 1000),
curve: Curves.ease,
);
} else if (_controller.offset > 90) {
_controller.animateTo(0, duration: const Duration(milliseconds: 1000), curve: Curves.ease);
}
@ -60,12 +63,9 @@ class _ShaderMaskCachePageState extends State<ShaderMaskCachePage>
},
child: Container(
clipBehavior: Clip.antiAlias,
decoration: const BoxDecoration(boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.white,
blurRadius: 5.0,
),
]),
decoration: const BoxDecoration(
boxShadow: <BoxShadow>[BoxShadow(color: Colors.white, blurRadius: 5.0)],
),
child: ListItem(index: index),
),
);

View File

@ -11,8 +11,7 @@ class SimpleScroll extends StatelessWidget {
Widget build(BuildContext context) {
return ListView(
children: <Widget>[
for (int n = 0; n < 200; n += 1)
SizedBox(height: 40.0, child: Text('$n')),
for (int n = 0; n < 200; n += 1) SizedBox(height: 40.0, child: Text('$n')),
],
);
}

View File

@ -14,7 +14,7 @@ class SlidersPage extends StatefulWidget {
}
class _SlidersPageState extends State<SlidersPage> with TickerProviderStateMixin {
late AnimationController _sliderController;
late AnimationController _sliderController;
late Animation<double> _sliderAnimation;
double _sliderValue = 0.0;
RangeValues _rangeSliderValues = const RangeValues(0.0, 1.0);
@ -22,20 +22,17 @@ class _SlidersPageState extends State<SlidersPage> with TickerProviderStateMixin
@override
void initState() {
super.initState();
_sliderController = AnimationController(
duration: const Duration(seconds: 1),
vsync: this,
)..repeat();
_sliderAnimation = Tween<double>(begin: 0, end: 1).animate(_sliderController)
..addListener(() {
setState(() {
_sliderValue = _sliderAnimation.value;
_rangeSliderValues = RangeValues(
clampDouble(_sliderAnimation.value, 0, 0.45),
1.0 - clampDouble(_sliderAnimation.value, 0, 0.45),
);
});
_sliderController = AnimationController(duration: const Duration(seconds: 1), vsync: this)
..repeat();
_sliderAnimation = Tween<double>(begin: 0, end: 1).animate(_sliderController)..addListener(() {
setState(() {
_sliderValue = _sliderAnimation.value;
_rangeSliderValues = RangeValues(
clampDouble(_sliderAnimation.value, 0, 0.45),
1.0 - clampDouble(_sliderAnimation.value, 0, 0.45),
);
});
});
}
@override
@ -50,14 +47,8 @@ class _SlidersPageState extends State<SlidersPage> with TickerProviderStateMixin
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Slider(
value: _sliderValue,
onChanged: (double value) { },
),
RangeSlider(
values: _rangeSliderValues,
onChanged: (RangeValues values) { },
),
Slider(value: _sliderValue, onChanged: (double value) {}),
RangeSlider(values: _rangeSliderValues, onChanged: (RangeValues values) {}),
],
),
);

View File

@ -13,13 +13,7 @@ class TextPage extends StatelessWidget {
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(
width: 200,
height: 100,
child: TextField(
key: Key('basic-textfield'),
),
),
SizedBox(width: 200, height: 100, child: TextField(key: Key('basic-textfield'))),
],
),
);

View File

@ -30,17 +30,25 @@ class VeryLongPictureScrollingPerfState extends State<VeryLongPictureScrollingPe
Row(
children: <Widget>[
const Text('list:'),
Checkbox(value: useList, onChanged: (bool? value) => setState(() {
useList = value!;
}),),
Checkbox(
value: useList,
onChanged:
(bool? value) => setState(() {
useList = value!;
}),
),
],
),
Row(
children: <Widget>[
const Text('consolidate:'),
Checkbox(value: consolidate, onChanged: (bool? value) => setState(() {
consolidate = value!;
}),),
Checkbox(
value: consolidate,
onChanged:
(bool? value) => setState(() {
consolidate = value!;
}),
),
],
),
],
@ -49,48 +57,44 @@ class VeryLongPictureScrollingPerfState extends State<VeryLongPictureScrollingPe
body: SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: useList
? ListView.builder(
key: const ValueKey<String>('vlp_list_view_scrollable'),
scrollDirection: Axis.horizontal,
clipBehavior: Clip.none,
itemCount: (waveData.length / 200).ceil(),
itemExtent: 100,
itemBuilder: (BuildContext context, int index) => CustomPaint(
painter: PaintSomeTest(
waveData: waveData,
from: index * 200,
to: min((index + 1) * 200, waveData.length - 1),
)
),
)
: SingleChildScrollView(
key: const ValueKey<String>('vlp_single_child_scrollable'),
scrollDirection: Axis.horizontal,
child: SizedBox(
width: MediaQuery.of(context).size.width * 20,
height: MediaQuery.of(context).size.height,
child: RepaintBoundary(
child: CustomPaint(
isComplex: true,
painter: PaintTest(
consolidate: consolidate,
waveData: waveData,
child:
useList
? ListView.builder(
key: const ValueKey<String>('vlp_list_view_scrollable'),
scrollDirection: Axis.horizontal,
clipBehavior: Clip.none,
itemCount: (waveData.length / 200).ceil(),
itemExtent: 100,
itemBuilder:
(BuildContext context, int index) => CustomPaint(
painter: PaintSomeTest(
waveData: waveData,
from: index * 200,
to: min((index + 1) * 200, waveData.length - 1),
),
),
)
: SingleChildScrollView(
key: const ValueKey<String>('vlp_single_child_scrollable'),
scrollDirection: Axis.horizontal,
child: SizedBox(
width: MediaQuery.of(context).size.width * 20,
height: MediaQuery.of(context).size.height,
child: RepaintBoundary(
child: CustomPaint(
isComplex: true,
painter: PaintTest(consolidate: consolidate, waveData: waveData),
),
),
),
),
),
),
),
),
),
);
}
}
class PaintTest extends CustomPainter {
const PaintTest({
required this.consolidate,
required this.waveData,
});
const PaintTest({required this.consolidate, required this.waveData});
final bool consolidate;
final Int16List waveData;
@ -102,23 +106,26 @@ class PaintTest extends CustomPainter {
const double strokeSize = .5;
const double zoomFactor = .5;
final Paint paintPos = Paint()
..color = Colors.pink
..strokeWidth = strokeSize
..isAntiAlias = false
..style = PaintingStyle.stroke;
final Paint paintPos =
Paint()
..color = Colors.pink
..strokeWidth = strokeSize
..isAntiAlias = false
..style = PaintingStyle.stroke;
final Paint paintNeg = Paint()
..color = Colors.pink
..strokeWidth = strokeSize
..isAntiAlias = false
..style = PaintingStyle.stroke;
final Paint paintNeg =
Paint()
..color = Colors.pink
..strokeWidth = strokeSize
..isAntiAlias = false
..style = PaintingStyle.stroke;
final Paint paintZero = Paint()
..color = Colors.green
..strokeWidth = strokeSize
..isAntiAlias = false
..style = PaintingStyle.stroke;
final Paint paintZero =
Paint()
..color = Colors.green
..strokeWidth = strokeSize
..isAntiAlias = false
..style = PaintingStyle.stroke;
int index = 0;
Paint? listPaint;
@ -126,9 +133,9 @@ class PaintTest extends CustomPainter {
int used = 0;
for (index = 0; index < waveData.length; index++) {
final (Paint curPaint, Offset p1) = switch (waveData[index]) {
< 0 => (paintPos, Offset(x, halfHeight * (1 - waveData[index] / 32768))),
> 0 => (paintNeg, Offset(x, halfHeight * (1 - waveData[index] / 32767))),
_ => (paintZero, Offset(x, halfHeight + 1)),
< 0 => (paintPos, Offset(x, halfHeight * (1 - waveData[index] / 32768))),
> 0 => (paintNeg, Offset(x, halfHeight * (1 - waveData[index] / 32767))),
_ => (paintZero, Offset(x, halfHeight + 1)),
};
final Offset p0 = Offset(x, halfHeight);
if (consolidate) {
@ -160,11 +167,9 @@ class PaintTest extends CustomPainter {
}
class PaintSomeTest extends CustomPainter {
const PaintSomeTest({
required this.waveData,
int? from,
int? to,
}) : from = from ?? 0, to = to?? waveData.length;
const PaintSomeTest({required this.waveData, int? from, int? to})
: from = from ?? 0,
to = to ?? waveData.length;
final Int16List waveData;
final int from;
@ -177,29 +182,32 @@ class PaintSomeTest extends CustomPainter {
const double strokeSize = .5;
const double zoomFactor = .5;
final Paint paintPos = Paint()
..color = Colors.pink
..strokeWidth = strokeSize
..isAntiAlias = false
..style = PaintingStyle.stroke;
final Paint paintPos =
Paint()
..color = Colors.pink
..strokeWidth = strokeSize
..isAntiAlias = false
..style = PaintingStyle.stroke;
final Paint paintNeg = Paint()
..color = Colors.pink
..strokeWidth = strokeSize
..isAntiAlias = false
..style = PaintingStyle.stroke;
final Paint paintNeg =
Paint()
..color = Colors.pink
..strokeWidth = strokeSize
..isAntiAlias = false
..style = PaintingStyle.stroke;
final Paint paintZero = Paint()
..color = Colors.green
..strokeWidth = strokeSize
..isAntiAlias = false
..style = PaintingStyle.stroke;
final Paint paintZero =
Paint()
..color = Colors.green
..strokeWidth = strokeSize
..isAntiAlias = false
..style = PaintingStyle.stroke;
for (int index = from; index <= to; index++) {
final (Paint curPaint, Offset p1) = switch (waveData[index]) {
< 0 => (paintPos, Offset(x, halfHeight * (1 - waveData[index] / 32768))),
> 0 => (paintNeg, Offset(x, halfHeight * (1 - waveData[index] / 32767))),
_ => (paintZero, Offset(x, halfHeight + 1)),
< 0 => (paintPos, Offset(x, halfHeight * (1 - waveData[index] / 32768))),
> 0 => (paintNeg, Offset(x, halfHeight * (1 - waveData[index] / 32767))),
_ => (paintZero, Offset(x, halfHeight + 1)),
};
final Offset p0 = Offset(x, halfHeight);
canvas.drawLine(p0, p1, curPaint);

View File

@ -10,30 +10,251 @@ import 'package:flutter/widgets.dart';
import 'recorder.dart';
const List<int> kTransparentImage = <int>[
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49,
0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06,
0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4, 0x89, 0x00, 0x00, 0x00, 0x06, 0x62, 0x4B,
0x47, 0x44, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0xA0, 0xBD, 0xA7, 0x93, 0x00,
0x00, 0x00, 0x09, 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0B, 0x13, 0x00, 0x00,
0x0B, 0x13, 0x01, 0x00, 0x9A, 0x9C, 0x18, 0x00, 0x00, 0x00, 0x07, 0x74, 0x49,
0x4D, 0x45, 0x07, 0xE6, 0x03, 0x10, 0x17, 0x07, 0x1D, 0x2E, 0x5E, 0x30, 0x9B,
0x00, 0x00, 0x00, 0x0B, 0x49, 0x44, 0x41, 0x54, 0x08, 0xD7, 0x63, 0x60, 0x00,
0x02, 0x00, 0x00, 0x05, 0x00, 0x01, 0xE2, 0x26, 0x05, 0x9B, 0x00, 0x00, 0x00,
0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82,
0x89,
0x50,
0x4E,
0x47,
0x0D,
0x0A,
0x1A,
0x0A,
0x00,
0x00,
0x00,
0x0D,
0x49,
0x48,
0x44,
0x52,
0x00,
0x00,
0x00,
0x01,
0x00,
0x00,
0x00,
0x01,
0x08,
0x06,
0x00,
0x00,
0x00,
0x1F,
0x15,
0xC4,
0x89,
0x00,
0x00,
0x00,
0x06,
0x62,
0x4B,
0x47,
0x44,
0x00,
0xFF,
0x00,
0xFF,
0x00,
0xFF,
0xA0,
0xBD,
0xA7,
0x93,
0x00,
0x00,
0x00,
0x09,
0x70,
0x48,
0x59,
0x73,
0x00,
0x00,
0x0B,
0x13,
0x00,
0x00,
0x0B,
0x13,
0x01,
0x00,
0x9A,
0x9C,
0x18,
0x00,
0x00,
0x00,
0x07,
0x74,
0x49,
0x4D,
0x45,
0x07,
0xE6,
0x03,
0x10,
0x17,
0x07,
0x1D,
0x2E,
0x5E,
0x30,
0x9B,
0x00,
0x00,
0x00,
0x0B,
0x49,
0x44,
0x41,
0x54,
0x08,
0xD7,
0x63,
0x60,
0x00,
0x02,
0x00,
0x00,
0x05,
0x00,
0x01,
0xE2,
0x26,
0x05,
0x9B,
0x00,
0x00,
0x00,
0x00,
0x49,
0x45,
0x4E,
0x44,
0xAE,
0x42,
0x60,
0x82,
];
/// An animated GIF image with 3 1x1 pixel frames (a red, green, and blue
/// frames). The GIF animates forever, and each frame has a 100ms delay.
const List<int> kAnimatedGif = <int> [
0x47, 0x49, 0x46, 0x38, 0x39, 0x61, 0x01, 0x00, 0x01, 0x00, 0xa1, 0x03, 0x00,
0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x21,
0xff, 0x0b, 0x4e, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2e, 0x30,
0x03, 0x01, 0x00, 0x00, 0x00, 0x21, 0xf9, 0x04, 0x00, 0x0a, 0x00, 0xff, 0x00,
0x2c, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x4c,
0x01, 0x00, 0x21, 0xf9, 0x04, 0x00, 0x0a, 0x00, 0xff, 0x00, 0x2c, 0x00, 0x00,
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x54, 0x01, 0x00, 0x21,
0xf9, 0x04, 0x00, 0x0a, 0x00, 0xff, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x01,
0x00, 0x01, 0x00, 0x00, 0x02, 0x02, 0x44, 0x01, 0x00, 0x3b,
const List<int> kAnimatedGif = <int>[
0x47,
0x49,
0x46,
0x38,
0x39,
0x61,
0x01,
0x00,
0x01,
0x00,
0xa1,
0x03,
0x00,
0x00,
0x00,
0xff,
0xff,
0x00,
0x00,
0x00,
0xff,
0x00,
0xff,
0xff,
0xff,
0x21,
0xff,
0x0b,
0x4e,
0x45,
0x54,
0x53,
0x43,
0x41,
0x50,
0x45,
0x32,
0x2e,
0x30,
0x03,
0x01,
0x00,
0x00,
0x00,
0x21,
0xf9,
0x04,
0x00,
0x0a,
0x00,
0xff,
0x00,
0x2c,
0x00,
0x00,
0x00,
0x00,
0x01,
0x00,
0x01,
0x00,
0x00,
0x02,
0x02,
0x4c,
0x01,
0x00,
0x21,
0xf9,
0x04,
0x00,
0x0a,
0x00,
0xff,
0x00,
0x2c,
0x00,
0x00,
0x00,
0x00,
0x01,
0x00,
0x01,
0x00,
0x00,
0x02,
0x02,
0x54,
0x01,
0x00,
0x21,
0xf9,
0x04,
0x00,
0x0a,
0x00,
0xff,
0x00,
0x2c,
0x00,
0x00,
0x00,
0x00,
0x01,
0x00,
0x01,
0x00,
0x00,
0x02,
0x02,
0x44,
0x01,
0x00,
0x3b,
];
/// Measures expense of constructing Image widgets.
@ -47,10 +268,12 @@ class BenchBuildImage extends WidgetRecorder {
return Directionality(
textDirection: TextDirection.ltr,
child: _RotatingWidget(
child: Row(children: <Widget>[
Image.memory(Uint8List.fromList(kTransparentImage)),
Image.memory(Uint8List.fromList(kAnimatedGif)),
]),
child: Row(
children: <Widget>[
Image.memory(Uint8List.fromList(kTransparentImage)),
Image.memory(Uint8List.fromList(kAnimatedGif)),
],
),
),
);
}
@ -71,10 +294,8 @@ class _RotatingWidgetState extends State<_RotatingWidget> with SingleTickerProvi
@override
void initState() {
super.initState();
controller = AnimationController(
duration: const Duration(milliseconds: 200),
vsync: this,
)..repeat();
controller = AnimationController(duration: const Duration(milliseconds: 200), vsync: this)
..repeat();
}
@override

View File

@ -32,8 +32,8 @@ class BenchBuildMaterialCheckbox extends WidgetBuildRecorder {
Row _buildRow() {
_isChecked = switch (_isChecked) {
null => true,
true => false,
null => true,
true => false,
false => null,
};

View File

@ -56,9 +56,7 @@ class _InfiniteScrollCardsState extends State<_InfiniteScrollCards> {
offset = widget.initialOffset;
scrollController = ScrollController(
initialScrollOffset: offset,
);
scrollController = ScrollController(initialScrollOffset: offset);
// Without the timer the animation doesn't begin.
Timer.run(() async {
@ -86,10 +84,7 @@ class _InfiniteScrollCardsState extends State<_InfiniteScrollCards> {
height: 100.0,
child: Card(
elevation: 16.0,
child: Text(
'${lipsum[index % lipsum.length]} $index',
textAlign: TextAlign.center,
),
child: Text('${lipsum[index % lipsum.length]} $index', textAlign: TextAlign.center),
),
);
},

View File

@ -39,10 +39,7 @@ class BenchUpdateManyChildLayers extends SceneBuilderRecorder {
Future<void> setUpAll() async {
_pictures = <Picture>[];
viewSize = view.physicalSize;
cellSize = Size(
viewSize.width / kColumns,
viewSize.height / kRows,
);
cellSize = Size(viewSize.width / kColumns, viewSize.height / kRows);
rectSize = cellSize * 0.8;
final Paint paint = Paint()..color = const Color.fromARGB(255, 255, 0, 0);
@ -72,11 +69,7 @@ class BenchUpdateManyChildLayers extends SceneBuilderRecorder {
if (shouldRetain) {
sceneBuilder.addRetained(oldLayer);
} else {
_layers[layerId] = sceneBuilder.pushOffset(
wobbleOffsetX,
offsetY,
oldLayer: oldLayer,
);
_layers[layerId] = sceneBuilder.pushOffset(wobbleOffsetX, offsetY, oldLayer: oldLayer);
sceneBuilder.addPicture(Offset.zero, _pictures[row * kColumns + col]);
sceneBuilder.pop();
}

View File

@ -42,27 +42,24 @@ class BenchClippedOutPictures extends SceneBuilderRecorder {
@override
void onDrawFrame(SceneBuilder sceneBuilder) {
final Size viewSize = view.physicalSize / view.devicePixelRatio;
final Size pictureSize = Size(
viewSize.width / kColumns,
viewSize.height / kRows,
);
final Size pictureSize = Size(viewSize.width / kColumns, viewSize.height / kRows);
// Fills a single cell with random text.
void fillCell(int row, int column) {
sceneBuilder.pushOffset(
column * pictureSize.width,
row * pictureSize.height,
);
sceneBuilder.pushOffset(column * pictureSize.width, row * pictureSize.height);
final PictureRecorder pictureRecorder = PictureRecorder();
final Canvas canvas = Canvas(pictureRecorder);
canvas.save();
canvas.drawCircle(Offset(pictureSize.width / 2, pictureSize.height / 2), 5.0, paint);
canvas.drawRect(Rect.fromCenter(
center: Offset(pictureSize.width / 2, pictureSize.height / 2),
width: pictureSize.width / 6,
height: pictureSize.height / 6,
), paint);
canvas.drawRect(
Rect.fromCenter(
center: Offset(pictureSize.width / 2, pictureSize.height / 2),
width: pictureSize.width / 6,
height: pictureSize.height / 6,
),
paint,
);
canvas.restore();
final Picture picture = pictureRecorder.endRecording();
sceneBuilder.addPicture(Offset.zero, picture);
@ -70,14 +67,13 @@ class BenchClippedOutPictures extends SceneBuilderRecorder {
}
// Starting with the top-left cell, fill every cell.
sceneBuilder.pushClipRect(Rect.fromCircle(
center: Offset(viewSize.width / 2, viewSize.height / 2),
radius: math.min(viewSize.width, viewSize.height) / 6,
));
sceneBuilder.pushOffset(
5.0 * math.cos(angle),
5.0 * math.sin(angle),
sceneBuilder.pushClipRect(
Rect.fromCircle(
center: Offset(viewSize.width / 2, viewSize.height / 2),
radius: math.min(viewSize.width, viewSize.height) / 6,
),
);
sceneBuilder.pushOffset(5.0 * math.cos(angle), 5.0 * math.sin(angle));
angle += math.pi / 20;
for (int row = 0; row < 10; row++) {
for (int column = 0; column < 10; column++) {

View File

@ -49,7 +49,12 @@ class BenchDrawRect extends SceneBuilderRecorder {
if (benchmarkPaint) {
final Paint paint = Paint();
final double rowRatio = row / kRows;
paint.color = Color.fromARGB(255, (255 * rowRatio).floor(), (255 * col / kColumns).floor(), 255);
paint.color = Color.fromARGB(
255,
(255 * rowRatio).floor(),
(255 * col / kColumns).floor(),
255,
);
paint.filterQuality = FilterQuality.values[(FilterQuality.values.length * rowRatio).floor()];
paint.strokeCap = StrokeCap.values[(StrokeCap.values.length * rowRatio).floor()];
paint.strokeJoin = StrokeJoin.values[(StrokeJoin.values.length * rowRatio).floor()];
@ -69,19 +74,13 @@ class BenchDrawRect extends SceneBuilderRecorder {
final Canvas canvas = Canvas(pictureRecorder);
final Size viewSize = view.physicalSize;
final Size cellSize = Size(
viewSize.width / kColumns,
viewSize.height / kRows,
);
final Size cellSize = Size(viewSize.width / kColumns, viewSize.height / kRows);
final Size rectSize = cellSize * 0.8;
for (int row = 0; row < kRows; row++) {
canvas.save();
for (int col = 0; col < kColumns; col++) {
canvas.drawRect(
Offset((wobbleCounter - 5).abs(), 0) & rectSize,
makePaint(row, col),
);
canvas.drawRect(Offset((wobbleCounter - 5).abs(), 0) & rectSize, makePaint(row, col));
canvas.translate(cellSize.width, 0);
}
canvas.restore();

View File

@ -43,7 +43,7 @@ class BenchDynamicClipOnStaticPicture extends SceneBuilderRecorder {
'Bad combination of constant values kRowHeight, kRows, and '
'kScrollData. With these numbers there is risk that the picture '
'will scroll out of the clip entirely. To fix the issue reduce '
'kScrollDelta, or increase either kRows or kRowHeight.'
'kScrollDelta, or increase either kRows or kRowHeight.',
);
}
@ -52,10 +52,7 @@ class BenchDynamicClipOnStaticPicture extends SceneBuilderRecorder {
final PictureRecorder pictureRecorder = PictureRecorder();
final Canvas canvas = Canvas(pictureRecorder);
viewSize = view.physicalSize / view.devicePixelRatio;
clipSize = Size(
viewSize.width / 2,
viewSize.height / 5,
);
clipSize = Size(viewSize.width / 2, viewSize.height / 5);
final double cellWidth = viewSize.width / kColumns;
final List<Paragraph> paragraphs = generateLaidOutParagraphs(
@ -72,12 +69,7 @@ class BenchDynamicClipOnStaticPicture extends SceneBuilderRecorder {
for (int column = 0; column < kColumns; column += 1) {
final double left = cellWidth * column;
canvas.save();
canvas.clipRect(Rect.fromLTWH(
left,
yOffset,
cellWidth,
20.0,
));
canvas.clipRect(Rect.fromLTWH(left, yOffset, cellWidth, 20.0));
canvas.drawParagraph(
paragraphs[paragraphCounter % paragraphs.length],
Offset(left, yOffset),

View File

@ -19,10 +19,7 @@ import 'recorder.dart';
// but the browser's WebCodecs API is asynchronous running on a separate thread
// and does not jank. However, the benchmark result may be the same.
class BenchImageDecoding extends RawRecorder {
BenchImageDecoding() : super(
name: benchmarkName,
useCustomWarmUp: true,
);
BenchImageDecoding() : super(name: benchmarkName, useCustomWarmUp: true);
static const String benchmarkName = 'bench_image_decoding';
@ -62,8 +59,7 @@ class BenchImageDecoding extends RawRecorder {
Future<void> body(Profile profile) async {
await profile.recordAsync('recordImageDecode', () async {
final List<Future<void>> allDecodes = <Future<void>>[
for (final Uint8List data in _imageData)
_decodeImage(data),
for (final Uint8List data in _imageData) _decodeImage(data),
];
await Future.wait(allDecodes);
}, reported: true);
@ -84,7 +80,7 @@ Future<void> _decodeImage(Uint8List data) async {
if (codec.frameCount < decodeFrameCount) {
throw Exception(
'Test image contains too few frames for this benchmark (${codec.frameCount}). '
'Choose a test image with at least $decodeFrameCount frames.'
'Choose a test image with at least $decodeFrameCount frames.',
);
}
for (int i = 0; i < decodeFrameCount; i++) {

View File

@ -39,7 +39,9 @@ class BenchMaterial3Semantics extends WidgetBuildRecorder {
final AggregatedTimings timings = FlutterTimeline.debugCollect();
final AggregatedTimedBlock semanticsBlock = timings.getAggregated('SEMANTICS');
final AggregatedTimedBlock getFragmentBlock = timings.getAggregated('Semantics.GetFragment');
final AggregatedTimedBlock compileChildrenBlock = timings.getAggregated('Semantics.compileChildren');
final AggregatedTimedBlock compileChildrenBlock = timings.getAggregated(
'Semantics.compileChildren',
);
profile!.addTimedBlock(semanticsBlock, reported: true);
profile!.addTimedBlock(getFragmentBlock, reported: true);
profile!.addTimedBlock(compileChildrenBlock, reported: true);
@ -89,7 +91,9 @@ class BenchMaterial3ScrollSemantics extends WidgetRecorder {
final AggregatedTimings timings = FlutterTimeline.debugCollect();
final AggregatedTimedBlock semanticsBlock = timings.getAggregated('SEMANTICS');
final AggregatedTimedBlock getFragmentBlock = timings.getAggregated('Semantics.GetFragment');
final AggregatedTimedBlock compileChildrenBlock = timings.getAggregated('Semantics.compileChildren');
final AggregatedTimedBlock compileChildrenBlock = timings.getAggregated(
'Semantics.compileChildren',
);
profile!.addTimedBlock(semanticsBlock, reported: true);
profile!.addTimedBlock(getFragmentBlock, reported: true);
profile!.addTimedBlock(compileChildrenBlock, reported: true);
@ -140,8 +144,6 @@ class _ScrollTestState extends State<_ScrollTest> with SingleTickerProviderState
@override
Widget build(BuildContext context) {
return SingleColumnMaterial3Components(
scrollController: scrollController,
);
return SingleColumnMaterial3Components(scrollController: scrollController);
}
}

View File

@ -23,10 +23,7 @@ class _NestedMouseRegion extends StatelessWidget {
Widget build(BuildContext context) {
Widget current = child;
for (int i = 0; i < nests; i++) {
current = MouseRegion(
onEnter: (_) {},
child: child,
);
current = MouseRegion(onEnter: (_) {}, child: child);
}
return current;
}
@ -90,25 +87,26 @@ class BenchMouseRegionGridHover extends WidgetRecorder {
itemCount: rowsCount,
cacheExtent: rowsCount * containerSize,
physics: const ClampingScrollPhysics(),
itemBuilder: (BuildContext context, int rowIndex) => _NestedMouseRegion(
nests: 10,
child: Row(
children: List<Widget>.generate(
columnsCount,
(int columnIndex) => _NestedMouseRegion(
nests: 10,
child: Container(
decoration: BoxDecoration(
border: _getBorder(columnIndex, rowIndex),
color: Color.fromARGB(255, rowIndex * 20 % 256, 127, 127),
itemBuilder:
(BuildContext context, int rowIndex) => _NestedMouseRegion(
nests: 10,
child: Row(
children: List<Widget>.generate(
columnsCount,
(int columnIndex) => _NestedMouseRegion(
nests: 10,
child: Container(
decoration: BoxDecoration(
border: _getBorder(columnIndex, rowIndex),
color: Color.fromARGB(255, rowIndex * 20 % 256, 127, 127),
),
width: containerSize,
height: containerSize,
),
),
width: containerSize,
height: containerSize,
),
),
),
),
),
),
),
),
@ -148,6 +146,7 @@ class _Tester {
kind: PointerDeviceKind.mouse,
);
}
TestGesture? _gesture;
Duration currentTime = Duration.zero;

View File

@ -65,22 +65,23 @@ class BenchMouseRegionGridScroll extends WidgetRecorder {
itemCount: rowsCount,
cacheExtent: rowsCount * containerSize,
physics: const ClampingScrollPhysics(),
itemBuilder: (BuildContext context, int rowIndex) => Row(
children: List<Widget>.generate(
columnsCount,
(int columnIndex) => MouseRegion(
onEnter: (_) {},
child: Container(
decoration: BoxDecoration(
border: _getBorder(columnIndex, rowIndex),
color: Color.fromARGB(255, rowIndex * 20 % 256, 127, 127),
itemBuilder:
(BuildContext context, int rowIndex) => Row(
children: List<Widget>.generate(
columnsCount,
(int columnIndex) => MouseRegion(
onEnter: (_) {},
child: Container(
decoration: BoxDecoration(
border: _getBorder(columnIndex, rowIndex),
color: Color.fromARGB(255, rowIndex * 20 % 256, 127, 127),
),
width: containerSize,
height: containerSize,
),
),
width: containerSize,
height: containerSize,
),
),
),
),
),
),
),
@ -120,6 +121,7 @@ class _Tester {
kind: PointerDeviceKind.mouse,
);
}
TestGesture? _gesture;
Duration currentTime = Duration.zero;

Some files were not shown because too many files have changed in this diff Show More