Skip to content

Commit 0061b0d

Browse files
platform_design: Enforce use_key_in_widget_constructors (flutter#927)
1 parent ac2bef7 commit 0061b0d

File tree

8 files changed

+35
-18
lines changed

8 files changed

+35
-18
lines changed

platform_design/analysis_options.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,3 @@ linter:
1717
test_types_in_equals: true
1818
throw_in_finally: true
1919
unnecessary_statements: true
20-
# Tests fail if we enforce `use_key_in_widget_constructors`
21-
use_key_in_widget_constructors: false

platform_design/lib/main.dart

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ import 'settings_tab.dart';
1111
import 'songs_tab.dart';
1212
import 'widgets.dart';
1313

14-
void main() => runApp(MyAdaptingApp());
14+
void main() => runApp(const MyAdaptingApp());
1515

1616
class MyAdaptingApp extends StatelessWidget {
17+
const MyAdaptingApp({Key? key}) : super(key: key);
18+
1719
@override
1820
Widget build(context) {
1921
// Either Material or Cupertino widgets work in either Material or Cupertino
@@ -34,6 +36,7 @@ class MyAdaptingApp extends StatelessWidget {
3436
child: Material(child: child),
3537
);
3638
},
39+
// ignore: use_key_in_widget_constructors
3740
home: PlatformAdaptingHomePage(),
3841
);
3942
}
@@ -47,6 +50,8 @@ class MyAdaptingApp extends StatelessWidget {
4750
// These differences are also subjective and have more than one 'right' answer
4851
// depending on the app and content.
4952
class PlatformAdaptingHomePage extends StatefulWidget {
53+
const PlatformAdaptingHomePage({Key? key}) : super(key: key);
54+
5055
@override
5156
_PlatformAdaptingHomePageState createState() =>
5257
_PlatformAdaptingHomePageState();
@@ -107,12 +112,12 @@ class _PlatformAdaptingHomePageState extends State<PlatformAdaptingHomePage> {
107112
case 1:
108113
return CupertinoTabView(
109114
defaultTitle: NewsTab.title,
110-
builder: (context) => NewsTab(),
115+
builder: (context) => const NewsTab(),
111116
);
112117
case 2:
113118
return CupertinoTabView(
114119
defaultTitle: ProfileTab.title,
115-
builder: (context) => ProfileTab(),
120+
builder: (context) => const ProfileTab(),
116121
);
117122
default:
118123
assert(false, 'Unexpected tab');
@@ -161,8 +166,8 @@ class _AndroidDrawer extends StatelessWidget {
161166
title: const Text(NewsTab.title),
162167
onTap: () {
163168
Navigator.pop(context);
164-
Navigator.push<void>(
165-
context, MaterialPageRoute(builder: (context) => NewsTab()));
169+
Navigator.push<void>(context,
170+
MaterialPageRoute(builder: (context) => const NewsTab()));
166171
},
167172
),
168173
ListTile(
@@ -171,7 +176,7 @@ class _AndroidDrawer extends StatelessWidget {
171176
onTap: () {
172177
Navigator.pop(context);
173178
Navigator.push<void>(context,
174-
MaterialPageRoute(builder: (context) => ProfileTab()));
179+
MaterialPageRoute(builder: (context) => const ProfileTab()));
175180
},
176181
),
177182
// Long drawer contents are often segmented.
@@ -185,7 +190,7 @@ class _AndroidDrawer extends StatelessWidget {
185190
onTap: () {
186191
Navigator.pop(context);
187192
Navigator.push<void>(context,
188-
MaterialPageRoute(builder: (context) => SettingsTab()));
193+
MaterialPageRoute(builder: (context) => const SettingsTab()));
189194
},
190195
),
191196
],

platform_design/lib/news_tab.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ class NewsTab extends StatefulWidget {
1515
static const androidIcon = Icon(Icons.library_books);
1616
static const iosIcon = Icon(CupertinoIcons.news);
1717

18+
const NewsTab({Key? key}) : super(key: key);
19+
1820
@override
1921
_NewsTabState createState() => _NewsTabState();
2022
}

platform_design/lib/profile_tab.dart

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ class ProfileTab extends StatelessWidget {
1313
static const androidIcon = Icon(Icons.person);
1414
static const iosIcon = Icon(CupertinoIcons.profile_circled);
1515

16+
const ProfileTab({Key? key}) : super(key: key);
17+
1618
Widget _buildBody(BuildContext context) {
1719
return SafeArea(
1820
child: Padding(
@@ -55,7 +57,7 @@ class ProfileTab extends StatelessWidget {
5557
Expanded(
5658
child: Container(),
5759
),
58-
LogOutButton(),
60+
const LogOutButton(),
5961
],
6062
),
6163
),
@@ -89,7 +91,7 @@ class ProfileTab extends StatelessWidget {
8991
CupertinoPageRoute(
9092
title: SettingsTab.title,
9193
fullscreenDialog: true,
92-
builder: (context) => SettingsTab(),
94+
builder: (context) => const SettingsTab(),
9395
),
9496
);
9597
},
@@ -113,7 +115,8 @@ class PreferenceCard extends StatelessWidget {
113115
required this.header,
114116
required this.content,
115117
required this.preferenceChoices,
116-
});
118+
Key? key,
119+
}) : super(key: key);
117120

118121
final String header;
119122
final String content;
@@ -171,6 +174,8 @@ class LogOutButton extends StatelessWidget {
171174
static const _logoutMessage = Text(
172175
"You can't actually log out! This is just a demo of how alerts work.");
173176

177+
const LogOutButton({Key? key}) : super(key: key);
178+
174179
// ===========================================================================
175180
// Non-shared code below because this tab shows different interfaces. On
176181
// Android, it's showing an alert dialog with 2 buttons and on iOS,

platform_design/lib/settings_tab.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ class SettingsTab extends StatefulWidget {
1212
static const androidIcon = Icon(Icons.settings);
1313
static const iosIcon = Icon(CupertinoIcons.gear);
1414

15+
const SettingsTab({Key? key}) : super(key: key);
16+
1517
@override
1618
_SettingsTabState createState() => _SettingsTabState();
1719
}

platform_design/lib/song_detail_tab.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ class SongDetailTab extends StatelessWidget {
1616
required this.id,
1717
required this.song,
1818
required this.color,
19-
});
19+
Key? key,
20+
}) : super(key: key);
2021

2122
final int id;
2223
final String song;
@@ -71,7 +72,7 @@ class SongDetailTab extends StatelessWidget {
7172
);
7273
}
7374
// Just a bunch of boxes that simulates loading song choices.
74-
return SongPlaceholderTile();
75+
return const SongPlaceholderTile();
7576
},
7677
),
7778
),

platform_design/lib/widgets.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ class PressableCard extends StatefulWidget {
4141
required this.color,
4242
required this.flattenAnimation,
4343
this.child,
44-
});
44+
Key? key,
45+
}) : super(key: key);
4546

4647
final VoidCallback? onPressed;
4748
final Color color;
@@ -140,7 +141,8 @@ class HeroAnimatingSongCard extends StatelessWidget {
140141
required this.color,
141142
required this.heroAnimation,
142143
this.onPressed,
143-
});
144+
Key? key,
145+
}) : super(key: key);
144146

145147
final String song;
146148
final Color color;
@@ -218,6 +220,8 @@ class HeroAnimatingSongCard extends StatelessWidget {
218220
/// This is an example of a custom widget that an app developer might create for
219221
/// use on both iOS and Android as part of their brand's unique design.
220222
class SongPlaceholderTile extends StatelessWidget {
223+
const SongPlaceholderTile({Key? key}) : super(key: key);
224+
221225
@override
222226
Widget build(BuildContext context) {
223227
return SizedBox(

platform_design/test/widget_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ import 'package:platform_design/main.dart';
1111

1212
void main() {
1313
testWidgets('Can change platform correctly', (tester) async {
14-
await tester.pumpWidget(MyAdaptingApp());
14+
await tester.pumpWidget(const MyAdaptingApp());
1515

1616
// The test should be able to find the drawer button.
1717
expect(find.byIcon(Icons.menu), findsOneWidget);
1818
// There should be a refresh button.
1919
expect(find.byIcon(Icons.refresh), findsOneWidget);
2020

2121
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
22-
await tester.pumpWidget(MyAdaptingApp());
22+
await tester.pumpWidget(const MyAdaptingApp());
2323

2424
// There should now be a large title style nav bar.
2525
expect(find.byType(CupertinoSliverNavigationBar), findsOneWidget);

0 commit comments

Comments
 (0)