From 08beb692455e5c59f8c2fbcbeb569ca6060e0f21 Mon Sep 17 00:00:00 2001
From: Andrew Brogdon <RedBrogdon@users.noreply.github.com>
Date: Mon, 10 Jun 2019 09:47:09 -0700
Subject: [PATCH] Updates veggieseasons to Dart 2.3, adds some minor UI updates
 (#88)

---
 veggieseasons/ios/Podfile.lock                |   4 +-
 .../ios/Runner.xcodeproj/project.pbxproj      |   2 +
 .../lib/data/local_veggie_provider.dart       |  18 +++
 veggieseasons/lib/screens/details.dart        |  59 ++++-----
 veggieseasons/lib/screens/favorites.dart      |  54 +++-----
 veggieseasons/lib/screens/list.dart           |  90 +++++++-------
 veggieseasons/lib/screens/search.dart         |   6 +-
 veggieseasons/lib/screens/settings.dart       |   2 +-
 veggieseasons/lib/styles.dart                 |  58 ++++-----
 veggieseasons/lib/widgets/close_button.dart   |   2 +-
 veggieseasons/lib/widgets/search_bar.dart     |   6 +-
 veggieseasons/lib/widgets/settings_group.dart |  70 +++++------
 veggieseasons/lib/widgets/settings_item.dart  | 115 ++++++++----------
 veggieseasons/lib/widgets/trivia.dart         |  48 ++++----
 veggieseasons/lib/widgets/veggie_card.dart    |  51 ++++++--
 .../lib/widgets/veggie_headline.dart          |  70 ++++++++---
 veggieseasons/pubspec.lock                    |  16 +--
 veggieseasons/pubspec.yaml                    |   2 +-
 18 files changed, 348 insertions(+), 325 deletions(-)

diff --git a/veggieseasons/ios/Podfile.lock b/veggieseasons/ios/Podfile.lock
index 38ab12b2d..7e5a41704 100644
--- a/veggieseasons/ios/Podfile.lock
+++ b/veggieseasons/ios/Podfile.lock
@@ -17,6 +17,6 @@ SPEC CHECKSUMS:
   Flutter: 58dd7d1b27887414a370fcccb9e645c08ffd7a6a
   shared_preferences: 1feebfa37bb57264736e16865e7ffae7fc99b523
 
-PODFILE CHECKSUM: aff02bfeed411c636180d6812254b2daeea14d09
+PODFILE CHECKSUM: e8988baac3a50f787b9d3ed7ca44957b442f92a7
 
-COCOAPODS: 1.6.1
+COCOAPODS: 1.7.0
diff --git a/veggieseasons/ios/Runner.xcodeproj/project.pbxproj b/veggieseasons/ios/Runner.xcodeproj/project.pbxproj
index fa0d1924b..1388a7132 100644
--- a/veggieseasons/ios/Runner.xcodeproj/project.pbxproj
+++ b/veggieseasons/ios/Runner.xcodeproj/project.pbxproj
@@ -56,6 +56,7 @@
 		97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
 		97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
 		97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		9AC24389CA19ECD679B522EE /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
 		BA0A9C772FFC1878911ECDBC /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
@@ -134,6 +135,7 @@
 			children = (
 				BA0A9C772FFC1878911ECDBC /* Pods-Runner.debug.xcconfig */,
 				44D0F7D543E9A9D5B9AF94AC /* Pods-Runner.release.xcconfig */,
+				9AC24389CA19ECD679B522EE /* Pods-Runner.profile.xcconfig */,
 			);
 			name = Pods;
 			sourceTree = "<group>";
diff --git a/veggieseasons/lib/data/local_veggie_provider.dart b/veggieseasons/lib/data/local_veggie_provider.dart
index 2455a8b4c..5f7e5e71d 100644
--- a/veggieseasons/lib/data/local_veggie_provider.dart
+++ b/veggieseasons/lib/data/local_veggie_provider.dart
@@ -227,6 +227,15 @@ class LocalVeggieProvider {
           ],
           1,
         ),
+        Trivia(
+          'The first evidence of avocado consumption by humans dates back to what year?',
+          [
+            '2,000 B.C.',
+            '6,000 B.C.',
+            '10,000 B.C.',
+          ],
+          2,
+        ),
       ],
     ),
     Veggie(
@@ -371,6 +380,15 @@ class LocalVeggieProvider {
           ],
           0,
         ),
+        Trivia(
+          'Green cauliflower is sometimes called what?',
+          [
+            'Broccoflower',
+            'Avocadoflower',
+            'Gross',
+          ],
+          0,
+        ),
       ],
     ),
     Veggie(
diff --git a/veggieseasons/lib/screens/details.dart b/veggieseasons/lib/screens/details.dart
index 5f63199fa..292bcd2d8 100644
--- a/veggieseasons/lib/screens/details.dart
+++ b/veggieseasons/lib/screens/details.dart
@@ -42,13 +42,13 @@ class ServingInfoChart extends StatelessWidget {
   Widget build(BuildContext context) {
     return Column(
       children: [
-        SizedBox(height: 16.0),
+        SizedBox(height: 16),
         Align(
           alignment: Alignment.centerLeft,
           child: Padding(
             padding: const EdgeInsets.only(
-              left: 9.0,
-              bottom: 4.0,
+              left: 9,
+              bottom: 4,
             ),
             child: Text(
               'Serving info',
@@ -60,7 +60,7 @@ class ServingInfoChart extends StatelessWidget {
           decoration: BoxDecoration(
             border: Border.all(color: Styles.servingInfoBorderColor),
           ),
-          padding: const EdgeInsets.all(8.0),
+          padding: const EdgeInsets.all(8),
           child: Column(
             children: [
               Table(
@@ -134,7 +134,7 @@ class ServingInfoChart extends StatelessWidget {
                 ],
               ),
               Padding(
-                padding: const EdgeInsets.only(top: 16.0),
+                padding: const EdgeInsets.only(top: 16),
                 child: FutureBuilder(
                   future: prefs.desiredCalories,
                   builder: (context, snapshot) {
@@ -164,24 +164,8 @@ class InfoView extends StatelessWidget {
     final prefs = ScopedModel.of<Preferences>(context, rebuildOnChange: true);
     final veggie = appState.getVeggie(id);
 
-    final seasonIcons = <Widget>[];
-
-    for (Season season in veggie.seasons) {
-      seasonIcons.addAll([
-        SizedBox(width: 12.0),
-        Padding(
-          padding: Styles.seasonIconPadding[season],
-          child: Icon(
-            Styles.seasonIconData[season],
-            semanticLabel: seasonNames[season],
-            color: Styles.seasonColors[season],
-          ),
-        ),
-      ]);
-    }
-
     return Padding(
-      padding: const EdgeInsets.all(24.0),
+      padding: const EdgeInsets.all(24),
       child: Column(
         crossAxisAlignment: CrossAxisAlignment.stretch,
         children: [
@@ -201,20 +185,31 @@ class InfoView extends StatelessWidget {
                 },
               ),
               Spacer(),
-            ]..addAll(seasonIcons),
+              for (Season season in veggie.seasons) ...[
+                SizedBox(width: 12),
+                Padding(
+                  padding: Styles.seasonIconPadding[season],
+                  child: Icon(
+                    Styles.seasonIconData[season],
+                    semanticLabel: seasonNames[season],
+                    color: Styles.seasonColors[season],
+                  ),
+                ),
+              ],
+            ],
           ),
-          SizedBox(height: 8.0),
+          SizedBox(height: 8),
           Text(
             veggie.name,
             style: Styles.detailsTitleText,
           ),
-          SizedBox(height: 8.0),
+          SizedBox(height: 8),
           Text(
             veggie.shortDescription,
             style: Styles.detailsDescriptionText,
           ),
           ServingInfoChart(veggie, prefs),
-          SizedBox(height: 24.0),
+          SizedBox(height: 24),
           Row(
             mainAxisSize: MainAxisSize.min,
             children: [
@@ -224,7 +219,7 @@ class InfoView extends StatelessWidget {
                   appState.setFavorite(id, value);
                 },
               ),
-              SizedBox(width: 8.0),
+              SizedBox(width: 8),
               Text('Save to Garden'),
             ],
           ),
@@ -250,12 +245,12 @@ class _DetailsScreenState extends State<DetailsScreen> {
     final veggie = model.getVeggie(widget.id);
 
     return SizedBox(
-      height: 150.0,
+      height: 150,
       child: Stack(
         children: [
           Positioned(
-            right: 0.0,
-            left: 0.0,
+            right: 0,
+            left: 0,
             child: Image.asset(
               veggie.imageAssetPath,
               fit: BoxFit.cover,
@@ -263,8 +258,8 @@ class _DetailsScreenState extends State<DetailsScreen> {
             ),
           ),
           Positioned(
-            top: 16.0,
-            left: 16.0,
+            top: 16,
+            left: 16,
             child: SafeArea(
               child: CloseButton(() {
                 Navigator.of(context).pop();
diff --git a/veggieseasons/lib/screens/favorites.dart b/veggieseasons/lib/screens/favorites.dart
index 812159d69..0bade8625 100644
--- a/veggieseasons/lib/screens/favorites.dart
+++ b/veggieseasons/lib/screens/favorites.dart
@@ -11,49 +11,35 @@ import 'package:veggieseasons/styles.dart';
 import 'package:veggieseasons/widgets/veggie_headline.dart';
 
 class FavoritesScreen extends StatelessWidget {
-  /// Builds the "content" of the favorites screen: either a list of favorite
-  /// veggies or a note that says the user hasn't favorited any yet.
-  Widget _buildTabViewBody(BuildContext context) {
-    final model = ScopedModel.of<AppState>(context, rebuildOnChange: true);
-
-    if (model.favoriteVeggies.length == 0) {
-      return Padding(
-        padding: const EdgeInsets.symmetric(horizontal: 24.0),
-        child: Text(
-          'You haven\'t added any favorite veggies to your garden yet.',
-          style: Styles.headlineDescription,
-        ),
-      );
-    }
-
-    final rows = <Widget>[
-      SizedBox(height: 24.0),
-    ];
-
-    for (Veggie veggie in model.favoriteVeggies) {
-      rows.add(
-        Padding(
-          padding: EdgeInsets.only(left: 16.0, right: 16.0, bottom: 24.0),
-          child: VeggieHeadline(veggie),
-        ),
-      );
-    }
-
-    return ListView(
-      children: rows,
-    );
-  }
-
   @override
   Widget build(BuildContext context) {
     return CupertinoTabView(
       builder: (context) {
+        final model = ScopedModel.of<AppState>(context, rebuildOnChange: true);
+
         return CupertinoPageScaffold(
           navigationBar: CupertinoNavigationBar(
             middle: Text('My Garden'),
           ),
           child: Center(
-            child: _buildTabViewBody(context),
+            child: model.favoriteVeggies.isEmpty
+                ? Padding(
+                    padding: const EdgeInsets.symmetric(horizontal: 24),
+                    child: Text(
+                      'You haven\'t added any favorite veggies to your garden yet.',
+                      style: Styles.headlineDescription,
+                    ),
+                  )
+                : ListView(
+                    children: [
+                      SizedBox(height: 24),
+                      for (Veggie veggie in model.favoriteVeggies)
+                        Padding(
+                          padding: EdgeInsets.fromLTRB(16, 0, 16, 24),
+                          child: VeggieHeadline(veggie),
+                        ),
+                    ],
+                  ),
           ),
         );
       },
diff --git a/veggieseasons/lib/screens/list.dart b/veggieseasons/lib/screens/list.dart
index 9a5611fc6..5dbd34684 100644
--- a/veggieseasons/lib/screens/list.dart
+++ b/veggieseasons/lib/screens/list.dart
@@ -13,24 +13,16 @@ import 'package:veggieseasons/styles.dart';
 import 'package:veggieseasons/widgets/veggie_card.dart';
 
 class ListScreen extends StatelessWidget {
-  List<Widget> _generateVeggieRows(List<Veggie> veggies, Preferences prefs,
-      {bool inSeason = true}) {
-    final cards = List<Widget>();
-
-    for (Veggie veggie in veggies) {
-      cards.add(Padding(
-        padding: EdgeInsets.only(left: 16.0, right: 16.0, bottom: 24.0),
-        child: FutureBuilder<Set<VeggieCategory>>(
-            future: prefs.preferredCategories,
-            builder: (context, snapshot) {
-              final data = snapshot.data ?? Set<VeggieCategory>();
-              return VeggieCard(
-                  veggie, inSeason, data.contains(veggie.category));
-            }),
-      ));
-    }
-
-    return cards;
+  Widget _generateVeggieRow(veggie, Preferences prefs, {bool inSeason = true}) {
+    return Padding(
+      padding: EdgeInsets.only(left: 16, right: 16, bottom: 24),
+      child: FutureBuilder<Set<VeggieCategory>>(
+          future: prefs.preferredCategories,
+          builder: (context, snapshot) {
+            final data = snapshot.data ?? Set<VeggieCategory>();
+            return VeggieCard(veggie, inSeason, data.contains(veggie.category));
+          }),
+    );
   }
 
   @override
@@ -38,42 +30,46 @@ class ListScreen extends StatelessWidget {
     return CupertinoTabView(
       builder: (context) {
         String dateString = DateFormat("MMMM y").format(DateTime.now());
+
         final appState =
             ScopedModel.of<AppState>(context, rebuildOnChange: true);
         final prefs =
             ScopedModel.of<Preferences>(context, rebuildOnChange: true);
 
-        final rows = <Widget>[];
-
-        rows.add(
-          Padding(
-            padding: const EdgeInsets.fromLTRB(16.0, 24.0, 16.0, 16.0),
-            child: Column(
-              crossAxisAlignment: CrossAxisAlignment.start,
-              children: [
-                Text(dateString.toUpperCase(), style: Styles.minorText),
-                Text('In season today', style: Styles.headlineText),
-              ],
-            ),
-          ),
-        );
-
-        rows.addAll(_generateVeggieRows(appState.availableVeggies, prefs));
-
-        rows.add(
-          Padding(
-            padding: const EdgeInsets.fromLTRB(16.0, 24.0, 16.0, 16.0),
-            child: Text('Not in season', style: Styles.headlineText),
-          ),
-        );
-
-        rows.addAll(_generateVeggieRows(appState.unavailableVeggies, prefs,
-            inSeason: false));
-
         return DecoratedBox(
           decoration: BoxDecoration(color: Color(0xffffffff)),
-          child: ListView(
-            children: rows,
+          child: ListView.builder(
+            itemCount: appState.allVeggies.length + 2,
+            itemBuilder: (context, index) {
+              if (index == 0) {
+                return Padding(
+                  padding: const EdgeInsets.fromLTRB(16, 24, 16, 16),
+                  child: Column(
+                    crossAxisAlignment: CrossAxisAlignment.start,
+                    children: [
+                      Text(dateString.toUpperCase(), style: Styles.minorText),
+                      Text('In season today', style: Styles.headlineText),
+                    ],
+                  ),
+                );
+              } else if (index <= appState.availableVeggies.length) {
+                return _generateVeggieRow(
+                  appState.availableVeggies[index - 1],
+                  prefs,
+                );
+              } else if (index <= appState.availableVeggies.length + 1) {
+                return Padding(
+                  padding: const EdgeInsets.fromLTRB(16, 24, 16, 16),
+                  child: Text('Not in season', style: Styles.headlineText),
+                );
+              } else {
+                int relativeIndex =
+                    index - (appState.availableVeggies.length + 2);
+                return _generateVeggieRow(
+                    appState.unavailableVeggies[relativeIndex], prefs,
+                    inSeason: false);
+              }
+            },
           ),
         );
       },
diff --git a/veggieseasons/lib/screens/search.dart b/veggieseasons/lib/screens/search.dart
index 05966d336..a5d93daf3 100644
--- a/veggieseasons/lib/screens/search.dart
+++ b/veggieseasons/lib/screens/search.dart
@@ -39,7 +39,7 @@ class _SearchScreenState extends State<SearchScreen> {
 
   Widget _createSearchBox() {
     return Padding(
-      padding: const EdgeInsets.all(8.0),
+      padding: const EdgeInsets.all(8),
       child: SearchBar(
         controller: controller,
         focusNode: focusNode,
@@ -51,7 +51,7 @@ class _SearchScreenState extends State<SearchScreen> {
     if (veggies.isEmpty) {
       return Center(
         child: Padding(
-          padding: const EdgeInsets.symmetric(horizontal: 24.0),
+          padding: const EdgeInsets.symmetric(horizontal: 24),
           child: Text(
             'No veggies matching your search terms were found.',
             style: Styles.headlineDescription,
@@ -64,7 +64,7 @@ class _SearchScreenState extends State<SearchScreen> {
       itemCount: veggies.length,
       itemBuilder: (context, i) {
         return Padding(
-          padding: EdgeInsets.only(left: 16.0, right: 16.0, bottom: 24.0),
+          padding: EdgeInsets.only(left: 16, right: 16, bottom: 24),
           child: VeggieHeadline(veggies[i]),
         );
       },
diff --git a/veggieseasons/lib/screens/settings.dart b/veggieseasons/lib/screens/settings.dart
index b6f537a66..7480837b5 100644
--- a/veggieseasons/lib/screens/settings.dart
+++ b/veggieseasons/lib/screens/settings.dart
@@ -139,7 +139,7 @@ class SettingsScreen extends StatelessWidget {
           return Row(
             children: [
               Text(snapshot.data?.toString() ?? ''),
-              SizedBox(width: 8.0),
+              SizedBox(width: 8),
               SettingsNavigationIndicator(),
             ],
           );
diff --git a/veggieseasons/lib/styles.dart b/veggieseasons/lib/styles.dart
index 6e3371298..cd16dd126 100644
--- a/veggieseasons/lib/styles.dart
+++ b/veggieseasons/lib/styles.dart
@@ -11,15 +11,15 @@ abstract class Styles {
   static const headlineText = TextStyle(
     color: Color.fromRGBO(0, 0, 0, 0.8),
     fontFamily: 'NotoSans',
-    fontSize: 32.0,
+    fontSize: 32,
     fontStyle: FontStyle.normal,
     fontWeight: FontWeight.bold,
   );
 
   static const minorText = TextStyle(
-    color: Color.fromRGBO(128, 128, 128, 1.0),
+    color: Color.fromRGBO(128, 128, 128, 1),
     fontFamily: 'NotoSans',
-    fontSize: 16.0,
+    fontSize: 16,
     fontStyle: FontStyle.normal,
     fontWeight: FontWeight.normal,
   );
@@ -27,7 +27,7 @@ abstract class Styles {
   static const headlineName = TextStyle(
     color: Color.fromRGBO(0, 0, 0, 0.9),
     fontFamily: 'NotoSans',
-    fontSize: 24.0,
+    fontSize: 24,
     fontStyle: FontStyle.normal,
     fontWeight: FontWeight.bold,
   );
@@ -35,7 +35,7 @@ abstract class Styles {
   static const headlineDescription = TextStyle(
     color: Color.fromRGBO(0, 0, 0, 0.8),
     fontFamily: 'NotoSans',
-    fontSize: 16.0,
+    fontSize: 16,
     fontStyle: FontStyle.normal,
     fontWeight: FontWeight.normal,
   );
@@ -43,7 +43,7 @@ abstract class Styles {
   static const cardTitleText = TextStyle(
     color: Color.fromRGBO(0, 0, 0, 0.9),
     fontFamily: 'NotoSans',
-    fontSize: 32.0,
+    fontSize: 32,
     fontStyle: FontStyle.normal,
     fontWeight: FontWeight.bold,
   );
@@ -51,7 +51,7 @@ abstract class Styles {
   static const cardCategoryText = TextStyle(
     color: Color.fromRGBO(255, 255, 255, 0.9),
     fontFamily: 'NotoSans',
-    fontSize: 16.0,
+    fontSize: 16,
     fontStyle: FontStyle.normal,
     fontWeight: FontWeight.normal,
   );
@@ -59,7 +59,7 @@ abstract class Styles {
   static const cardDescriptionText = TextStyle(
     color: Color.fromRGBO(0, 0, 0, 0.9),
     fontFamily: 'NotoSans',
-    fontSize: 16.0,
+    fontSize: 16,
     fontStyle: FontStyle.normal,
     fontWeight: FontWeight.normal,
   );
@@ -67,7 +67,7 @@ abstract class Styles {
   static const detailsTitleText = TextStyle(
     color: Color.fromRGBO(0, 0, 0, 0.9),
     fontFamily: 'NotoSans',
-    fontSize: 30.0,
+    fontSize: 30,
     fontStyle: FontStyle.normal,
     fontWeight: FontWeight.bold,
   );
@@ -75,7 +75,7 @@ abstract class Styles {
   static const detailsPreferredCategoryText = TextStyle(
     color: Color.fromRGBO(0, 80, 0, 0.7),
     fontFamily: 'NotoSans',
-    fontSize: 16.0,
+    fontSize: 16,
     fontStyle: FontStyle.normal,
     fontWeight: FontWeight.bold,
   );
@@ -83,7 +83,7 @@ abstract class Styles {
   static const detailsCategoryText = TextStyle(
     color: Color.fromRGBO(0, 0, 0, 0.7),
     fontFamily: 'NotoSans',
-    fontSize: 16.0,
+    fontSize: 16,
     fontStyle: FontStyle.normal,
     fontWeight: FontWeight.normal,
   );
@@ -91,7 +91,7 @@ abstract class Styles {
   static const detailsDescriptionText = TextStyle(
     color: Color.fromRGBO(0, 0, 0, 0.9),
     fontFamily: 'NotoSans',
-    fontSize: 16.0,
+    fontSize: 16,
     fontStyle: FontStyle.normal,
     fontWeight: FontWeight.normal,
   );
@@ -99,15 +99,15 @@ abstract class Styles {
   static const detailsBoldDescriptionText = TextStyle(
     color: Color.fromRGBO(0, 0, 0, 0.9),
     fontFamily: 'NotoSans',
-    fontSize: 16.0,
+    fontSize: 16,
     fontStyle: FontStyle.normal,
     fontWeight: FontWeight.bold,
   );
 
   static const detailsServingHeaderText = TextStyle(
-    color: Color.fromRGBO(176, 176, 176, 1.0),
+    color: Color.fromRGBO(176, 176, 176, 1),
     fontFamily: 'NotoSans',
-    fontSize: 16.0,
+    fontSize: 16,
     fontStyle: FontStyle.normal,
     fontWeight: FontWeight.bold,
   );
@@ -115,7 +115,7 @@ abstract class Styles {
   static const detailsServingLabelText = TextStyle(
     color: Color.fromRGBO(0, 0, 0, 0.9),
     fontFamily: 'NotoSans',
-    fontSize: 16.0,
+    fontSize: 16,
     fontStyle: FontStyle.normal,
     fontWeight: FontWeight.bold,
   );
@@ -123,7 +123,7 @@ abstract class Styles {
   static const detailsServingValueText = TextStyle(
     color: Color.fromRGBO(0, 0, 0, 0.9),
     fontFamily: 'NotoSans',
-    fontSize: 16.0,
+    fontSize: 16,
     fontStyle: FontStyle.normal,
     fontWeight: FontWeight.normal,
   );
@@ -131,7 +131,7 @@ abstract class Styles {
   static const detailsServingNoteText = TextStyle(
     color: Color.fromRGBO(0, 0, 0, 0.9),
     fontFamily: 'NotoSans',
-    fontSize: 16.0,
+    fontSize: 16,
     fontStyle: FontStyle.italic,
     fontWeight: FontWeight.normal,
   );
@@ -139,7 +139,7 @@ abstract class Styles {
   static const triviaFinishedTitleText = TextStyle(
     color: Color.fromRGBO(0, 0, 0, 0.9),
     fontFamily: 'NotoSans',
-    fontSize: 32.0,
+    fontSize: 32,
     fontStyle: FontStyle.normal,
     fontWeight: FontWeight.normal,
   );
@@ -147,7 +147,7 @@ abstract class Styles {
   static const triviaFinishedText = TextStyle(
     color: Color.fromRGBO(0, 0, 0, 0.9),
     fontFamily: 'NotoSans',
-    fontSize: 16.0,
+    fontSize: 16,
     fontStyle: FontStyle.normal,
     fontWeight: FontWeight.normal,
   );
@@ -155,7 +155,7 @@ abstract class Styles {
   static const triviaFinishedBigText = TextStyle(
     color: Color.fromRGBO(0, 0, 0, 0.9),
     fontFamily: 'NotoSans',
-    fontSize: 48.0,
+    fontSize: 48,
     fontStyle: FontStyle.normal,
     fontWeight: FontWeight.normal,
   );
@@ -173,16 +173,16 @@ abstract class Styles {
   static const closeButtonPressed = Color(0xff808080);
 
   static const TextStyle searchText = TextStyle(
-    color: Color.fromRGBO(0, 0, 0, 1.0),
+    color: Color.fromRGBO(0, 0, 0, 1),
     fontFamily: 'NotoSans',
-    fontSize: 14.0,
+    fontSize: 14,
     fontStyle: FontStyle.normal,
     fontWeight: FontWeight.normal,
   );
 
-  static const Color searchCursorColor = Color.fromRGBO(0, 122, 255, 1.0);
+  static const Color searchCursorColor = Color.fromRGBO(0, 122, 255, 1);
 
-  static const Color searchIconColor = Color.fromRGBO(128, 128, 128, 1.0);
+  static const Color searchIconColor = Color.fromRGBO(128, 128, 128, 1);
 
   static const seasonColors = <Season, Color>{
     Season.winter: Color(0xff336dcc),
@@ -194,10 +194,10 @@ abstract class Styles {
   // While handy, some of the Font Awesome icons sometimes bleed over their
   // allotted bounds. This padding is used to adjust for that.
   static const seasonIconPadding = {
-    Season.winter: const EdgeInsets.only(right: 0.0),
-    Season.spring: const EdgeInsets.only(right: 4.0),
-    Season.summer: const EdgeInsets.only(right: 6.0),
-    Season.autumn: const EdgeInsets.only(right: 0.0),
+    Season.winter: const EdgeInsets.only(right: 0),
+    Season.spring: const EdgeInsets.only(right: 4),
+    Season.summer: const EdgeInsets.only(right: 6),
+    Season.autumn: const EdgeInsets.only(right: 0),
   };
 
   static const seasonIconData = {
diff --git a/veggieseasons/lib/widgets/close_button.dart b/veggieseasons/lib/widgets/close_button.dart
index 5c42a5ea1..ee72a3aa2 100644
--- a/veggieseasons/lib/widgets/close_button.dart
+++ b/veggieseasons/lib/widgets/close_button.dart
@@ -20,7 +20,7 @@ class FrostedBox extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
     return BackdropFilter(
-      filter: ImageFilter.blur(sigmaX: 10.0, sigmaY: 10.0),
+      filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
       child: DecoratedBox(
         decoration: BoxDecoration(
           color: Styles.frostedBackground,
diff --git a/veggieseasons/lib/widgets/search_bar.dart b/veggieseasons/lib/widgets/search_bar.dart
index 717cfa626..aa1549c64 100644
--- a/veggieseasons/lib/widgets/search_bar.dart
+++ b/veggieseasons/lib/widgets/search_bar.dart
@@ -20,12 +20,12 @@ class SearchBar extends StatelessWidget {
     return DecoratedBox(
       decoration: BoxDecoration(
         color: Styles.searchBackground,
-        borderRadius: BorderRadius.circular(10.0),
+        borderRadius: BorderRadius.circular(10),
       ),
       child: Padding(
         padding: const EdgeInsets.symmetric(
-          horizontal: 4.0,
-          vertical: 8.0,
+          horizontal: 4,
+          vertical: 8,
         ),
         child: Row(
           children: [
diff --git a/veggieseasons/lib/widgets/settings_group.dart b/veggieseasons/lib/widgets/settings_group.dart
index f73cc17b6..0687ffd05 100644
--- a/veggieseasons/lib/widgets/settings_group.dart
+++ b/veggieseasons/lib/widgets/settings_group.dart
@@ -22,9 +22,9 @@ class SettingsGroupHeader extends StatelessWidget {
   Widget build(BuildContext context) {
     return Padding(
       padding: EdgeInsets.only(
-        left: 15.0,
-        right: 15.0,
-        bottom: 6.0,
+        left: 15,
+        right: 15,
+        bottom: 6,
       ),
       child: Text(
         title.toUpperCase(),
@@ -47,15 +47,15 @@ class SettingsGroupFooter extends StatelessWidget {
   Widget build(BuildContext context) {
     return Padding(
       padding: EdgeInsets.only(
-        left: 15.0,
-        right: 15.0,
+        left: 15,
+        right: 15,
         top: 7.5,
       ),
       child: Text(
         title,
         style: TextStyle(
           color: Styles.settingsGroupSubtitle,
-          fontSize: 13.0,
+          fontSize: 13,
           letterSpacing: -0.08,
         ),
       ),
@@ -87,45 +87,35 @@ class SettingsGroup extends StatelessWidget {
       dividedItems.add(items[i]);
     }
 
-    final List<Widget> columnChildren = [];
-
-    if (header != null) {
-      columnChildren.add(header);
-    }
-
-    columnChildren.add(
-      Container(
-        decoration: BoxDecoration(
-          color: CupertinoColors.white,
-          border: Border(
-            top: const BorderSide(
-              color: Styles.settingsLineation,
-              width: 0.0,
-            ),
-            bottom: const BorderSide(
-              color: Styles.settingsLineation,
-              width: 0.0,
-            ),
-          ),
-        ),
-        child: Column(
-          crossAxisAlignment: CrossAxisAlignment.stretch,
-          children: dividedItems,
-        ),
-      ),
-    );
-
-    if (footer != null) {
-      columnChildren.add(footer);
-    }
-
     return Padding(
       padding: EdgeInsets.only(
-        top: header == null ? 35.0 : 22.0,
+        top: header == null ? 35 : 22,
       ),
       child: Column(
         crossAxisAlignment: CrossAxisAlignment.start,
-        children: columnChildren,
+        children: [
+          if (header != null) header,
+          Container(
+            decoration: BoxDecoration(
+              color: CupertinoColors.white,
+              border: Border(
+                top: const BorderSide(
+                  color: Styles.settingsLineation,
+                  width: 0,
+                ),
+                bottom: const BorderSide(
+                  color: Styles.settingsLineation,
+                  width: 0,
+                ),
+              ),
+            ),
+            child: Column(
+              crossAxisAlignment: CrossAxisAlignment.stretch,
+              children: dividedItems,
+            ),
+          ),
+          if (footer != null) footer,
+        ],
       ),
     );
   }
diff --git a/veggieseasons/lib/widgets/settings_item.dart b/veggieseasons/lib/widgets/settings_item.dart
index 4af93fe9e..80f1b3beb 100644
--- a/veggieseasons/lib/widgets/settings_item.dart
+++ b/veggieseasons/lib/widgets/settings_item.dart
@@ -23,7 +23,7 @@ class SettingsNavigationIndicator extends StatelessWidget {
     return Icon(
       CupertinoIcons.forward,
       color: Styles.settingsMediumGray,
-      size: 21.0,
+      size: 21,
     );
   }
 }
@@ -45,14 +45,14 @@ class SettingsIcon extends StatelessWidget {
   Widget build(BuildContext context) {
     return Container(
       decoration: BoxDecoration(
-        borderRadius: BorderRadius.circular(5.0),
+        borderRadius: BorderRadius.circular(5),
         color: backgroundColor,
       ),
       child: Center(
         child: Icon(
           icon,
           color: foregroundColor,
-          size: 20.0,
+          size: 20,
         ),
       ),
     );
@@ -85,67 +85,6 @@ class SettingsItemState extends State<SettingsItem> {
 
   @override
   Widget build(BuildContext context) {
-    List<Widget> rowChildren = [];
-
-    if (widget.icon != null) {
-      rowChildren.add(
-        Padding(
-          padding: const EdgeInsets.only(
-            left: 15.0,
-            bottom: 2.0,
-          ),
-          child: SizedBox(
-            height: 29.0,
-            width: 29.0,
-            child: widget.icon,
-          ),
-        ),
-      );
-    }
-
-    Widget titleSection;
-
-    if (widget.subtitle == null) {
-      titleSection = Padding(
-        padding: EdgeInsets.only(top: 1.5),
-        child: Text(widget.label),
-      );
-    } else {
-      titleSection = Column(
-        crossAxisAlignment: CrossAxisAlignment.start,
-        children: <Widget>[
-          SizedBox(height: 8.5),
-          Text(widget.label),
-          SizedBox(height: 4.0),
-          Text(
-            widget.subtitle,
-            style: TextStyle(
-              fontSize: 12.0,
-              letterSpacing: -0.2,
-            ),
-          )
-        ],
-      );
-    }
-
-    rowChildren.add(
-      Expanded(
-        child: Padding(
-          padding: const EdgeInsets.only(
-            left: 15.0,
-          ),
-          child: titleSection,
-        ),
-      ),
-    );
-
-    rowChildren.add(
-      Padding(
-        padding: const EdgeInsets.only(right: 11.0),
-        child: widget.content ?? Container(),
-      ),
-    );
-
     return AnimatedContainer(
       duration: const Duration(milliseconds: 200),
       color: pressed ? Styles.settingsItemPressed : Styles.transparentColor,
@@ -168,9 +107,53 @@ class SettingsItemState extends State<SettingsItem> {
           }
         },
         child: SizedBox(
-          height: widget.subtitle == null ? 44.0 : 57.0,
+          height: widget.subtitle == null ? 44 : 57,
           child: Row(
-            children: rowChildren,
+            children: [
+              if (widget.icon != null)
+                Padding(
+                  padding: const EdgeInsets.only(
+                    left: 15,
+                    bottom: 2,
+                  ),
+                  child: SizedBox(
+                    height: 29,
+                    width: 29,
+                    child: widget.icon,
+                  ),
+                ),
+              Expanded(
+                child: Padding(
+                  padding: const EdgeInsets.only(
+                    left: 15,
+                  ),
+                  child: widget.subtitle != null
+                      ? Column(
+                          crossAxisAlignment: CrossAxisAlignment.start,
+                          children: <Widget>[
+                            SizedBox(height: 8.5),
+                            Text(widget.label),
+                            SizedBox(height: 4),
+                            Text(
+                              widget.subtitle,
+                              style: TextStyle(
+                                fontSize: 12,
+                                letterSpacing: -0.2,
+                              ),
+                            ),
+                          ],
+                        )
+                      : Padding(
+                          padding: EdgeInsets.only(top: 1.5),
+                          child: Text(widget.label),
+                        ),
+                ),
+              ),
+              Padding(
+                padding: const EdgeInsets.only(right: 11),
+                child: widget.content ?? Container(),
+              ),
+            ],
           ),
         ),
       ),
diff --git a/veggieseasons/lib/widgets/trivia.dart b/veggieseasons/lib/widgets/trivia.dart
index 766b1b365..d7954b67d 100644
--- a/veggieseasons/lib/widgets/trivia.dart
+++ b/veggieseasons/lib/widgets/trivia.dart
@@ -107,14 +107,14 @@ class _TriviaViewState extends State<TriviaView> {
   // restart everything.
   Widget _buildFinishedView() {
     return Padding(
-      padding: const EdgeInsets.all(32.0),
+      padding: const EdgeInsets.all(32),
       child: Column(
         children: [
           Text(
             'All done!',
             style: Styles.triviaFinishedTitleText,
           ),
-          SizedBox(height: 16.0),
+          SizedBox(height: 16),
           Text(
             'You answered',
             style: Styles.triviaFinishedText,
@@ -129,7 +129,7 @@ class _TriviaViewState extends State<TriviaView> {
                 style: Styles.triviaFinishedBigText,
               ),
               Padding(
-                padding: const EdgeInsets.symmetric(horizontal: 16.0),
+                padding: const EdgeInsets.symmetric(horizontal: 16),
                 child: Text(
                   ' of ',
                   style: Styles.triviaFinishedText,
@@ -145,7 +145,7 @@ class _TriviaViewState extends State<TriviaView> {
             'questions correctly!',
             style: Styles.triviaFinishedText,
           ),
-          SizedBox(height: 16.0),
+          SizedBox(height: 16),
           CupertinoButton(
             child: Text('Try Again'),
             onPressed: () => _resetGame(),
@@ -157,30 +157,26 @@ class _TriviaViewState extends State<TriviaView> {
 
   // Presents the current trivia's question and answer choices.
   Widget _buildQuestionView() {
-    List<Widget> buttons = [];
-
-    for (int i = 0; i < currentTrivia.answers.length; i++) {
-      buttons.add(Padding(
-        padding: const EdgeInsets.all(8.0),
-        child: CupertinoButton(
-          color: CupertinoColors.activeBlue,
-          child: Text(
-            currentTrivia.answers[i],
-            textAlign: TextAlign.center,
-          ),
-          onPressed: () => _processAnswer(i),
-        ),
-      ));
-    }
-
     return Padding(
-      padding: const EdgeInsets.all(16.0),
+      padding: const EdgeInsets.all(16),
       child: Column(
         children: [
-          SizedBox(height: 16.0),
+          SizedBox(height: 16),
           Text(currentTrivia.question),
-          SizedBox(height: 32.0),
-        ]..addAll(buttons),
+          SizedBox(height: 32),
+          for (int i = 0; i < currentTrivia.answers.length; i++)
+            Padding(
+              padding: const EdgeInsets.all(8),
+              child: CupertinoButton(
+                color: CupertinoColors.activeBlue,
+                child: Text(
+                  currentTrivia.answers[i],
+                  textAlign: TextAlign.center,
+                ),
+                onPressed: () => _processAnswer(i),
+              ),
+            ),
+        ],
       ),
     );
   }
@@ -189,13 +185,13 @@ class _TriviaViewState extends State<TriviaView> {
   // continue through the game.
   Widget _buildResultView() {
     return Padding(
-      padding: const EdgeInsets.all(32.0),
+      padding: const EdgeInsets.all(32),
       child: Column(
         children: [
           Text(status == PlayerStatus.wasCorrect
               ? 'That\'s right!'
               : 'Sorry, that wasn\'t the right answer.'),
-          SizedBox(height: 16.0),
+          SizedBox(height: 16),
           CupertinoButton(
             child: Text('Next Question'),
             onPressed: () => setState(() {
diff --git a/veggieseasons/lib/widgets/veggie_card.dart b/veggieseasons/lib/widgets/veggie_card.dart
index 7449a8623..3f39887bd 100644
--- a/veggieseasons/lib/widgets/veggie_card.dart
+++ b/veggieseasons/lib/widgets/veggie_card.dart
@@ -2,19 +2,48 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'dart:ui';
+
 import 'package:flutter/cupertino.dart';
 import 'package:veggieseasons/data/veggie.dart';
 import 'package:veggieseasons/screens/details.dart';
 import 'package:veggieseasons/styles.dart';
 
+class FrostyBackground extends StatelessWidget {
+  const FrostyBackground({
+    this.color,
+    this.intensity = 25,
+    this.child,
+  });
+
+  final Color color;
+  final double intensity;
+  final Widget child;
+
+  @override
+  Widget build(BuildContext context) {
+    return ClipRect(
+      child: BackdropFilter(
+        filter: ImageFilter.blur(sigmaX: intensity, sigmaY: intensity),
+        child: DecoratedBox(
+          decoration: BoxDecoration(
+            color: color,
+          ),
+          child: child,
+        ),
+      ),
+    );
+  }
+}
+
 /// A Card-like Widget that responds to tap events by animating changes to its
 /// elevation and invoking an optional [onPressed] callback.
 class PressableCard extends StatefulWidget {
   const PressableCard({
     @required this.child,
-    this.borderRadius = const BorderRadius.all(Radius.circular(10.0)),
-    this.upElevation = 2.0,
-    this.downElevation = 0.0,
+    this.borderRadius = const BorderRadius.all(Radius.circular(5)),
+    this.upElevation = 2,
+    this.downElevation = 0,
     this.shadowColor = CupertinoColors.black,
     this.duration = const Duration(milliseconds: 100),
     this.onPressed,
@@ -89,12 +118,10 @@ class VeggieCard extends StatelessWidget {
   final bool isPreferredCategory;
 
   Widget _buildDetails() {
-    return DecoratedBox(
-      decoration: BoxDecoration(
-        color: veggie.accentColor,
-      ),
+    return FrostyBackground(
+      color: Color(0x90ffffff),
       child: Padding(
-        padding: const EdgeInsets.all(16.0),
+        padding: const EdgeInsets.all(16),
         child: Column(
           crossAxisAlignment: CrossAxisAlignment.start,
           children: <Widget>[
@@ -126,7 +153,7 @@ class VeggieCard extends StatelessWidget {
           Semantics(
             label: 'A card background featuring ${veggie.name}',
             child: Container(
-              height: isInSeason ? 350 : 150,
+              height: isInSeason ? 300 : 150,
               decoration: BoxDecoration(
                 image: DecorationImage(
                   fit: BoxFit.cover,
@@ -140,9 +167,9 @@ class VeggieCard extends StatelessWidget {
             ),
           ),
           Positioned(
-            bottom: 0.0,
-            left: 0.0,
-            right: 0.0,
+            bottom: 0,
+            left: 0,
+            right: 0,
             child: _buildDetails(),
           ),
         ],
diff --git a/veggieseasons/lib/widgets/veggie_headline.dart b/veggieseasons/lib/widgets/veggie_headline.dart
index 996b4694b..9d0847320 100644
--- a/veggieseasons/lib/widgets/veggie_headline.dart
+++ b/veggieseasons/lib/widgets/veggie_headline.dart
@@ -7,6 +7,39 @@ import 'package:veggieseasons/data/veggie.dart';
 import 'package:veggieseasons/screens/details.dart';
 import 'package:veggieseasons/styles.dart';
 
+class ZoomClipAssetImage extends StatelessWidget {
+  const ZoomClipAssetImage(
+      {@required this.zoom,
+      this.height,
+      this.width,
+      @required this.imageAsset});
+
+  final double zoom;
+  final double height;
+  final double width;
+  final String imageAsset;
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      height: height,
+      width: width,
+      alignment: Alignment.center,
+      child: ClipRRect(
+        borderRadius: BorderRadius.circular(10),
+        child: OverflowBox(
+          maxHeight: height * zoom,
+          maxWidth: width * zoom,
+          child: Image.asset(
+            imageAsset,
+            fit: BoxFit.fill,
+          ),
+        ),
+      ),
+    );
+  }
+}
+
 class VeggieHeadline extends StatelessWidget {
   final Veggie veggie;
 
@@ -16,14 +49,14 @@ class VeggieHeadline extends StatelessWidget {
     List<Widget> widgets = <Widget>[];
 
     for (Season season in seasons) {
-      widgets.add(SizedBox(width: 4.0));
+      widgets.add(SizedBox(width: 4));
       widgets.add(
         Container(
-          height: 10.0,
-          width: 10.0,
+          height: 10,
+          width: 10,
           decoration: BoxDecoration(
             color: Styles.seasonColors[season],
-            borderRadius: BorderRadius.circular(5.0),
+            borderRadius: BorderRadius.circular(5),
           ),
         ),
       );
@@ -42,31 +75,28 @@ class VeggieHeadline extends StatelessWidget {
       child: Row(
         crossAxisAlignment: CrossAxisAlignment.start,
         children: [
-          SizedBox(
-            width: 80.0,
-            height: 80.0,
-            child: ClipRRect(
-              borderRadius: BorderRadius.circular(10.0),
-              child: Image.asset(
-                veggie.imageAssetPath,
-                semanticLabel: 'An icon showing ${veggie.name}',
-                fit: BoxFit.fitWidth,
-              ),
-            ),
+          ZoomClipAssetImage(
+            imageAsset: veggie.imageAssetPath,
+            zoom: 2.4,
+            height: 72,
+            width: 72,
           ),
-          SizedBox(width: 8.0),
+          SizedBox(width: 8),
           Flexible(
             child: Column(
               mainAxisAlignment: MainAxisAlignment.start,
               crossAxisAlignment: CrossAxisAlignment.start,
               children: [
                 Row(
-                  children: <Widget>[
+                  children: [
                     Text(veggie.name, style: Styles.headlineName),
-                  ]..addAll(_buildSeasonDots(veggie.seasons)),
+                    ..._buildSeasonDots(veggie.seasons),
+                  ],
+                ),
+                Text(
+                  veggie.shortDescription,
+                  style: Styles.headlineDescription,
                 ),
-                Text(veggie.shortDescription,
-                    style: Styles.headlineDescription),
               ],
             ),
           )
diff --git a/veggieseasons/pubspec.lock b/veggieseasons/pubspec.lock
index 8ebe58210..f0a1d0356 100644
--- a/veggieseasons/pubspec.lock
+++ b/veggieseasons/pubspec.lock
@@ -21,7 +21,7 @@ packages:
       name: async
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.8"
+    version: "2.1.0"
   boolean_selector:
     dependency: transitive
     description:
@@ -117,7 +117,7 @@ packages:
       name: matcher
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.12.3+1"
+    version: "0.12.5"
   meta:
     dependency: transitive
     description:
@@ -138,7 +138,7 @@ packages:
       name: pedantic
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.4.0"
+    version: "1.5.0"
   petitparser:
     dependency: transitive
     description:
@@ -152,7 +152,7 @@ packages:
       name: quiver
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "2.0.1"
+    version: "2.0.2"
   scoped_model:
     dependency: "direct main"
     description:
@@ -178,7 +178,7 @@ packages:
       name: source_span
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.5.4"
+    version: "1.5.5"
   stack_trace:
     dependency: transitive
     description:
@@ -192,7 +192,7 @@ packages:
       name: stream_channel
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "1.6.8"
+    version: "2.0.0"
   string_scanner:
     dependency: transitive
     description:
@@ -213,7 +213,7 @@ packages:
       name: test_api
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.2.2"
+    version: "0.2.4"
   typed_data:
     dependency: transitive
     description:
@@ -243,5 +243,5 @@ packages:
     source: hosted
     version: "2.1.15"
 sdks:
-  dart: ">=2.1.0 <3.0.0"
+  dart: ">=2.3.0-dev <3.0.0"
   flutter: ">=0.1.4 <2.0.0"
diff --git a/veggieseasons/pubspec.yaml b/veggieseasons/pubspec.yaml
index b1b576b04..4fb057ee5 100644
--- a/veggieseasons/pubspec.yaml
+++ b/veggieseasons/pubspec.yaml
@@ -4,7 +4,7 @@ description: An iOS app that shows the fruits and veggies currently in season.
 version: 1.0.0+1
 
 environment:
-  sdk: ">=2.1.0 <3.0.0"
+  sdk: ">=2.3.0-dev <3.0.0"
 
 dependencies:
   flutter: