`platform_design`: Enforce `use_key_in_widget_constructors` (#927)

pull/929/head
Brett Morgan 3 years ago committed by GitHub
parent ac2bef7d83
commit 0061b0d70d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -17,5 +17,3 @@ linter:
test_types_in_equals: true test_types_in_equals: true
throw_in_finally: true throw_in_finally: true
unnecessary_statements: true unnecessary_statements: true
# Tests fail if we enforce `use_key_in_widget_constructors`
use_key_in_widget_constructors: false

@ -11,9 +11,11 @@ import 'settings_tab.dart';
import 'songs_tab.dart'; import 'songs_tab.dart';
import 'widgets.dart'; import 'widgets.dart';
void main() => runApp(MyAdaptingApp()); void main() => runApp(const MyAdaptingApp());
class MyAdaptingApp extends StatelessWidget { class MyAdaptingApp extends StatelessWidget {
const MyAdaptingApp({Key? key}) : super(key: key);
@override @override
Widget build(context) { Widget build(context) {
// Either Material or Cupertino widgets work in either Material or Cupertino // Either Material or Cupertino widgets work in either Material or Cupertino
@ -34,6 +36,7 @@ class MyAdaptingApp extends StatelessWidget {
child: Material(child: child), child: Material(child: child),
); );
}, },
// ignore: use_key_in_widget_constructors
home: PlatformAdaptingHomePage(), home: PlatformAdaptingHomePage(),
); );
} }
@ -47,6 +50,8 @@ class MyAdaptingApp extends StatelessWidget {
// These differences are also subjective and have more than one 'right' answer // These differences are also subjective and have more than one 'right' answer
// depending on the app and content. // depending on the app and content.
class PlatformAdaptingHomePage extends StatefulWidget { class PlatformAdaptingHomePage extends StatefulWidget {
const PlatformAdaptingHomePage({Key? key}) : super(key: key);
@override @override
_PlatformAdaptingHomePageState createState() => _PlatformAdaptingHomePageState createState() =>
_PlatformAdaptingHomePageState(); _PlatformAdaptingHomePageState();
@ -107,12 +112,12 @@ class _PlatformAdaptingHomePageState extends State<PlatformAdaptingHomePage> {
case 1: case 1:
return CupertinoTabView( return CupertinoTabView(
defaultTitle: NewsTab.title, defaultTitle: NewsTab.title,
builder: (context) => NewsTab(), builder: (context) => const NewsTab(),
); );
case 2: case 2:
return CupertinoTabView( return CupertinoTabView(
defaultTitle: ProfileTab.title, defaultTitle: ProfileTab.title,
builder: (context) => ProfileTab(), builder: (context) => const ProfileTab(),
); );
default: default:
assert(false, 'Unexpected tab'); assert(false, 'Unexpected tab');
@ -161,8 +166,8 @@ class _AndroidDrawer extends StatelessWidget {
title: const Text(NewsTab.title), title: const Text(NewsTab.title),
onTap: () { onTap: () {
Navigator.pop(context); Navigator.pop(context);
Navigator.push<void>( Navigator.push<void>(context,
context, MaterialPageRoute(builder: (context) => NewsTab())); MaterialPageRoute(builder: (context) => const NewsTab()));
}, },
), ),
ListTile( ListTile(
@ -171,7 +176,7 @@ class _AndroidDrawer extends StatelessWidget {
onTap: () { onTap: () {
Navigator.pop(context); Navigator.pop(context);
Navigator.push<void>(context, Navigator.push<void>(context,
MaterialPageRoute(builder: (context) => ProfileTab())); MaterialPageRoute(builder: (context) => const ProfileTab()));
}, },
), ),
// Long drawer contents are often segmented. // Long drawer contents are often segmented.
@ -185,7 +190,7 @@ class _AndroidDrawer extends StatelessWidget {
onTap: () { onTap: () {
Navigator.pop(context); Navigator.pop(context);
Navigator.push<void>(context, Navigator.push<void>(context,
MaterialPageRoute(builder: (context) => SettingsTab())); MaterialPageRoute(builder: (context) => const SettingsTab()));
}, },
), ),
], ],

@ -15,6 +15,8 @@ class NewsTab extends StatefulWidget {
static const androidIcon = Icon(Icons.library_books); static const androidIcon = Icon(Icons.library_books);
static const iosIcon = Icon(CupertinoIcons.news); static const iosIcon = Icon(CupertinoIcons.news);
const NewsTab({Key? key}) : super(key: key);
@override @override
_NewsTabState createState() => _NewsTabState(); _NewsTabState createState() => _NewsTabState();
} }

@ -13,6 +13,8 @@ class ProfileTab extends StatelessWidget {
static const androidIcon = Icon(Icons.person); static const androidIcon = Icon(Icons.person);
static const iosIcon = Icon(CupertinoIcons.profile_circled); static const iosIcon = Icon(CupertinoIcons.profile_circled);
const ProfileTab({Key? key}) : super(key: key);
Widget _buildBody(BuildContext context) { Widget _buildBody(BuildContext context) {
return SafeArea( return SafeArea(
child: Padding( child: Padding(
@ -55,7 +57,7 @@ class ProfileTab extends StatelessWidget {
Expanded( Expanded(
child: Container(), child: Container(),
), ),
LogOutButton(), const LogOutButton(),
], ],
), ),
), ),
@ -89,7 +91,7 @@ class ProfileTab extends StatelessWidget {
CupertinoPageRoute( CupertinoPageRoute(
title: SettingsTab.title, title: SettingsTab.title,
fullscreenDialog: true, fullscreenDialog: true,
builder: (context) => SettingsTab(), builder: (context) => const SettingsTab(),
), ),
); );
}, },
@ -113,7 +115,8 @@ class PreferenceCard extends StatelessWidget {
required this.header, required this.header,
required this.content, required this.content,
required this.preferenceChoices, required this.preferenceChoices,
}); Key? key,
}) : super(key: key);
final String header; final String header;
final String content; final String content;
@ -171,6 +174,8 @@ class LogOutButton extends StatelessWidget {
static const _logoutMessage = Text( static const _logoutMessage = Text(
"You can't actually log out! This is just a demo of how alerts work."); "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 // Non-shared code below because this tab shows different interfaces. On
// Android, it's showing an alert dialog with 2 buttons and on iOS, // Android, it's showing an alert dialog with 2 buttons and on iOS,

@ -12,6 +12,8 @@ class SettingsTab extends StatefulWidget {
static const androidIcon = Icon(Icons.settings); static const androidIcon = Icon(Icons.settings);
static const iosIcon = Icon(CupertinoIcons.gear); static const iosIcon = Icon(CupertinoIcons.gear);
const SettingsTab({Key? key}) : super(key: key);
@override @override
_SettingsTabState createState() => _SettingsTabState(); _SettingsTabState createState() => _SettingsTabState();
} }

@ -16,7 +16,8 @@ class SongDetailTab extends StatelessWidget {
required this.id, required this.id,
required this.song, required this.song,
required this.color, required this.color,
}); Key? key,
}) : super(key: key);
final int id; final int id;
final String song; final String song;
@ -71,7 +72,7 @@ class SongDetailTab extends StatelessWidget {
); );
} }
// Just a bunch of boxes that simulates loading song choices. // Just a bunch of boxes that simulates loading song choices.
return SongPlaceholderTile(); return const SongPlaceholderTile();
}, },
), ),
), ),

@ -41,7 +41,8 @@ class PressableCard extends StatefulWidget {
required this.color, required this.color,
required this.flattenAnimation, required this.flattenAnimation,
this.child, this.child,
}); Key? key,
}) : super(key: key);
final VoidCallback? onPressed; final VoidCallback? onPressed;
final Color color; final Color color;
@ -140,7 +141,8 @@ class HeroAnimatingSongCard extends StatelessWidget {
required this.color, required this.color,
required this.heroAnimation, required this.heroAnimation,
this.onPressed, this.onPressed,
}); Key? key,
}) : super(key: key);
final String song; final String song;
final Color color; 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 /// 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. /// use on both iOS and Android as part of their brand's unique design.
class SongPlaceholderTile extends StatelessWidget { class SongPlaceholderTile extends StatelessWidget {
const SongPlaceholderTile({Key? key}) : super(key: key);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return SizedBox( return SizedBox(

@ -11,7 +11,7 @@ import 'package:platform_design/main.dart';
void main() { void main() {
testWidgets('Can change platform correctly', (tester) async { 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. // The test should be able to find the drawer button.
expect(find.byIcon(Icons.menu), findsOneWidget); expect(find.byIcon(Icons.menu), findsOneWidget);
@ -19,7 +19,7 @@ void main() {
expect(find.byIcon(Icons.refresh), findsOneWidget); expect(find.byIcon(Icons.refresh), findsOneWidget);
debugDefaultTargetPlatformOverride = TargetPlatform.iOS; debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
await tester.pumpWidget(MyAdaptingApp()); await tester.pumpWidget(const MyAdaptingApp());
// There should now be a large title style nav bar. // There should now be a large title style nav bar.
expect(find.byType(CupertinoSliverNavigationBar), findsOneWidget); expect(find.byType(CupertinoSliverNavigationBar), findsOneWidget);

Loading…
Cancel
Save