From 0061b0d70db6fdaa829c2138e237d6e76a0ddf70 Mon Sep 17 00:00:00 2001 From: Brett Morgan Date: Tue, 12 Oct 2021 11:12:35 +1100 Subject: [PATCH] `platform_design`: Enforce `use_key_in_widget_constructors` (#927) --- platform_design/analysis_options.yaml | 2 -- platform_design/lib/main.dart | 19 ++++++++++++------- platform_design/lib/news_tab.dart | 2 ++ platform_design/lib/profile_tab.dart | 11 ++++++++--- platform_design/lib/settings_tab.dart | 2 ++ platform_design/lib/song_detail_tab.dart | 5 +++-- platform_design/lib/widgets.dart | 8 ++++++-- platform_design/test/widget_test.dart | 4 ++-- 8 files changed, 35 insertions(+), 18 deletions(-) diff --git a/platform_design/analysis_options.yaml b/platform_design/analysis_options.yaml index 2d21f645a..85f6fbe91 100644 --- a/platform_design/analysis_options.yaml +++ b/platform_design/analysis_options.yaml @@ -17,5 +17,3 @@ linter: test_types_in_equals: true throw_in_finally: true unnecessary_statements: true - # Tests fail if we enforce `use_key_in_widget_constructors` - use_key_in_widget_constructors: false diff --git a/platform_design/lib/main.dart b/platform_design/lib/main.dart index a3b089d55..fc4fd52ac 100644 --- a/platform_design/lib/main.dart +++ b/platform_design/lib/main.dart @@ -11,9 +11,11 @@ import 'settings_tab.dart'; import 'songs_tab.dart'; import 'widgets.dart'; -void main() => runApp(MyAdaptingApp()); +void main() => runApp(const MyAdaptingApp()); class MyAdaptingApp extends StatelessWidget { + const MyAdaptingApp({Key? key}) : super(key: key); + @override Widget build(context) { // Either Material or Cupertino widgets work in either Material or Cupertino @@ -34,6 +36,7 @@ class MyAdaptingApp extends StatelessWidget { child: Material(child: child), ); }, + // ignore: use_key_in_widget_constructors home: PlatformAdaptingHomePage(), ); } @@ -47,6 +50,8 @@ class MyAdaptingApp extends StatelessWidget { // These differences are also subjective and have more than one 'right' answer // depending on the app and content. class PlatformAdaptingHomePage extends StatefulWidget { + const PlatformAdaptingHomePage({Key? key}) : super(key: key); + @override _PlatformAdaptingHomePageState createState() => _PlatformAdaptingHomePageState(); @@ -107,12 +112,12 @@ class _PlatformAdaptingHomePageState extends State { case 1: return CupertinoTabView( defaultTitle: NewsTab.title, - builder: (context) => NewsTab(), + builder: (context) => const NewsTab(), ); case 2: return CupertinoTabView( defaultTitle: ProfileTab.title, - builder: (context) => ProfileTab(), + builder: (context) => const ProfileTab(), ); default: assert(false, 'Unexpected tab'); @@ -161,8 +166,8 @@ class _AndroidDrawer extends StatelessWidget { title: const Text(NewsTab.title), onTap: () { Navigator.pop(context); - Navigator.push( - context, MaterialPageRoute(builder: (context) => NewsTab())); + Navigator.push(context, + MaterialPageRoute(builder: (context) => const NewsTab())); }, ), ListTile( @@ -171,7 +176,7 @@ class _AndroidDrawer extends StatelessWidget { onTap: () { Navigator.pop(context); Navigator.push(context, - MaterialPageRoute(builder: (context) => ProfileTab())); + MaterialPageRoute(builder: (context) => const ProfileTab())); }, ), // Long drawer contents are often segmented. @@ -185,7 +190,7 @@ class _AndroidDrawer extends StatelessWidget { onTap: () { Navigator.pop(context); Navigator.push(context, - MaterialPageRoute(builder: (context) => SettingsTab())); + MaterialPageRoute(builder: (context) => const SettingsTab())); }, ), ], diff --git a/platform_design/lib/news_tab.dart b/platform_design/lib/news_tab.dart index a9aa83166..5debbb4be 100644 --- a/platform_design/lib/news_tab.dart +++ b/platform_design/lib/news_tab.dart @@ -15,6 +15,8 @@ class NewsTab extends StatefulWidget { static const androidIcon = Icon(Icons.library_books); static const iosIcon = Icon(CupertinoIcons.news); + const NewsTab({Key? key}) : super(key: key); + @override _NewsTabState createState() => _NewsTabState(); } diff --git a/platform_design/lib/profile_tab.dart b/platform_design/lib/profile_tab.dart index 70b571404..20df6a41a 100644 --- a/platform_design/lib/profile_tab.dart +++ b/platform_design/lib/profile_tab.dart @@ -13,6 +13,8 @@ class ProfileTab extends StatelessWidget { static const androidIcon = Icon(Icons.person); static const iosIcon = Icon(CupertinoIcons.profile_circled); + const ProfileTab({Key? key}) : super(key: key); + Widget _buildBody(BuildContext context) { return SafeArea( child: Padding( @@ -55,7 +57,7 @@ class ProfileTab extends StatelessWidget { Expanded( child: Container(), ), - LogOutButton(), + const LogOutButton(), ], ), ), @@ -89,7 +91,7 @@ class ProfileTab extends StatelessWidget { CupertinoPageRoute( title: SettingsTab.title, fullscreenDialog: true, - builder: (context) => SettingsTab(), + builder: (context) => const SettingsTab(), ), ); }, @@ -113,7 +115,8 @@ class PreferenceCard extends StatelessWidget { required this.header, required this.content, required this.preferenceChoices, - }); + Key? key, + }) : super(key: key); final String header; final String content; @@ -171,6 +174,8 @@ class LogOutButton extends StatelessWidget { static const _logoutMessage = Text( "You can't actually log out! This is just a demo of how alerts work."); + const LogOutButton({Key? key}) : super(key: key); + // =========================================================================== // Non-shared code below because this tab shows different interfaces. On // Android, it's showing an alert dialog with 2 buttons and on iOS, diff --git a/platform_design/lib/settings_tab.dart b/platform_design/lib/settings_tab.dart index ae29d5cf7..6b9ea42c1 100644 --- a/platform_design/lib/settings_tab.dart +++ b/platform_design/lib/settings_tab.dart @@ -12,6 +12,8 @@ class SettingsTab extends StatefulWidget { static const androidIcon = Icon(Icons.settings); static const iosIcon = Icon(CupertinoIcons.gear); + const SettingsTab({Key? key}) : super(key: key); + @override _SettingsTabState createState() => _SettingsTabState(); } diff --git a/platform_design/lib/song_detail_tab.dart b/platform_design/lib/song_detail_tab.dart index 67811a104..e4eb0162f 100644 --- a/platform_design/lib/song_detail_tab.dart +++ b/platform_design/lib/song_detail_tab.dart @@ -16,7 +16,8 @@ class SongDetailTab extends StatelessWidget { required this.id, required this.song, required this.color, - }); + Key? key, + }) : super(key: key); final int id; final String song; @@ -71,7 +72,7 @@ class SongDetailTab extends StatelessWidget { ); } // Just a bunch of boxes that simulates loading song choices. - return SongPlaceholderTile(); + return const SongPlaceholderTile(); }, ), ), diff --git a/platform_design/lib/widgets.dart b/platform_design/lib/widgets.dart index 7645010da..a26ed9dbd 100644 --- a/platform_design/lib/widgets.dart +++ b/platform_design/lib/widgets.dart @@ -41,7 +41,8 @@ class PressableCard extends StatefulWidget { required this.color, required this.flattenAnimation, this.child, - }); + Key? key, + }) : super(key: key); final VoidCallback? onPressed; final Color color; @@ -140,7 +141,8 @@ class HeroAnimatingSongCard extends StatelessWidget { required this.color, required this.heroAnimation, this.onPressed, - }); + Key? key, + }) : super(key: key); final String song; final Color color; @@ -218,6 +220,8 @@ class HeroAnimatingSongCard extends StatelessWidget { /// This is an example of a custom widget that an app developer might create for /// use on both iOS and Android as part of their brand's unique design. class SongPlaceholderTile extends StatelessWidget { + const SongPlaceholderTile({Key? key}) : super(key: key); + @override Widget build(BuildContext context) { return SizedBox( diff --git a/platform_design/test/widget_test.dart b/platform_design/test/widget_test.dart index 273ef0ec1..e5f7d3b46 100644 --- a/platform_design/test/widget_test.dart +++ b/platform_design/test/widget_test.dart @@ -11,7 +11,7 @@ import 'package:platform_design/main.dart'; void main() { testWidgets('Can change platform correctly', (tester) async { - await tester.pumpWidget(MyAdaptingApp()); + await tester.pumpWidget(const MyAdaptingApp()); // The test should be able to find the drawer button. expect(find.byIcon(Icons.menu), findsOneWidget); @@ -19,7 +19,7 @@ void main() { expect(find.byIcon(Icons.refresh), findsOneWidget); debugDefaultTargetPlatformOverride = TargetPlatform.iOS; - await tester.pumpWidget(MyAdaptingApp()); + await tester.pumpWidget(const MyAdaptingApp()); // There should now be a large title style nav bar. expect(find.byType(CupertinoSliverNavigationBar), findsOneWidget);