Unverified Commit 2cdd5190 authored by Michael Thomsen's avatar Michael Thomsen Committed by GitHub

Enable null safety by default in templates (#78619)

parent e9359047
...@@ -38,13 +38,14 @@ void main() { ...@@ -38,13 +38,14 @@ void main() {
run(ui.window.defaultRouteName); run(ui.window.defaultRouteName);
} }
Future<String> run(String name) async { Future<String> run(String? name) async {
// The platform-specific component will call [setInitialRoute] on the Flutter // The platform-specific component will call [setInitialRoute] on the Flutter
// view (or view controller for iOS) to set [ui.window.defaultRouteName]. // view (or view controller for iOS) to set [ui.window.defaultRouteName].
// We then dispatch based on the route names to show different Flutter // We then dispatch based on the route names to show different Flutter
// widgets. // widgets.
// Since we don't really care about Flutter-side navigation in this app, we're // Since we don't really care about Flutter-side navigation in this app, we're
// not using a regular routes map. // not using a regular routes map.
name ??= '';
switch (name) { switch (name) {
case greenMarqueeRouteName: case greenMarqueeRouteName:
runApp(Marquee(color: Colors.green[400])); runApp(Marquee(color: Colors.green[400]));
...@@ -62,7 +63,7 @@ Future<String> run(String name) async { ...@@ -62,7 +63,7 @@ Future<String> run(String name) async {
} }
class FlutterView extends StatelessWidget { class FlutterView extends StatelessWidget {
const FlutterView({@required this.initialRoute}); const FlutterView({required this.initialRoute});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
...@@ -76,7 +77,7 @@ class FlutterView extends StatelessWidget { ...@@ -76,7 +77,7 @@ class FlutterView extends StatelessWidget {
} }
class MyHomePage extends StatefulWidget { class MyHomePage extends StatefulWidget {
const MyHomePage({this.initialRoute}); const MyHomePage({required this.initialRoute});
@override @override
_MyHomePageState createState() => _MyHomePageState(); _MyHomePageState createState() => _MyHomePageState();
...@@ -131,7 +132,7 @@ class _MyHomePageState extends State<MyHomePage> { ...@@ -131,7 +132,7 @@ class _MyHomePageState extends State<MyHomePage> {
/// Callback for messages sent by the platform-specific component. /// Callback for messages sent by the platform-specific component.
/// ///
/// Increments our internal counter. /// Increments our internal counter.
Future<String> _handlePlatformIncrement(String message) async { Future<String> _handlePlatformIncrement(String? message) async {
// Normally we'd dispatch based on the value of [message], but in this // Normally we'd dispatch based on the value of [message], but in this
// sample, there is only one message that is sent to us. // sample, there is only one message that is sent to us.
_incrementCounter(); _incrementCounter();
......
...@@ -7,7 +7,7 @@ import 'package:flutter/animation.dart'; ...@@ -7,7 +7,7 @@ import 'package:flutter/animation.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
class _MarqueeText extends AnimatedWidget { class _MarqueeText extends AnimatedWidget {
const _MarqueeText({Key key, Animation<double> animation}) const _MarqueeText({Key? key, required Animation<double> animation})
: super(key: key, listenable: animation); : super(key: key, listenable: animation);
@override @override
...@@ -26,15 +26,15 @@ class _MarqueeText extends AnimatedWidget { ...@@ -26,15 +26,15 @@ class _MarqueeText extends AnimatedWidget {
class Marquee extends StatefulWidget { class Marquee extends StatefulWidget {
const Marquee({this.color}); const Marquee({this.color});
final Color color; final Color? color;
@override @override
State<StatefulWidget> createState() => MarqueeState(); State<StatefulWidget> createState() => MarqueeState();
} }
class MarqueeState extends State<Marquee> with SingleTickerProviderStateMixin { class MarqueeState extends State<Marquee> with SingleTickerProviderStateMixin {
AnimationController controller; late AnimationController controller;
Animation<double> animation; late Animation<double> animation;
@override @override
void initState() { void initState() {
......
...@@ -242,8 +242,8 @@ class CreateCommand extends CreateBase { ...@@ -242,8 +242,8 @@ class CreateCommand extends CreateBase {
macos: featureFlags.isMacOSEnabled && platforms.contains('macos'), macos: featureFlags.isMacOSEnabled && platforms.contains('macos'),
windows: featureFlags.isWindowsEnabled && platforms.contains('windows'), windows: featureFlags.isWindowsEnabled && platforms.contains('windows'),
windowsUwp: featureFlags.isWindowsUwpEnabled && platforms.contains('winuwp'), windowsUwp: featureFlags.isWindowsUwpEnabled && platforms.contains('winuwp'),
// Enable null-safety for sample code, which is - unlike our regular templates - already migrated. // Enable null safety everywhere.
dartSdkVersionBounds: sampleCode != null ? '">=2.12.0-0 <3.0.0"' : '">=2.7.0 <3.0.0"' dartSdkVersionBounds: '">=2.12.0 <3.0.0"'
); );
final String relativeDirPath = globals.fs.path.relative(projectDirPath); final String relativeDirPath = globals.fs.path.relative(projectDirPath);
...@@ -325,11 +325,6 @@ In order to run your $application, type: ...@@ -325,11 +325,6 @@ In order to run your $application, type:
\$ cd $relativeAppPath \$ cd $relativeAppPath
\$ flutter run \$ flutter run
To enable null safety, type:
\$ cd $relativeAppPath
\$ dart migrate --apply-changes
Your $application code is in $relativeAppMain. Your $application code is in $relativeAppMain.
'''); ''');
// Show warning if any selected platform is not enabled // Show warning if any selected platform is not enabled
......
...@@ -35,7 +35,7 @@ class MyApp extends StatelessWidget { ...@@ -35,7 +35,7 @@ class MyApp extends StatelessWidget {
} }
class MyHomePage extends StatefulWidget { class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key); MyHomePage({Key? key, required this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning // This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect // that it has a State object (defined below) that contains fields that affect
...@@ -138,8 +138,10 @@ class _MyAppState extends State<MyApp> { ...@@ -138,8 +138,10 @@ class _MyAppState extends State<MyApp> {
Future<void> initPlatformState() async { Future<void> initPlatformState() async {
String platformVersion; String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException. // Platform messages may fail, so we use a try/catch PlatformException.
// We also handle the message potentially returning null.
try { try {
platformVersion = await {{pluginDartClass}}.platformVersion; platformVersion =
await {{pluginDartClass}}.platformVersion ?? 'Unknown platform version';
} on PlatformException { } on PlatformException {
platformVersion = 'Failed to get platform version.'; platformVersion = 'Failed to get platform version.';
} }
......
...@@ -40,7 +40,7 @@ void main() { ...@@ -40,7 +40,7 @@ void main() {
expect( expect(
find.byWidgetPredicate( find.byWidgetPredicate(
(Widget widget) => widget is Text && (Widget widget) => widget is Text &&
widget.data.startsWith('Running on:'), widget.data!.startsWith('Running on:'),
), ),
findsOneWidget, findsOneWidget,
); );
......
...@@ -32,7 +32,7 @@ class MyApp extends StatelessWidget { ...@@ -32,7 +32,7 @@ class MyApp extends StatelessWidget {
} }
class MyHomePage extends StatefulWidget { class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key); MyHomePage({Key? key, required this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning // This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect // that it has a State object (defined below) that contains fields that affect
...@@ -135,8 +135,10 @@ class _MyAppState extends State<MyApp> { ...@@ -135,8 +135,10 @@ class _MyAppState extends State<MyApp> {
Future<void> initPlatformState() async { Future<void> initPlatformState() async {
String platformVersion; String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException. // Platform messages may fail, so we use a try/catch PlatformException.
// We also handle the message potentially returning null.
try { try {
platformVersion = await {{pluginDartClass}}.platformVersion; platformVersion =
await {{pluginDartClass}}.platformVersion ?? 'Unknown platform version';
} on PlatformException { } on PlatformException {
platformVersion = 'Failed to get platform version.'; platformVersion = 'Failed to get platform version.';
} }
......
...@@ -40,7 +40,7 @@ void main() { ...@@ -40,7 +40,7 @@ void main() {
expect( expect(
find.byWidgetPredicate( find.byWidgetPredicate(
(Widget widget) => widget is Text && (Widget widget) => widget is Text &&
widget.data.startsWith('Running on:'), widget.data!.startsWith('Running on:'),
), ),
findsOneWidget, findsOneWidget,
); );
......
...@@ -13,8 +13,8 @@ class {{pluginDartClass}} { ...@@ -13,8 +13,8 @@ class {{pluginDartClass}} {
static const MethodChannel _channel = static const MethodChannel _channel =
const MethodChannel('{{projectName}}'); const MethodChannel('{{projectName}}');
static Future<String> get platformVersion async { static Future<String?> get platformVersion async {
final String version = await _channel.invokeMethod('getPlatformVersion'); final String? version = await _channel.invokeMethod('getPlatformVersion');
return version; return version;
} }
} }
...@@ -28,7 +28,6 @@ class {{pluginDartClass}}Web { ...@@ -28,7 +28,6 @@ class {{pluginDartClass}}Web {
switch (call.method) { switch (call.method) {
case 'getPlatformVersion': case 'getPlatformVersion':
return getPlatformVersion(); return getPlatformVersion();
break;
default: default:
throw PlatformException( throw PlatformException(
code: 'Unimplemented', code: 'Unimplemented',
......
...@@ -4,7 +4,7 @@ version: 0.0.1 ...@@ -4,7 +4,7 @@ version: 0.0.1
homepage: homepage:
environment: environment:
sdk: ">=2.7.0 <3.0.0" sdk: {{dartSdkVersionBounds}}
flutter: ">=1.20.0" flutter: ">=1.20.0"
dependencies: dependencies:
......
...@@ -2450,25 +2450,6 @@ void main() { ...@@ -2450,25 +2450,6 @@ void main() {
FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true, isAndroidEnabled: false, isIOSEnabled: false), FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true, isAndroidEnabled: false, isIOSEnabled: false),
Logger: () => logger, Logger: () => logger,
}); });
testUsingContext('flutter create prints note about null safety', () async {
await _createProject(
projectDir,
<String>[],
<String>[],
);
expect(logger.statusText, contains('dart migrate --apply-changes'));
}, overrides: <Type, Generator>{
Pub: () => Pub(
fileSystem: globals.fs,
logger: globals.logger,
processManager: globals.processManager,
usage: globals.flutterUsage,
botDetector: globals.botDetector,
platform: globals.platform,
),
Logger: () => logger,
});
} }
Future<void> _createProject( Future<void> _createProject(
......
...@@ -47,7 +47,7 @@ void main() { ...@@ -47,7 +47,7 @@ void main() {
// We need to add a dependency with web support to trigger // We need to add a dependency with web support to trigger
// the generated_plugin_registrant generation. // the generated_plugin_registrant generation.
await _addDependency(projectDir, 'shared_preferences', await _addDependency(projectDir, 'shared_preferences',
version: '^0.5.12+4'); version: '^2.0.0');
await _analyzeProject(projectDir); await _analyzeProject(projectDir);
expect( expect(
......
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import '../src/common.dart';
import 'test_utils.dart';
void main() {
/// Verifies that `dart migrate` will run successfully on the default `flutter create`
/// template.
group('dart migrate', () {
testWithoutContext('dart migrate succeeds on flutter create template', () async {
Directory tempDir;
try {
tempDir = await _createProject(tempDir);
await _migrate(tempDir);
await _analyze(tempDir);
} finally {
tempDir?.deleteSync(recursive: true);
}
});
/// Verifies that `dart migrate` will run successfully on the module template
/// used by `flutter create --template=module`.
testWithoutContext('dart migrate succeeds on module template', () async {
Directory tempDir;
try {
tempDir = await _createProject(tempDir, <String>['--template=module']);
await _migrate(tempDir);
await _analyze(tempDir);
} finally {
tempDir?.deleteSync(recursive: true);
}
});
/// Verifies that `dart migrate` will run successfully on the module template
/// used by `flutter create --template=plugin`.
testWithoutContext('dart migrate succeeds on plugin template', () async {
Directory tempDir;
try {
tempDir = await _createProject(tempDir, <String>['--template=plugin']);
await _migrate(tempDir);
await _analyze(tempDir);
} finally {
tempDir?.deleteSync(recursive: true);
}
});
/// Verifies that `dart migrate` will run successfully on the module template
/// used by `flutter create --template=package`.
testWithoutContext('dart migrate succeeds on package template', () async {
Directory tempDir;
try {
tempDir = await _createProject(tempDir, <String>['--template=package']);
await _migrate(tempDir);
await _analyze(tempDir);
} finally {
tempDir?.deleteSync(recursive: true);
}
});
}, timeout: const Timeout(Duration(seconds: 90)));
}
Future<Directory> _createProject(Directory tempDir, [List<String> extraAgs]) async {
tempDir = createResolvedTempDirectorySync('dart_migrate_test.');
final ProcessResult createResult = await processManager.run(<String>[
_flutterBin,
'create',
if (extraAgs != null)
...extraAgs,
'foo',
], workingDirectory: tempDir.path);
if (createResult.exitCode != 0) {
fail('flutter create did not work: ${createResult.stdout}${createResult.stderr}');
}
return tempDir;
}
Future<void> _migrate(Directory tempDir) async {
final ProcessResult migrateResult = await processManager.run(<String>[
_dartBin,
'migrate',
'--apply-changes',
], workingDirectory: fileSystem.path.join(tempDir.path, 'foo'));
if (migrateResult.exitCode != 0) {
fail('dart migrate did not work: ${migrateResult.stdout}${migrateResult.stderr}');
}
}
Future<void> _analyze(Directory tempDir) async {
final ProcessResult analyzeResult = await processManager.run(<String>[
_flutterBin,
'analyze',
], workingDirectory: fileSystem.path.join(tempDir.path, 'foo'));
if (analyzeResult.exitCode != 0) {
fail('flutter analyze had errors: ${analyzeResult.stdout}${analyzeResult.stderr}');
}
}
String get _flutterBin => fileSystem.path.join(getFlutterRoot(), 'bin', platform.isWindows ? 'flutter.bat' : 'flutter');
String get _dartBin => fileSystem.path.join(getFlutterRoot(), 'bin', platform.isWindows ? 'dart.bat' : 'dart');
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment