From 4893a24625398bac2e701ada62e7f516057d1207 Mon Sep 17 00:00:00 2001 From: John Ryan Date: Tue, 12 Oct 2021 14:38:34 -0700 Subject: [PATCH] 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 --- .../web_dashboard/lib/src/api/api.dart | 12 +- .../web_dashboard/lib/src/api/firebase.dart | 72 ++++---- .../web_dashboard/lib/src/api/mock.dart | 21 ++- experimental/web_dashboard/lib/src/app.dart | 22 +-- .../web_dashboard/lib/src/auth/firebase.dart | 10 +- .../web_dashboard/lib/src/auth/mock.dart | 7 - .../lib/src/pages/dashboard.dart | 12 +- .../web_dashboard/lib/src/pages/entries.dart | 44 ++--- .../web_dashboard/lib/src/pages/home.dart | 12 +- .../web_dashboard/lib/src/pages/sign_in.dart | 14 +- .../lib/src/utils/chart_utils.dart | 12 +- .../lib/src/widgets/categories_dropdown.dart | 18 +- .../lib/src/widgets/category_chart.dart | 22 ++- .../lib/src/widgets/category_forms.dart | 14 +- .../lib/src/widgets/dialogs.dart | 18 +- .../lib/src/widgets/edit_entry.dart | 31 ++-- .../third_party/adaptive_scaffold.dart | 22 +-- experimental/web_dashboard/pubspec.lock | 154 +++++++----------- experimental/web_dashboard/pubspec.yaml | 25 +-- .../web_dashboard/test/mock_service_test.dart | 36 ++-- 20 files changed, 277 insertions(+), 301 deletions(-) diff --git a/experimental/web_dashboard/lib/src/api/api.dart b/experimental/web_dashboard/lib/src/api/api.dart index 4445178b5..0bc43cc5b 100644 --- a/experimental/web_dashboard/lib/src/api/api.dart +++ b/experimental/web_dashboard/lib/src/api/api.dart @@ -15,9 +15,9 @@ abstract class DashboardApi { /// Manipulates [Category] data. abstract class CategoryApi { - Future delete(String id); + Future delete(String id); - Future get(String id); + Future get(String id); Future insert(Category category); @@ -30,9 +30,9 @@ abstract class CategoryApi { /// Manipulates [Entry] data. abstract class EntryApi { - Future delete(String categoryId, String id); + Future delete(String categoryId, String id); - Future get(String categoryId, String id); + Future get(String categoryId, String id); Future insert(String categoryId, Entry entry); @@ -49,7 +49,7 @@ class Category { String name; @JsonKey(ignore: true) - String id; + String? id; Category(this.name); @@ -76,7 +76,7 @@ class Entry { DateTime time; @JsonKey(ignore: true) - String id; + String? id; Entry(this.value, this.time); diff --git a/experimental/web_dashboard/lib/src/api/firebase.dart b/experimental/web_dashboard/lib/src/api/firebase.dart index 443e39f23..c332c947c 100644 --- a/experimental/web_dashboard/lib/src/api/firebase.dart +++ b/experimental/web_dashboard/lib/src/api/firebase.dart @@ -13,15 +13,15 @@ class FirebaseDashboardApi implements DashboardApi { @override final CategoryApi categories; - FirebaseDashboardApi(Firestore firestore, String userId) + FirebaseDashboardApi(FirebaseFirestore firestore, String userId) : entries = FirebaseEntryApi(firestore, userId), categories = FirebaseCategoryApi(firestore, userId); } class FirebaseEntryApi implements EntryApi { - final Firestore firestore; + final FirebaseFirestore firestore; final String userId; - final CollectionReference _categoriesRef; + final CollectionReference> _categoriesRef; FirebaseEntryApi(this.firestore, this.userId) : _categoriesRef = firestore.collection('users/$userId/categories'); @@ -29,10 +29,10 @@ class FirebaseEntryApi implements EntryApi { @override Stream> subscribe(String categoryId) { var snapshots = - _categoriesRef.document(categoryId).collection('entries').snapshots(); - var result = snapshots.map((querySnapshot) { - return querySnapshot.documents.map((snapshot) { - return Entry.fromJson(snapshot.data)..id = snapshot.documentID; + _categoriesRef.doc(categoryId).collection('entries').snapshots(); + var result = snapshots.map>((querySnapshot) { + return querySnapshot.docs.map((snapshot) { + return Entry.fromJson(snapshot.data())..id = snapshot.id; }).toList(); }); @@ -41,8 +41,8 @@ class FirebaseEntryApi implements EntryApi { @override Future delete(String categoryId, String id) async { - var document = _categoriesRef.document('$categoryId/entries/$id'); - var entry = await get(categoryId, document.documentID); + var document = _categoriesRef.doc('$categoryId/entries/$id'); + var entry = await get(categoryId, document.id); await document.delete(); @@ -52,18 +52,18 @@ class FirebaseEntryApi implements EntryApi { @override Future insert(String categoryId, Entry entry) async { var document = await _categoriesRef - .document(categoryId) + .doc(categoryId) .collection('entries') .add(entry.toJson()); - return await get(categoryId, document.documentID); + return await get(categoryId, document.id); } @override Future> list(String categoryId) async { - var entriesRef = _categoriesRef.document(categoryId).collection('entries'); - var querySnapshot = await entriesRef.getDocuments(); - var entries = querySnapshot.documents - .map((doc) => Entry.fromJson(doc.data)..id = doc.documentID) + var entriesRef = _categoriesRef.doc(categoryId).collection('entries'); + var querySnapshot = await entriesRef.get(); + var entries = querySnapshot.docs + .map((doc) => Entry.fromJson(doc.data())..id = doc.id) .toList(); return entries; @@ -71,24 +71,24 @@ class FirebaseEntryApi implements EntryApi { @override Future update(String categoryId, String id, Entry entry) async { - var document = _categoriesRef.document('$categoryId/entries/$id'); - await document.setData(entry.toJson()); + var document = _categoriesRef.doc('$categoryId/entries/$id'); + await document.update(entry.toJson()); var snapshot = await document.get(); - return Entry.fromJson(snapshot.data)..id = snapshot.documentID; + return Entry.fromJson(snapshot.data()!)..id = snapshot.id; } @override Future get(String categoryId, String id) async { - var document = _categoriesRef.document('$categoryId/entries/$id'); + var document = _categoriesRef.doc('$categoryId/entries/$id'); var snapshot = await document.get(); - return Entry.fromJson(snapshot.data)..id = snapshot.documentID; + return Entry.fromJson(snapshot.data()!)..id = snapshot.id; } } class FirebaseCategoryApi implements CategoryApi { - final Firestore firestore; + final FirebaseFirestore firestore; final String userId; - final CollectionReference _categoriesRef; + final CollectionReference> _categoriesRef; FirebaseCategoryApi(this.firestore, this.userId) : _categoriesRef = firestore.collection('users/$userId/categories'); @@ -96,9 +96,9 @@ class FirebaseCategoryApi implements CategoryApi { @override Stream> subscribe() { var snapshots = _categoriesRef.snapshots(); - var result = snapshots.map((querySnapshot) { - return querySnapshot.documents.map((snapshot) { - return Category.fromJson(snapshot.data)..id = snapshot.documentID; + var result = snapshots.map>((querySnapshot) { + return querySnapshot.docs.map((snapshot) { + return Category.fromJson(snapshot.data())..id = snapshot.id; }).toList(); }); @@ -107,8 +107,8 @@ class FirebaseCategoryApi implements CategoryApi { @override Future delete(String id) async { - var document = _categoriesRef.document(id); - var categories = await get(document.documentID); + var document = _categoriesRef.doc(id); + var categories = await get(document.id); await document.delete(); @@ -117,22 +117,22 @@ class FirebaseCategoryApi implements CategoryApi { @override Future get(String id) async { - var document = _categoriesRef.document(id); + var document = _categoriesRef.doc(id); var snapshot = await document.get(); - return Category.fromJson(snapshot.data)..id = snapshot.documentID; + return Category.fromJson(snapshot.data()!)..id = snapshot.id; } @override Future insert(Category category) async { var document = await _categoriesRef.add(category.toJson()); - return await get(document.documentID); + return await get(document.id); } @override Future> list() async { - var querySnapshot = await _categoriesRef.getDocuments(); - var categories = querySnapshot.documents - .map((doc) => Category.fromJson(doc.data)..id = doc.documentID) + var querySnapshot = await _categoriesRef.get(); + var categories = querySnapshot.docs + .map((doc) => Category.fromJson(doc.data())..id = doc.id) .toList(); return categories; @@ -140,9 +140,9 @@ class FirebaseCategoryApi implements CategoryApi { @override Future update(Category category, String id) async { - var document = _categoriesRef.document(id); - await document.setData(category.toJson()); + var document = _categoriesRef.doc(id); + await document.update(category.toJson()); var snapshot = await document.get(); - return Category.fromJson(snapshot.data)..id = snapshot.documentID; + return Category.fromJson(snapshot.data()!)..id = snapshot.id; } } diff --git a/experimental/web_dashboard/lib/src/api/mock.dart b/experimental/web_dashboard/lib/src/api/mock.dart index 6303e2d25..17458dd9a 100644 --- a/experimental/web_dashboard/lib/src/api/mock.dart +++ b/experimental/web_dashboard/lib/src/api/mock.dart @@ -5,6 +5,7 @@ import 'dart:async'; import 'dart:math'; +import 'package:collection/collection.dart'; import 'package:uuid/uuid.dart' as uuid; import 'api.dart'; @@ -30,7 +31,7 @@ class MockDashboardApi implements DashboardApi { for (var i = 0; i < 30; i++) { var date = monthAgo.add(Duration(days: i)); var value = Random().nextInt(6) + 1; - await entries.insert(category.id, Entry(value, date)); + await entries.insert(category.id!, Entry(value, date)); } } } @@ -42,20 +43,20 @@ class MockCategoryApi implements CategoryApi { StreamController>.broadcast(); @override - Future delete(String id) async { + Future delete(String id) async { var removed = _storage.remove(id); _emit(); return removed; } @override - Future get(String id) async { + Future get(String id) async { return _storage[id]; } @override Future insert(Category category) async { - var id = uuid.Uuid().v4(); + var id = const uuid.Uuid().v4(); var newCategory = Category(category.name)..id = id; _storage[id] = newCategory; _emit(); @@ -88,14 +89,14 @@ class MockEntryApi implements EntryApi { StreamController.broadcast(); @override - Future delete(String categoryId, String id) async { + Future delete(String categoryId, String id) async { _emit(categoryId); return _storage.remove('$categoryId-$id'); } @override Future insert(String categoryId, Entry entry) async { - var id = uuid.Uuid().v4(); + var id = const uuid.Uuid().v4(); var newEntry = Entry(entry.value, entry.time)..id = id; _storage['$categoryId-$id'] = newEntry; _emit(categoryId); @@ -104,10 +105,12 @@ class MockEntryApi implements EntryApi { @override Future> list(String categoryId) async { - return _storage.keys + var list = _storage.keys .where((k) => k.startsWith(categoryId)) .map((k) => _storage[k]) + .whereNotNull() .toList(); + return list; } @override @@ -127,14 +130,14 @@ class MockEntryApi implements EntryApi { void _emit(String categoryId) { var entries = _storage.keys .where((k) => k.startsWith(categoryId)) - .map((k) => _storage[k]) + .map((k) => _storage[k]!) .toList(); _streamController.add(_EntriesEvent(categoryId, entries)); } @override - Future get(String categoryId, String id) async { + Future get(String categoryId, String id) async { return _storage['$categoryId-$id']; } } diff --git a/experimental/web_dashboard/lib/src/app.dart b/experimental/web_dashboard/lib/src/app.dart index 07077e260..6a4b3eed5 100644 --- a/experimental/web_dashboard/lib/src/app.dart +++ b/experimental/web_dashboard/lib/src/app.dart @@ -18,7 +18,7 @@ import 'pages/sign_in.dart'; /// The global state the app. class AppState { final Auth auth; - DashboardApi api; + DashboardApi? api; AppState(this.auth); } @@ -33,19 +33,19 @@ class DashboardApp extends StatefulWidget { static DashboardApi _mockApiBuilder(User user) => MockDashboardApi()..fillWithMockData(); static DashboardApi _apiBuilder(User user) => - FirebaseDashboardApi(Firestore.instance, user.uid); + FirebaseDashboardApi(FirebaseFirestore.instance, user.uid); final Auth auth; final ApiBuilder apiBuilder; /// Runs the app using Firebase - DashboardApp.firebase({Key key}) + DashboardApp.firebase({Key? key}) : auth = FirebaseAuthService(), apiBuilder = _apiBuilder, super(key: key); /// Runs the app using mock data - DashboardApp.mock({Key key}) + DashboardApp.mock({Key? key}) : auth = MockAuthService(), apiBuilder = _mockApiBuilder, super(key: key); @@ -55,7 +55,7 @@ class DashboardApp extends StatefulWidget { } class _DashboardAppState extends State { - AppState _appState; + late final AppState _appState; @override void initState() { @@ -80,13 +80,13 @@ class _DashboardAppState extends State { /// Switches between showing the [SignInPage] or [HomePage], depending on /// whether or not the user is signed in. class SignInSwitcher extends StatefulWidget { - final AppState appState; - final ApiBuilder apiBuilder; + final AppState? appState; + final ApiBuilder? apiBuilder; const SignInSwitcher({ this.appState, this.apiBuilder, - Key key, + Key? key, }) : super(key: key); @override @@ -107,14 +107,14 @@ class _SignInSwitcherState extends State { onSignOut: _handleSignOut, ) : SignInPage( - auth: widget.appState.auth, + auth: widget.appState!.auth, onSuccess: _handleSignIn, ), ); } void _handleSignIn(User user) { - widget.appState.api = widget.apiBuilder(user); + widget.appState!.api = widget.apiBuilder!(user); setState(() { _isSignedIn = true; @@ -122,7 +122,7 @@ class _SignInSwitcherState extends State { } Future _handleSignOut() async { - await widget.appState.auth.signOut(); + await widget.appState!.auth.signOut(); setState(() { _isSignedIn = false; }); diff --git a/experimental/web_dashboard/lib/src/auth/firebase.dart b/experimental/web_dashboard/lib/src/auth/firebase.dart index d2c602fcf..fc3ceb2e3 100644 --- a/experimental/web_dashboard/lib/src/auth/firebase.dart +++ b/experimental/web_dashboard/lib/src/auth/firebase.dart @@ -2,7 +2,7 @@ // 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 'package:firebase_auth/firebase_auth.dart' hide FirebaseUser; +import 'package:firebase_auth/firebase_auth.dart' hide User; import 'package:flutter/services.dart'; import 'package:google_sign_in/google_sign_in.dart'; @@ -25,21 +25,21 @@ class FirebaseAuthService implements Auth { } Future _signIn() async { - GoogleSignInAccount googleUser; + GoogleSignInAccount? googleUser; if (await isSignedIn) { googleUser = await _googleSignIn.signInSilently(); } else { googleUser = await _googleSignIn.signIn(); } - var googleAuth = await googleUser.authentication; + var googleAuth = await googleUser!.authentication; - var credential = GoogleAuthProvider.getCredential( + var credential = GoogleAuthProvider.credential( accessToken: googleAuth.accessToken, idToken: googleAuth.idToken); var authResult = await _auth.signInWithCredential(credential); - return _FirebaseUser(authResult.user.uid); + return _FirebaseUser(authResult.user!.uid); } @override diff --git a/experimental/web_dashboard/lib/src/auth/mock.dart b/experimental/web_dashboard/lib/src/auth/mock.dart index e5cfb500b..e54d51831 100644 --- a/experimental/web_dashboard/lib/src/auth/mock.dart +++ b/experimental/web_dashboard/lib/src/auth/mock.dart @@ -2,8 +2,6 @@ // 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:math'; - import 'auth.dart'; class MockAuthService implements Auth { @@ -12,11 +10,6 @@ class MockAuthService implements Auth { @override Future signIn() async { - // Sign in will randomly fail 25% of the time. - var random = Random(); - if (random.nextInt(4) == 0) { - throw SignInException(); - } return MockUser(); } diff --git a/experimental/web_dashboard/lib/src/pages/dashboard.dart b/experimental/web_dashboard/lib/src/pages/dashboard.dart index 109794adf..6b7a1f6df 100644 --- a/experimental/web_dashboard/lib/src/pages/dashboard.dart +++ b/experimental/web_dashboard/lib/src/pages/dashboard.dart @@ -10,13 +10,13 @@ import '../app.dart'; import '../widgets/category_chart.dart'; class DashboardPage extends StatelessWidget { - const DashboardPage({Key key}) : super(key: key); + const DashboardPage({Key? key}) : super(key: key); @override Widget build(BuildContext context) { var appState = Provider.of(context); return FutureBuilder>( - future: appState.api.categories.list(), + future: appState.api!.categories.list(), builder: (context, futureSnapshot) { if (!futureSnapshot.hasData) { return const Center( @@ -25,7 +25,7 @@ class DashboardPage extends StatelessWidget { } return StreamBuilder>( initialData: futureSnapshot.data, - stream: appState.api.categories.subscribe(), + stream: appState.api!.categories.subscribe(), builder: (context, snapshot) { if (snapshot.data == null) { return const Center( @@ -41,9 +41,9 @@ class DashboardPage extends StatelessWidget { } class Dashboard extends StatelessWidget { - final List categories; + final List? categories; - const Dashboard(this.categories, {Key key}) : super(key: key); + const Dashboard(this.categories, {Key? key}) : super(key: key); @override Widget build(BuildContext context) { @@ -55,7 +55,7 @@ class Dashboard extends StatelessWidget { maxCrossAxisExtent: 500, ), children: [ - ...categories.map( + ...categories!.map( (category) => Card( child: CategoryChart( category: category, diff --git a/experimental/web_dashboard/lib/src/pages/entries.dart b/experimental/web_dashboard/lib/src/pages/entries.dart index edcf70841..7a0350eb2 100644 --- a/experimental/web_dashboard/lib/src/pages/entries.dart +++ b/experimental/web_dashboard/lib/src/pages/entries.dart @@ -2,6 +2,8 @@ // 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:async'; + import 'package:flutter/material.dart'; import 'package:intl/intl.dart' as intl; import 'package:provider/provider.dart'; @@ -12,14 +14,14 @@ import '../widgets/categories_dropdown.dart'; import '../widgets/dialogs.dart'; class EntriesPage extends StatefulWidget { - const EntriesPage({Key key}) : super(key: key); + const EntriesPage({Key? key}) : super(key: key); @override _EntriesPageState createState() => _EntriesPageState(); } class _EntriesPageState extends State { - Category _selected; + Category? _selected; @override Widget build(BuildContext context) { @@ -27,14 +29,14 @@ class _EntriesPageState extends State { return Column( children: [ CategoryDropdown( - api: appState.api.categories, + api: appState.api!.categories, onSelected: (category) => setState(() => _selected = category)), Expanded( child: _selected == null ? const Center(child: CircularProgressIndicator()) : EntriesList( category: _selected, - api: appState.api.entries, + api: appState.api!.entries, ), ), ], @@ -43,13 +45,13 @@ class _EntriesPageState extends State { } class EntriesList extends StatefulWidget { - final Category category; + final Category? category; final EntryApi api; EntriesList({ - @required this.category, - @required this.api, - }) : super(key: ValueKey(category.id)); + this.category, + required this.api, + }) : super(key: ValueKey(category?.id)); @override _EntriesListState createState() => _EntriesListState(); @@ -63,14 +65,14 @@ class _EntriesListState extends State { } return FutureBuilder>( - future: widget.api.list(widget.category.id), + future: widget.api.list(widget.category!.id!), builder: (context, futureSnapshot) { if (!futureSnapshot.hasData) { return _buildLoadingIndicator(); } return StreamBuilder>( initialData: futureSnapshot.data, - stream: widget.api.subscribe(widget.category.id), + stream: widget.api.subscribe(widget.category!.id!), builder: (context, snapshot) { if (!snapshot.hasData) { return _buildLoadingIndicator(); @@ -79,10 +81,10 @@ class _EntriesListState extends State { itemBuilder: (context, index) { return EntryTile( category: widget.category, - entry: snapshot.data[index], + entry: snapshot.data![index], ); }, - itemCount: snapshot.data.length, + itemCount: snapshot.data!.length, ); }, ); @@ -96,20 +98,20 @@ class _EntriesListState extends State { } class EntryTile extends StatelessWidget { - final Category category; - final Entry entry; + final Category? category; + final Entry? entry; const EntryTile({ this.category, this.entry, - Key key, + Key? key, }) : super(key: key); @override Widget build(BuildContext context) { return ListTile( - title: Text(entry.value.toString()), - subtitle: Text(intl.DateFormat('MM/dd/yy h:mm a').format(entry.time)), + title: Text(entry!.value.toString()), + subtitle: Text(intl.DateFormat('MM/dd/yy h:mm a').format(entry!.time)), trailing: Row( mainAxisSize: MainAxisSize.min, children: [ @@ -127,7 +129,7 @@ class EntryTile extends StatelessWidget { TextButton( child: const Text('Delete'), onPressed: () async { - var shouldDelete = await showDialog( + var shouldDelete = await (showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Delete entry?'), @@ -142,12 +144,12 @@ class EntryTile extends StatelessWidget { ), ], ), - ); + ) as FutureOr); if (shouldDelete) { await Provider.of(context, listen: false) - .api + .api! .entries - .delete(category.id, entry.id); + .delete(category!.id!, entry!.id!); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( diff --git a/experimental/web_dashboard/lib/src/pages/home.dart b/experimental/web_dashboard/lib/src/pages/home.dart index 8aa9b64d5..0d6ca7e24 100644 --- a/experimental/web_dashboard/lib/src/pages/home.dart +++ b/experimental/web_dashboard/lib/src/pages/home.dart @@ -2,6 +2,8 @@ // 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:async'; + import 'package:flutter/material.dart'; import '../widgets/dialogs.dart'; @@ -13,8 +15,8 @@ class HomePage extends StatefulWidget { final VoidCallback onSignOut; const HomePage({ - @required this.onSignOut, - Key key, + required this.onSignOut, + Key? key, }) : super(key: key); @override @@ -86,7 +88,7 @@ class _HomePageState extends State { } Future _handleSignOut() async { - var shouldSignOut = await showDialog( + var shouldSignOut = await (showDialog( context: context, builder: (context) => AlertDialog( title: const Text('Are you sure you want to sign out?'), @@ -105,9 +107,9 @@ class _HomePageState extends State { ), ], ), - ); + )); - if (!shouldSignOut) { + if (shouldSignOut == null || !shouldSignOut) { return; } diff --git a/experimental/web_dashboard/lib/src/pages/sign_in.dart b/experimental/web_dashboard/lib/src/pages/sign_in.dart index 6ec7a635d..447c9b50e 100644 --- a/experimental/web_dashboard/lib/src/pages/sign_in.dart +++ b/experimental/web_dashboard/lib/src/pages/sign_in.dart @@ -11,9 +11,9 @@ class SignInPage extends StatelessWidget { final ValueChanged onSuccess; const SignInPage({ - @required this.auth, - @required this.onSuccess, - Key key, + required this.auth, + required this.onSuccess, + Key? key, }) : super(key: key); @override @@ -31,9 +31,9 @@ class SignInButton extends StatefulWidget { final ValueChanged onSuccess; const SignInButton({ - @required this.auth, - @required this.onSuccess, - Key key, + required this.auth, + required this.onSuccess, + Key? key, }) : super(key: key); @override @@ -41,7 +41,7 @@ class SignInButton extends StatefulWidget { } class _SignInButtonState extends State { - Future _checkSignInFuture; + Future? _checkSignInFuture; @override void initState() { diff --git a/experimental/web_dashboard/lib/src/utils/chart_utils.dart b/experimental/web_dashboard/lib/src/utils/chart_utils.dart index 11d76cc09..4345eec04 100644 --- a/experimental/web_dashboard/lib/src/utils/chart_utils.dart +++ b/experimental/web_dashboard/lib/src/utils/chart_utils.dart @@ -15,14 +15,14 @@ class EntryTotal { /// Returns a list of [EntryTotal] objects. Each [EntryTotal] is the sum of /// the values of all the entries on a given day. -List entryTotalsByDay(List entries, int daysAgo, - {DateTime today}) { +List entryTotalsByDay(List? entries, int daysAgo, + {DateTime? today}) { today ??= DateTime.now(); return _entryTotalsByDay(entries, daysAgo, today).toList(); } Iterable _entryTotalsByDay( - List entries, int daysAgo, DateTime today) sync* { + List? entries, int daysAgo, DateTime today) sync* { var start = today.subtract(Duration(days: daysAgo)); var entriesByDay = _entriesInRange(start, today, entries); @@ -42,18 +42,18 @@ Iterable _entryTotalsByDay( /// lists. The outer list represents the number of days since [start], and the /// inner list is the group of entries on that day. List> _entriesInRange( - DateTime start, DateTime end, List entries) => + DateTime start, DateTime end, List? entries) => _entriesInRangeImpl(start, end, entries).toList(); Iterable> _entriesInRangeImpl( - DateTime start, DateTime end, List entries) sync* { + DateTime start, DateTime end, List? entries) sync* { start = start.atMidnight; end = end.atMidnight; var d = start; while (d.compareTo(end) <= 0) { var es = []; - for (var entry in entries) { + for (var entry in entries!) { if (d.isSameDay(entry.time.atMidnight)) { es.add(entry); } diff --git a/experimental/web_dashboard/lib/src/widgets/categories_dropdown.dart b/experimental/web_dashboard/lib/src/widgets/categories_dropdown.dart index 4b7632b22..8692bfdbd 100644 --- a/experimental/web_dashboard/lib/src/widgets/categories_dropdown.dart +++ b/experimental/web_dashboard/lib/src/widgets/categories_dropdown.dart @@ -11,12 +11,12 @@ import '../api/api.dart'; /// one. class CategoryDropdown extends StatefulWidget { final CategoryApi api; - final ValueChanged onSelected; + final ValueChanged 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 { - Category _selected; - Future> _future; - Stream> _stream; + Category? _selected; + Future>? _future; + Stream>? _stream; @override void initState() { @@ -78,7 +78,7 @@ class _CategoryDropdownState extends State { initialData: futureSnapshot.hasData ? futureSnapshot.data : [], stream: _stream, builder: (context, snapshot) { - var data = snapshot.hasData ? snapshot.data : []; + var data = snapshot.hasData ? snapshot.data! : []; return DropdownButton( value: _selected, items: data.map(_buildDropdownItem).toList(), @@ -92,7 +92,7 @@ class _CategoryDropdownState extends State { ); } - void _setSelected(Category category) { + void _setSelected(Category? category) { if (_selected == category) { return; } diff --git a/experimental/web_dashboard/lib/src/widgets/category_chart.dart b/experimental/web_dashboard/lib/src/widgets/category_chart.dart index 415723df1..5a976e767 100644 --- a/experimental/web_dashboard/lib/src/widgets/category_chart.dart +++ b/experimental/web_dashboard/lib/src/widgets/category_chart.dart @@ -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>( - future: api.entries.list(category.id), + future: api!.entries.list(category.id!), builder: (context, futureSnapshot) { if (!futureSnapshot.hasData) { return _buildLoadingIndicator(); } return StreamBuilder>( 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 entries; + final List? 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), diff --git a/experimental/web_dashboard/lib/src/widgets/category_forms.dart b/experimental/web_dashboard/lib/src/widgets/category_forms.dart index bd3c568be..a863f2b19 100644 --- a/experimental/web_dashboard/lib/src/widgets/category_forms.dart +++ b/experimental/web_dashboard/lib/src/widgets/category_forms.dart @@ -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 { 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 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 { 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 { child: ElevatedButton( child: const Text('OK'), onPressed: () { - if (_formKey.currentState.validate()) { + if (_formKey.currentState!.validate()) { widget.onDone(true); } }, diff --git a/experimental/web_dashboard/lib/src/widgets/dialogs.dart b/experimental/web_dashboard/lib/src/widgets/dialogs.dart index 170319b8f..deba648d6 100644 --- a/experimental/web_dashboard/lib/src/widgets/dialogs.dart +++ b/experimental/web_dashboard/lib/src/widgets/dialogs.dart @@ -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 { } 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(); }, diff --git a/experimental/web_dashboard/lib/src/widgets/edit_entry.dart b/experimental/web_dashboard/lib/src/widgets/edit_entry.dart index 4a6365c8e..04bbe23de 100644 --- a/experimental/web_dashboard/lib/src/widgets/edit_entry.dart +++ b/experimental/web_dashboard/lib/src/widgets/edit_entry.dart @@ -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 { - Category _selected; + late Category _selected; final Entry _entry = Entry(0, DateTime.now()); @override Widget build(BuildContext context) { - var api = Provider.of(context).api; + var api = Provider.of(context).api!; return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -33,6 +33,7 @@ class _NewEntryFormState extends State { child: CategoryDropdown( api: api.categories, onSelected: (category) { + if (category == null) return; setState(() { _selected = category; }); @@ -43,7 +44,7 @@ class _NewEntryFormState extends State { 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 { } class EditEntryForm extends StatefulWidget { - final Entry entry; + final Entry? entry; final ValueChanged 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 { 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 { 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 { return; } setState(() { - widget.entry.time = result; + widget.entry!.time = result; }); }, ) @@ -139,7 +140,7 @@ class _EditEntryFormState extends State { child: ElevatedButton( child: const Text('OK'), onPressed: () { - if (_formKey.currentState.validate()) { + if (_formKey.currentState!.validate()) { widget.onDone(true); } }, diff --git a/experimental/web_dashboard/lib/src/widgets/third_party/adaptive_scaffold.dart b/experimental/web_dashboard/lib/src/widgets/third_party/adaptive_scaffold.dart index 30b065821..1d7a443b0 100644 --- a/experimental/web_dashboard/lib/src/widgets/third_party/adaptive_scaffold.dart +++ b/experimental/web_dashboard/lib/src/widgets/third_party/adaptive_scaffold.dart @@ -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 actions; - final Widget body; + final Widget? body; final int currentIndex; final List destinations; - final ValueChanged onNavigationIndexChange; - final FloatingActionButton floatingActionButton; + final ValueChanged? 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 { color: Colors.grey[300], ), Expanded( - child: widget.body, + child: widget.body!, ), ], ), @@ -155,7 +155,7 @@ class _AdaptiveScaffoldState extends State { void _destinationTapped(AdaptiveScaffoldDestination destination) { var idx = widget.destinations.indexOf(destination); if (idx != widget.currentIndex) { - widget.onNavigationIndexChange(idx); + widget.onNavigationIndexChange!(idx); } } } diff --git a/experimental/web_dashboard/pubspec.lock b/experimental/web_dashboard/pubspec.lock index 04b8b5671..63d83600c 100644 --- a/experimental/web_dashboard/pubspec.lock +++ b/experimental/web_dashboard/pubspec.lock @@ -7,14 +7,14 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "14.0.0" + version: "28.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "0.41.2" + version: "2.5.0" args: dependency: transitive description: @@ -28,7 +28,7 @@ packages: name: async url: "https://pub.dartlang.org" source: hosted - version: "2.8.1" + version: "2.8.2" boolean_selector: dependency: transitive description: @@ -42,42 +42,42 @@ packages: name: build url: "https://pub.dartlang.org" source: hosted - version: "1.6.2" + version: "2.1.1" build_config: dependency: transitive description: name: build_config url: "https://pub.dartlang.org" source: hosted - version: "0.4.5" + version: "1.0.0" build_daemon: dependency: transitive description: name: build_daemon url: "https://pub.dartlang.org" source: hosted - version: "2.1.10" + version: "3.0.1" build_resolvers: dependency: transitive description: name: build_resolvers url: "https://pub.dartlang.org" source: hosted - version: "1.5.3" + version: "2.0.4" build_runner: dependency: "direct dev" description: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "1.11.1+1" + version: "2.1.4" build_runner_core: dependency: transitive description: name: build_runner_core url: "https://pub.dartlang.org" source: hosted - version: "6.1.7" + version: "7.2.2" built_collection: dependency: transitive description: @@ -98,7 +98,7 @@ packages: name: characters url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.2.0" charcode: dependency: transitive description: @@ -117,8 +117,8 @@ packages: dependency: "direct main" description: path: charts_flutter - ref: HEAD - resolved-ref: "30477090290b348ed3101bc13017aae465f59017" + ref: "03c2aa67d12952e7f3cbba1d87646d96a9a7cdc4" + resolved-ref: "03c2aa67d12952e7f3cbba1d87646d96a9a7cdc4" url: "git://github.com/google/charts.git" source: git version: "0.11.0" @@ -128,7 +128,7 @@ packages: name: checked_yaml url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "2.0.1" cli_util: dependency: transitive description: @@ -149,28 +149,28 @@ packages: name: cloud_firestore url: "https://pub.dartlang.org" source: hosted - version: "0.13.7" + version: "2.5.3" cloud_firestore_platform_interface: dependency: transitive description: name: cloud_firestore_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" + version: "5.4.2" cloud_firestore_web: dependency: transitive description: name: cloud_firestore_web url: "https://pub.dartlang.org" source: hosted - version: "0.1.1+2" + version: "2.4.3" code_builder: dependency: transitive description: name: code_builder url: "https://pub.dartlang.org" source: hosted - version: "3.7.0" + version: "4.1.0" collection: dependency: transitive description: @@ -184,28 +184,28 @@ packages: name: convert url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" + version: "3.0.1" crypto: dependency: transitive description: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "2.1.5" + version: "3.0.1" cupertino_icons: dependency: "direct main" description: name: cupertino_icons url: "https://pub.dartlang.org" source: hosted - version: "0.1.3" + version: "1.0.3" dart_style: dependency: transitive description: name: dart_style url: "https://pub.dartlang.org" source: hosted - version: "1.3.12" + version: "2.2.0" fake_async: dependency: transitive description: @@ -219,56 +219,49 @@ packages: name: file url: "https://pub.dartlang.org" source: hosted - version: "5.2.1" - firebase: - dependency: transitive - description: - name: firebase - url: "https://pub.dartlang.org" - source: hosted - version: "7.3.3" + version: "6.1.2" firebase_auth: dependency: "direct main" description: name: firebase_auth url: "https://pub.dartlang.org" source: hosted - version: "0.16.1" + version: "3.1.3" firebase_auth_platform_interface: dependency: transitive description: name: firebase_auth_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.1.8" + version: "6.1.1" firebase_auth_web: dependency: transitive description: name: firebase_auth_web url: "https://pub.dartlang.org" source: hosted - version: "0.1.3+1" + version: "3.1.2" firebase_core: dependency: "direct main" description: name: firebase_core url: "https://pub.dartlang.org" source: hosted - version: "0.4.4" + version: "1.7.0" firebase_core_platform_interface: dependency: transitive description: name: firebase_core_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "4.0.1" firebase_core_web: dependency: transitive description: name: firebase_core_web url: "https://pub.dartlang.org" source: hosted - version: "0.1.1+2" + version: "1.1.0" fixnum: dependency: transitive description: @@ -298,13 +291,20 @@ packages: description: flutter source: sdk version: "0.0.0" + frontend_server_client: + dependency: transitive + description: + name: frontend_server_client + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.2" glob: dependency: transitive description: name: glob url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "2.0.2" google_sign_in: dependency: "direct main" description: @@ -332,35 +332,28 @@ packages: name: graphs url: "https://pub.dartlang.org" source: hosted - version: "0.2.0" + version: "2.1.0" grinder: dependency: "direct dev" description: name: grinder url: "https://pub.dartlang.org" source: hosted - version: "0.8.6" - http: - dependency: transitive - description: - name: http - url: "https://pub.dartlang.org" - source: hosted - version: "0.12.2" + version: "0.9.0" http_multi_server: dependency: transitive description: name: http_multi_server url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "3.0.1" http_parser: dependency: transitive description: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "3.1.4" + version: "4.0.0" intl: dependency: transitive description: @@ -374,7 +367,7 @@ packages: name: io url: "https://pub.dartlang.org" source: hosted - version: "0.3.5" + version: "1.0.3" js: dependency: transitive description: @@ -388,14 +381,14 @@ packages: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "3.1.1" + version: "4.1.0" json_serializable: dependency: "direct dev" description: name: json_serializable url: "https://pub.dartlang.org" source: hosted - version: "3.5.1" + version: "5.0.2" lints: dependency: transitive description: @@ -416,7 +409,7 @@ packages: name: matcher url: "https://pub.dartlang.org" source: hosted - version: "0.12.10" + version: "0.12.11" meta: dependency: transitive description: @@ -438,27 +431,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.0" - node_interop: - dependency: transitive - description: - name: node_interop - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.1" - node_io: - dependency: transitive - description: - name: node_io - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.0" package_config: dependency: transitive description: name: package_config url: "https://pub.dartlang.org" source: hosted - version: "1.9.3" + version: "2.0.2" path: dependency: transitive description: @@ -466,20 +445,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.0" - pedantic: - dependency: transitive - description: - name: pedantic - url: "https://pub.dartlang.org" - source: hosted - version: "1.11.1" plugin_platform_interface: dependency: transitive description: name: plugin_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "2.0.2" pool: dependency: transitive description: @@ -493,7 +465,7 @@ packages: name: provider url: "https://pub.dartlang.org" source: hosted - version: "4.3.3" + version: "6.0.1" pub_semver: dependency: transitive description: @@ -507,7 +479,7 @@ packages: name: pubspec_parse url: "https://pub.dartlang.org" source: hosted - version: "0.1.8" + version: "1.1.0" quiver: dependency: transitive description: @@ -515,27 +487,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.0.1" - quiver_hashcode: - dependency: transitive - description: - name: quiver_hashcode - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" shelf: dependency: transitive description: name: shelf url: "https://pub.dartlang.org" source: hosted - version: "0.7.9" + version: "1.2.0" shelf_web_socket: dependency: transitive description: name: shelf_web_socket url: "https://pub.dartlang.org" source: hosted - version: "0.2.4+1" + version: "1.0.1" sky_engine: dependency: transitive description: flutter @@ -547,7 +512,14 @@ packages: name: source_gen url: "https://pub.dartlang.org" source: hosted - version: "0.9.10+3" + version: "1.1.1" + source_helper: + dependency: transitive + description: + name: source_helper + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.0" source_span: dependency: transitive description: @@ -596,14 +568,14 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.2" + version: "0.4.3" timing: dependency: transitive description: name: timing url: "https://pub.dartlang.org" source: hosted - version: "0.1.1+3" + version: "1.0.0" typed_data: dependency: transitive description: @@ -617,14 +589,14 @@ packages: name: uuid url: "https://pub.dartlang.org" source: hosted - version: "2.2.2" + version: "3.0.5" vector_math: dependency: transitive description: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.1.1" watcher: dependency: transitive description: @@ -638,7 +610,7 @@ packages: name: web_socket_channel url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "2.1.0" yaml: dependency: transitive description: diff --git a/experimental/web_dashboard/pubspec.yaml b/experimental/web_dashboard/pubspec.yaml index 02874b235..3280a32a0 100644 --- a/experimental/web_dashboard/pubspec.yaml +++ b/experimental/web_dashboard/pubspec.yaml @@ -3,28 +3,31 @@ description: A dashboard app sample version: 1.0.0+1 publish_to: none environment: - sdk: ">=2.6.0 <3.0.0" + sdk: '>=2.12.0 <3.0.0' dependencies: flutter: sdk: flutter - cloud_firestore: ^0.13.0 - cupertino_icons: ^0.1.2 - firebase_auth: ^0.16.1 - firebase_core: ^0.4.3 + cloud_firestore: ^2.5.0 + cupertino_icons: ^1.0.0 + firebase_auth: ^3.1.0 + firebase_core: ^1.7.0 google_sign_in: ^5.0.0 - json_annotation: ^3.0.0 - provider: ^4.0.0 - uuid: ^2.0.0 + json_annotation: ^4.1.0 + provider: ^6.0.0 + uuid: ^3.0.0 + # The published version of charts_flutter is not up to date with master: + # https://github.com/google/charts/issues/678 charts_flutter: git: url: git://github.com/google/charts.git path: charts_flutter + ref: 03c2aa67d12952e7f3cbba1d87646d96a9a7cdc4 dev_dependencies: flutter_test: sdk: flutter - build_runner: ^1.8.0 - json_serializable: ^3.3.0 - grinder: ^0.8.4 + build_runner: ^2.1.0 + json_serializable: ^5.0.0 + grinder: ^0.9.0 flutter_lints: ^1.0.0 flutter: uses-material-design: true diff --git a/experimental/web_dashboard/test/mock_service_test.dart b/experimental/web_dashboard/test/mock_service_test.dart index 6eb8248a4..801f03d86 100644 --- a/experimental/web_dashboard/test/mock_service_test.dart +++ b/experimental/web_dashboard/test/mock_service_test.dart @@ -9,7 +9,7 @@ import 'package:web_dashboard/src/api/mock.dart'; void main() { group('mock dashboard API', () { - DashboardApi api; + late DashboardApi api; setUp(() { api = MockDashboardApi(); @@ -24,9 +24,10 @@ void main() { test('delete', () async { await api.categories.insert(Category('Coffees Drank')); var category = await api.categories.insert(Category('Miles Ran')); - var removed = await api.categories.delete(category.id); + var removed = await api.categories.delete(category.id!); - expect(removed.name, 'Miles Ran'); + expect(removed, isNotNull); + expect(removed!.name, 'Miles Ran'); var categories = await api.categories.list(); expect(categories, hasLength(1)); @@ -34,10 +35,11 @@ void main() { test('update', () async { var category = await api.categories.insert(Category('Coffees Drank')); - await api.categories.update(Category('Bagels Consumed'), category.id); + await api.categories.update(Category('Bagels Consumed'), category.id!); - var latest = await api.categories.get(category.id); - expect(latest.name, equals('Bagels Consumed')); + var latest = await api.categories.get(category.id!); + expect(latest, isNotNull); + expect(latest!.name, equals('Bagels Consumed')); }); test('subscribe', () async { var stream = api.categories.subscribe(); @@ -51,7 +53,7 @@ void main() { }); group('entry service', () { - Category category; + late Category category; DateTime dateTime = DateTime(2020, 1, 1, 30, 45); setUp(() async { @@ -60,38 +62,38 @@ void main() { }); test('insert', () async { - var entry = await api.entries.insert(category.id, Entry(1, dateTime)); + var entry = await api.entries.insert(category.id!, Entry(1, dateTime)); expect(entry.value, 1); expect(entry.time, dateTime); }); test('delete', () async { - await api.entries.insert(category.id, Entry(1, dateTime)); - var entry2 = await api.entries.insert(category.id, Entry(2, dateTime)); + await api.entries.insert(category.id!, Entry(1, dateTime)); + var entry2 = await api.entries.insert(category.id!, Entry(2, dateTime)); - await api.entries.delete(category.id, entry2.id); + await api.entries.delete(category.id!, entry2.id!); - var entries = await api.entries.list(category.id); + var entries = await api.entries.list(category.id!); expect(entries, hasLength(1)); }); test('update', () async { - var entry = await api.entries.insert(category.id, Entry(1, dateTime)); - var updated = - await api.entries.update(category.id, entry.id, Entry(2, dateTime)); + var entry = await api.entries.insert(category.id!, Entry(1, dateTime)); + var updated = await api.entries + .update(category.id!, entry.id!, Entry(2, dateTime)); expect(updated.value, 2); }); test('subscribe', () async { - var stream = api.entries.subscribe(category.id); + var stream = api.entries.subscribe(category.id!); stream.listen(expectAsync1((x) { expect(x, hasLength(1)); expect(x.first.value, equals(1)); }, count: 1)); - await api.entries.insert(category.id, Entry(1, dateTime)); + await api.entries.insert(category.id!, Entry(1, dateTime)); }); }); });