1
0
mirror of https://github.com/flutter/samples.git synced 2026-04-05 19:22:08 +00:00

Migrate web dashboard to null safety (#928)

* update dependencies

* Update to cloud_firestore 2.x.x

* run dart migrate

* Fix analyzer warnings from null safety migration

* Fix errors resulting from null safety migration

* Fix info level warnings

* run flutter format

* fix tests

* remove unused import, format
This commit is contained in:
John Ryan
2021-10-12 14:38:34 -07:00
committed by GitHub
parent 0061b0d70d
commit 4893a24625
20 changed files with 277 additions and 301 deletions

View File

@@ -11,12 +11,12 @@ import '../api/api.dart';
/// one.
class CategoryDropdown extends StatefulWidget {
final CategoryApi api;
final ValueChanged<Category> onSelected;
final ValueChanged<Category?> onSelected;
const CategoryDropdown({
@required this.api,
@required this.onSelected,
Key key,
required this.api,
required this.onSelected,
Key? key,
}) : super(key: key);
@override
@@ -24,9 +24,9 @@ class CategoryDropdown extends StatefulWidget {
}
class _CategoryDropdownState extends State<CategoryDropdown> {
Category _selected;
Future<List<Category>> _future;
Stream<List<Category>> _stream;
Category? _selected;
Future<List<Category>>? _future;
Stream<List<Category>>? _stream;
@override
void initState() {
@@ -78,7 +78,7 @@ class _CategoryDropdownState extends State<CategoryDropdown> {
initialData: futureSnapshot.hasData ? futureSnapshot.data : [],
stream: _stream,
builder: (context, snapshot) {
var data = snapshot.hasData ? snapshot.data : <Category>[];
var data = snapshot.hasData ? snapshot.data! : <Category>[];
return DropdownButton<Category>(
value: _selected,
items: data.map(_buildDropdownItem).toList(),
@@ -92,7 +92,7 @@ class _CategoryDropdownState extends State<CategoryDropdown> {
);
}
void _setSelected(Category category) {
void _setSelected(Category? category) {
if (_selected == category) {
return;
}

View File

@@ -15,12 +15,12 @@ const _daysBefore = 10;
class CategoryChart extends StatelessWidget {
final Category category;
final DashboardApi api;
final DashboardApi? api;
const CategoryChart({
@required this.category,
@required this.api,
Key key,
required this.category,
required this.api,
Key? key,
}) : super(key: key);
@override
@@ -51,14 +51,14 @@ class CategoryChart extends StatelessWidget {
// Load the initial snapshot using a FutureBuilder, and subscribe to
// additional updates with a StreamBuilder.
child: FutureBuilder<List<Entry>>(
future: api.entries.list(category.id),
future: api!.entries.list(category.id!),
builder: (context, futureSnapshot) {
if (!futureSnapshot.hasData) {
return _buildLoadingIndicator();
}
return StreamBuilder<List<Entry>>(
initialData: futureSnapshot.data,
stream: api.entries.subscribe(category.id),
stream: api!.entries.subscribe(category.id!),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return _buildLoadingIndicator();
@@ -74,12 +74,14 @@ class CategoryChart extends StatelessWidget {
}
Widget _buildLoadingIndicator() {
return const Center(child: CircularProgressIndicator());
return const Center(
child: CircularProgressIndicator(),
);
}
}
class _BarChart extends StatelessWidget {
final List<Entry> entries;
final List<Entry>? entries;
const _BarChart({this.entries});
@@ -96,14 +98,10 @@ class _BarChart extends StatelessWidget {
id: 'Entries',
colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault,
domainFn: (entryTotal, _) {
if (entryTotal == null) return null;
var format = intl.DateFormat.Md();
return format.format(entryTotal.day);
},
measureFn: (total, _) {
if (total == null) return null;
return total.value;
},
data: utils.entryTotalsByDay(entries, _daysBefore),

View File

@@ -8,7 +8,7 @@ import 'package:web_dashboard/src/api/api.dart';
import 'package:web_dashboard/src/app.dart';
class NewCategoryForm extends StatefulWidget {
const NewCategoryForm({Key key}) : super(key: key);
const NewCategoryForm({Key? key}) : super(key: key);
@override
_NewCategoryFormState createState() => _NewCategoryFormState();
@@ -24,7 +24,7 @@ class _NewCategoryFormState extends State<NewCategoryForm> {
category: _category,
onDone: (shouldInsert) {
if (shouldInsert) {
api.categories.insert(_category);
api!.categories.insert(_category);
}
Navigator.of(context).pop();
},
@@ -37,9 +37,9 @@ class EditCategoryForm extends StatefulWidget {
final ValueChanged<bool> onDone;
const EditCategoryForm({
@required this.category,
@required this.onDone,
Key key,
required this.category,
required this.onDone,
Key? key,
}) : super(key: key);
@override
@@ -67,7 +67,7 @@ class _EditCategoryFormState extends State<EditCategoryForm> {
widget.category.name = newValue;
},
validator: (value) {
if (value.isEmpty) {
if (value!.isEmpty) {
return 'Please enter a name';
}
return null;
@@ -91,7 +91,7 @@ class _EditCategoryFormState extends State<EditCategoryForm> {
child: ElevatedButton(
child: const Text('OK'),
onPressed: () {
if (_formKey.currentState.validate()) {
if (_formKey.currentState!.validate()) {
widget.onDone(true);
}
},

View File

@@ -11,7 +11,7 @@ import '../app.dart';
import 'edit_entry.dart';
class NewCategoryDialog extends StatelessWidget {
const NewCategoryDialog({Key key}) : super(key: key);
const NewCategoryDialog({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
@@ -28,8 +28,8 @@ class EditCategoryDialog extends StatelessWidget {
final Category category;
const EditCategoryDialog({
@required this.category,
Key key,
required this.category,
Key? key,
}) : super(key: key);
@override
@@ -43,7 +43,7 @@ class EditCategoryDialog extends StatelessWidget {
category: category,
onDone: (shouldUpdate) {
if (shouldUpdate) {
api.categories.update(category, category.id);
api!.categories.update(category, category.id!);
}
Navigator.of(context).pop();
},
@@ -54,7 +54,7 @@ class EditCategoryDialog extends StatelessWidget {
}
class NewEntryDialog extends StatefulWidget {
const NewEntryDialog({Key key}) : super(key: key);
const NewEntryDialog({Key? key}) : super(key: key);
@override
_NewEntryDialogState createState() => _NewEntryDialogState();
@@ -73,13 +73,13 @@ class _NewEntryDialogState extends State<NewEntryDialog> {
}
class EditEntryDialog extends StatelessWidget {
final Category category;
final Entry entry;
final Category? category;
final Entry? entry;
const EditEntryDialog({
this.category,
this.entry,
Key key,
Key? key,
}) : super(key: key);
@override
@@ -93,7 +93,7 @@ class EditEntryDialog extends StatelessWidget {
entry: entry,
onDone: (shouldUpdate) {
if (shouldUpdate) {
api.entries.update(category.id, entry.id, entry);
api!.entries.update(category!.id!, entry!.id!, entry!);
}
Navigator.of(context).pop();
},

View File

@@ -11,19 +11,19 @@ import '../app.dart';
import 'categories_dropdown.dart';
class NewEntryForm extends StatefulWidget {
const NewEntryForm({Key key}) : super(key: key);
const NewEntryForm({Key? key}) : super(key: key);
@override
_NewEntryFormState createState() => _NewEntryFormState();
}
class _NewEntryFormState extends State<NewEntryForm> {
Category _selected;
late Category _selected;
final Entry _entry = Entry(0, DateTime.now());
@override
Widget build(BuildContext context) {
var api = Provider.of<AppState>(context).api;
var api = Provider.of<AppState>(context).api!;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -33,6 +33,7 @@ class _NewEntryFormState extends State<NewEntryForm> {
child: CategoryDropdown(
api: api.categories,
onSelected: (category) {
if (category == null) return;
setState(() {
_selected = category;
});
@@ -43,7 +44,7 @@ class _NewEntryFormState extends State<NewEntryForm> {
entry: _entry,
onDone: (shouldInsert) {
if (shouldInsert) {
api.entries.insert(_selected.id, _entry);
api.entries.insert(_selected.id!, _entry);
}
Navigator.of(context).pop();
},
@@ -54,13 +55,13 @@ class _NewEntryFormState extends State<NewEntryForm> {
}
class EditEntryForm extends StatefulWidget {
final Entry entry;
final Entry? entry;
final ValueChanged<bool> onDone;
const EditEntryForm({
@required this.entry,
@required this.onDone,
Key key,
required this.entry,
required this.onDone,
Key? key,
}) : super(key: key);
@override
@@ -80,19 +81,19 @@ class _EditEntryFormState extends State<EditEntryForm> {
Padding(
padding: const EdgeInsets.all(8),
child: TextFormField(
initialValue: widget.entry.value.toString(),
initialValue: widget.entry!.value.toString(),
decoration: const InputDecoration(labelText: 'Value'),
keyboardType: TextInputType.number,
validator: (value) {
try {
int.parse(value);
int.parse(value!);
} catch (e) {
return "Please enter a whole number";
}
return null;
},
onChanged: (newValue) {
widget.entry.value = int.parse(newValue);
widget.entry!.value = int.parse(newValue);
},
),
),
@@ -101,13 +102,13 @@ class _EditEntryFormState extends State<EditEntryForm> {
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(intl.DateFormat('MM/dd/yyyy').format(widget.entry.time)),
Text(intl.DateFormat('MM/dd/yyyy').format(widget.entry!.time)),
ElevatedButton(
child: const Text('Edit'),
onPressed: () async {
var result = await showDatePicker(
context: context,
initialDate: widget.entry.time,
initialDate: widget.entry!.time,
firstDate:
DateTime.now().subtract(const Duration(days: 365)),
lastDate: DateTime.now());
@@ -115,7 +116,7 @@ class _EditEntryFormState extends State<EditEntryForm> {
return;
}
setState(() {
widget.entry.time = result;
widget.entry!.time = result;
});
},
)
@@ -139,7 +140,7 @@ class _EditEntryFormState extends State<EditEntryForm> {
child: ElevatedButton(
child: const Text('OK'),
onPressed: () {
if (_formKey.currentState.validate()) {
if (_formKey.currentState!.validate()) {
widget.onDone(true);
}
},

View File

@@ -18,8 +18,8 @@ class AdaptiveScaffoldDestination {
final IconData icon;
const AdaptiveScaffoldDestination({
@required this.title,
@required this.icon,
required this.title,
required this.icon,
});
}
@@ -27,23 +27,23 @@ class AdaptiveScaffoldDestination {
/// [NavigationRail], or [BottomNavigationBar]. Navigation destinations are
/// defined in the [destinations] parameter.
class AdaptiveScaffold extends StatefulWidget {
final Widget title;
final Widget? title;
final List<Widget> actions;
final Widget body;
final Widget? body;
final int currentIndex;
final List<AdaptiveScaffoldDestination> destinations;
final ValueChanged<int> onNavigationIndexChange;
final FloatingActionButton floatingActionButton;
final ValueChanged<int>? onNavigationIndexChange;
final FloatingActionButton? floatingActionButton;
const AdaptiveScaffold({
this.title,
this.body,
this.actions = const [],
@required this.currentIndex,
@required this.destinations,
required this.currentIndex,
required this.destinations,
this.onNavigationIndexChange,
this.floatingActionButton,
Key key,
Key? key,
}) : super(key: key);
@override
@@ -122,7 +122,7 @@ class _AdaptiveScaffoldState extends State<AdaptiveScaffold> {
color: Colors.grey[300],
),
Expanded(
child: widget.body,
child: widget.body!,
),
],
),
@@ -155,7 +155,7 @@ class _AdaptiveScaffoldState extends State<AdaptiveScaffold> {
void _destinationTapped(AdaptiveScaffoldDestination destination) {
var idx = widget.destinations.indexOf(destination);
if (idx != widget.currentIndex) {
widget.onNavigationIndexChange(idx);
widget.onNavigationIndexChange!(idx);
}
}
}