mirror of
https://github.com/flutter/samples.git
synced 2025-11-08 13:58:47 +00:00
Migrate form_app to null safety (#925)
This commit is contained in:
@@ -3,7 +3,6 @@
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import 'src/autofill.dart';
|
||||
import 'src/form_widgets.dart';
|
||||
@@ -11,9 +10,6 @@ import 'src/http/mock_client.dart';
|
||||
import 'src/sign_in_http.dart';
|
||||
import 'src/validation.dart';
|
||||
|
||||
// Set up a mock HTTP client.
|
||||
final http.Client httpClient = MockClient();
|
||||
|
||||
void main() {
|
||||
runApp(const FormApp());
|
||||
}
|
||||
@@ -23,7 +19,8 @@ final demos = [
|
||||
name: 'Sign in with HTTP',
|
||||
route: '/signin_http',
|
||||
builder: (context) => SignInHttpDemo(
|
||||
httpClient: httpClient,
|
||||
// This sample uses a mock HTTP client.
|
||||
httpClient: mockClient,
|
||||
),
|
||||
),
|
||||
Demo(
|
||||
@@ -44,7 +41,7 @@ final demos = [
|
||||
];
|
||||
|
||||
class FormApp extends StatelessWidget {
|
||||
const FormApp({Key key}) : super(key: key);
|
||||
const FormApp({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -58,7 +55,7 @@ class FormApp extends StatelessWidget {
|
||||
}
|
||||
|
||||
class HomePage extends StatelessWidget {
|
||||
const HomePage({Key key}) : super(key: key);
|
||||
const HomePage({Key? key}) : super(key: key);
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@@ -73,16 +70,16 @@ class HomePage extends StatelessWidget {
|
||||
}
|
||||
|
||||
class DemoTile extends StatelessWidget {
|
||||
final Demo demo;
|
||||
final Demo? demo;
|
||||
|
||||
const DemoTile({this.demo, Key key}) : super(key: key);
|
||||
const DemoTile({this.demo, Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListTile(
|
||||
title: Text(demo.name),
|
||||
title: Text(demo!.name),
|
||||
onTap: () {
|
||||
Navigator.pushNamed(context, demo.route);
|
||||
Navigator.pushNamed(context, demo!.route);
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -93,5 +90,5 @@ class Demo {
|
||||
final String route;
|
||||
final WidgetBuilder builder;
|
||||
|
||||
const Demo({this.name, this.route, this.builder});
|
||||
const Demo({required this.name, required this.route, required this.builder});
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import 'package:flutter/material.dart';
|
||||
// Demonstrates how to use autofill hints. The full list of hints is here:
|
||||
// https://github.com/flutter/engine/blob/master/lib/web_ui/lib/src/engine/text_editing/autofill_hint.dart
|
||||
class AutofillDemo extends StatefulWidget {
|
||||
const AutofillDemo({Key key}) : super(key: key);
|
||||
const AutofillDemo({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_AutofillDemoState createState() => _AutofillDemoState();
|
||||
|
||||
@@ -6,7 +6,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart' as intl;
|
||||
|
||||
class FormWidgetsDemo extends StatefulWidget {
|
||||
const FormWidgetsDemo({Key key}) : super(key: key);
|
||||
const FormWidgetsDemo({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_FormWidgetsDemoState createState() => _FormWidgetsDemoState();
|
||||
@@ -18,7 +18,7 @@ class _FormWidgetsDemoState extends State<FormWidgetsDemo> {
|
||||
String description = '';
|
||||
DateTime date = DateTime.now();
|
||||
double maxValue = 0;
|
||||
bool brushedTeeth = false;
|
||||
bool? brushedTeeth = false;
|
||||
bool enableFeature = false;
|
||||
|
||||
@override
|
||||
@@ -159,8 +159,8 @@ class _FormWidgetsDemoState extends State<FormWidgetsDemo> {
|
||||
}
|
||||
|
||||
class _FormDatePicker<T> extends StatefulWidget {
|
||||
final DateTime date;
|
||||
final ValueChanged<T> onChanged;
|
||||
final DateTime? date;
|
||||
final ValueChanged<T>? onChanged;
|
||||
|
||||
const _FormDatePicker({
|
||||
this.date,
|
||||
@@ -187,7 +187,7 @@ class _FormDatePickerState extends State<_FormDatePicker> {
|
||||
style: Theme.of(context).textTheme.bodyText1,
|
||||
),
|
||||
Text(
|
||||
intl.DateFormat.yMd().format(widget.date),
|
||||
intl.DateFormat.yMd().format(widget.date!),
|
||||
style: Theme.of(context).textTheme.subtitle1,
|
||||
),
|
||||
],
|
||||
@@ -197,7 +197,7 @@ class _FormDatePickerState extends State<_FormDatePicker> {
|
||||
onPressed: () async {
|
||||
var newDate = await showDatePicker(
|
||||
context: context,
|
||||
initialDate: widget.date,
|
||||
initialDate: widget.date!,
|
||||
firstDate: DateTime(1900),
|
||||
lastDate: DateTime(2100),
|
||||
);
|
||||
@@ -207,7 +207,7 @@ class _FormDatePickerState extends State<_FormDatePicker> {
|
||||
return;
|
||||
}
|
||||
|
||||
widget.onChanged(newDate);
|
||||
widget.onChanged!(newDate);
|
||||
},
|
||||
)
|
||||
],
|
||||
|
||||
@@ -1,33 +1,18 @@
|
||||
// Copyright 2020, the Flutter project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:mockito/mockito.dart';
|
||||
import 'package:http/testing.dart';
|
||||
|
||||
class MockClient extends Mock implements http.Client {
|
||||
MockClient() {
|
||||
when(post('https://example.com/signin',
|
||||
body: anyNamed('body'), headers: anyNamed('headers')))
|
||||
.thenAnswer((answering) {
|
||||
dynamic body = answering.namedArguments[const Symbol('body')];
|
||||
// Set up a mock HTTP client.
|
||||
final http.Client mockClient = MockClient(_mockHandler);
|
||||
|
||||
if (body != null && body is String) {
|
||||
var decodedJson = Map<String, dynamic>.from(
|
||||
json.decode(body) as Map<String, dynamic>);
|
||||
Future<http.Response> _mockHandler(http.Request request) async {
|
||||
var decodedJson = Map<String, dynamic>.from(
|
||||
json.decode(request.body) as Map<String, dynamic>);
|
||||
|
||||
if (decodedJson['email'] == 'root' &&
|
||||
decodedJson['password'] == 'password') {
|
||||
return Future.value(http.Response('', 200));
|
||||
}
|
||||
}
|
||||
|
||||
return Future.value(http.Response('', 401));
|
||||
});
|
||||
|
||||
when(post('https://example.com/signout'))
|
||||
.thenAnswer((_) => Future.value(http.Response('', 401)));
|
||||
if (decodedJson['email'] == 'root' && decodedJson['password'] == 'password') {
|
||||
return http.Response('', 200);
|
||||
}
|
||||
|
||||
return http.Response('', 401);
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ part 'sign_in_http.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class FormData {
|
||||
String email;
|
||||
String password;
|
||||
String? email;
|
||||
String? password;
|
||||
|
||||
FormData({
|
||||
this.email,
|
||||
@@ -27,11 +27,11 @@ class FormData {
|
||||
}
|
||||
|
||||
class SignInHttpDemo extends StatefulWidget {
|
||||
final http.Client httpClient;
|
||||
final http.Client? httpClient;
|
||||
|
||||
const SignInHttpDemo({
|
||||
this.httpClient,
|
||||
Key key,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@@ -80,8 +80,8 @@ class _SignInHttpDemoState extends State<SignInHttpDemo> {
|
||||
child: const Text('Sign in'),
|
||||
onPressed: () async {
|
||||
// Use a JSON encoded string to send
|
||||
var result = await widget.httpClient.post(
|
||||
'https://example.com/signin',
|
||||
var result = await widget.httpClient!.post(
|
||||
Uri.parse('https://example.com/signin'),
|
||||
body: json.encode(formData.toJson()),
|
||||
headers: {'content-type': 'application/json'});
|
||||
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
// Copyright 2020, the Flutter project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'sign_in_http.dart';
|
||||
@@ -12,8 +8,8 @@ part of 'sign_in_http.dart';
|
||||
|
||||
FormData _$FormDataFromJson(Map<String, dynamic> json) {
|
||||
return FormData(
|
||||
email: json['email'] as String,
|
||||
password: json['password'] as String,
|
||||
email: json['email'] as String?,
|
||||
password: json['password'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import 'package:english_words/english_words.dart' as english_words;
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class FormValidationDemo extends StatefulWidget {
|
||||
const FormValidationDemo({Key key}) : super(key: key);
|
||||
const FormValidationDemo({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
_FormValidationDemoState createState() => _FormValidationDemoState();
|
||||
@@ -14,9 +14,9 @@ class FormValidationDemo extends StatefulWidget {
|
||||
|
||||
class _FormValidationDemoState extends State<FormValidationDemo> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
String adjective;
|
||||
String noun;
|
||||
bool agreedToTerms = false;
|
||||
String? adjective;
|
||||
String? noun;
|
||||
bool? agreedToTerms = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -32,7 +32,7 @@ class _FormValidationDemoState extends State<FormValidationDemo> {
|
||||
onPressed: () {
|
||||
// Validate the form by getting the FormState from the GlobalKey
|
||||
// and calling validate() on it.
|
||||
var valid = _formKey.currentState.validate();
|
||||
var valid = _formKey.currentState!.validate();
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
@@ -69,7 +69,7 @@ class _FormValidationDemoState extends State<FormValidationDemo> {
|
||||
autofocus: true,
|
||||
textInputAction: TextInputAction.next,
|
||||
validator: (value) {
|
||||
if (value.isEmpty) {
|
||||
if (value!.isEmpty) {
|
||||
return 'Please enter an adjective.';
|
||||
}
|
||||
if (english_words.adjectives.contains(value)) {
|
||||
@@ -92,7 +92,7 @@ class _FormValidationDemoState extends State<FormValidationDemo> {
|
||||
// A text field that validates that the text is a noun.
|
||||
TextFormField(
|
||||
validator: (value) {
|
||||
if (value.isEmpty) {
|
||||
if (value!.isEmpty) {
|
||||
return 'Please enter a noun.';
|
||||
}
|
||||
if (english_words.nouns.contains(value)) {
|
||||
@@ -151,7 +151,7 @@ class _FormValidationDemoState extends State<FormValidationDemo> {
|
||||
formFieldState.errorText ?? "",
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.caption
|
||||
.caption!
|
||||
.copyWith(color: Theme.of(context).errorColor),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -234,7 +234,7 @@ packages:
|
||||
name: http
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.12.2"
|
||||
version: "0.13.4"
|
||||
http_multi_server:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -248,7 +248,7 @@ packages:
|
||||
name: http_parser
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.4"
|
||||
version: "4.0.0"
|
||||
intl:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -319,13 +319,6 @@ packages:
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.0"
|
||||
mockito:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: mockito
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "5.0.7"
|
||||
package_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -374,7 +367,7 @@ packages:
|
||||
name: shelf
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.7.9"
|
||||
version: "1.2.0"
|
||||
shelf_web_socket:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -486,4 +479,4 @@ packages:
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
sdks:
|
||||
dart: ">=2.12.0 <3.0.0"
|
||||
dart: ">=2.14.0 <3.0.0"
|
||||
|
||||
@@ -4,15 +4,14 @@ publish_to: "none"
|
||||
version: 1.0.0+1
|
||||
|
||||
environment:
|
||||
sdk: ">=2.10.0 <3.0.0"
|
||||
sdk: '>=2.12.0 <3.0.0'
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
cupertino_icons: ^1.0.0
|
||||
intl: ^0.17.0
|
||||
http: ^0.12.0
|
||||
mockito: ^5.0.0
|
||||
http: ^0.13.0
|
||||
json_annotation: any
|
||||
english_words: ^4.0.0
|
||||
|
||||
|
||||
@@ -6,9 +6,6 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:form_app/src/http/mock_client.dart';
|
||||
import 'package:form_app/src/sign_in_http.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
final http.Client httpClient = MockClient();
|
||||
|
||||
void main() {
|
||||
testWidgets('sign in', (tester) async {
|
||||
@@ -28,7 +25,7 @@ void main() {
|
||||
Future<void> _signIn(WidgetTester tester, String email, String password) async {
|
||||
await tester.pumpWidget(MaterialApp(
|
||||
home: SignInHttpDemo(
|
||||
httpClient: httpClient,
|
||||
httpClient: mockClient,
|
||||
),
|
||||
));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user