Post Detail

Post #101

Flutter Jour Cinq Part 1

Flutter Jour Cinq

DeliMeals

  • 07:45 - 08:00 : Test de l’application Dépenses en profondeur pour chercher des bugs venant de moi et pas du tutoriel: NONE FOUND
  • 08:00 - 09:15 : Début du Projet DeliMeals
Code jusque là (1)
 1import 'package:delimeals/screens/categories_screen.dart';
 2import 'package:delimeals/screens/category_meals_screen.dart';
 3import 'package:flutter/material.dart';
 4
 5void main() {
 6  runApp(MyApp());
 7}
 8
 9class MyApp extends StatelessWidget {
10  @override
11  Widget build(BuildContext context) {
12    return MaterialApp(
13      title: 'DeliMeals',
14      theme: ThemeData(
15        primarySwatch: Colors.pink,
16        accentColor: Colors.amber,
17        canvasColor: Color.fromRGBO(255, 254, 229, 1),
18        fontFamily: 'Raleway',
19        textTheme: TextTheme(
20          headline6: TextStyle(
21            fontWeight: FontWeight.bold,
22          ),
23        ),
24      ),
25      routes: {
26        '/': (context) => CategoriesScreen(),
27        CategoryMealsScreen.routeName: (context) => CategoryMealsScreen()
28      },
29    );
30  }
31}
32
33class MyHomePage extends StatefulWidget {
34  @override
35  _MyHomePageState createState() => _MyHomePageState();
36}
37
38class _MyHomePageState extends State<MyHomePage> {
39  @override
40  Widget build(BuildContext context) {
41    return Scaffold(
42      appBar: AppBar(
43        title: Text('DeliMeals'),
44      ),
45      body: Center(
46        child: Text('Navigation Time!'),
47      ),
48    );
49  }
50}
 1import 'package:delimeals/dummy_data.dart';
 2import 'package:delimeals/widgets/category_item.dart';
 3import 'package:flutter/material.dart';
 4import 'package:flutter/widgets.dart';
 5
 6class CategoriesScreen extends StatelessWidget {
 7  @override
 8  Widget build(BuildContext context) {
 9    return Scaffold(
10      appBar: AppBar(
11        title: const Text(
12          'DeliMeals',
13        ),
14      ),
15      body: GridView(
16        padding: const EdgeInsets.all(25),
17        children: DUMMY_CATEGORIES
18            .map(
19              (catData) => CategoryItem(
20                catData.id,
21                catData.title,
22                catData.color,
23              ),
24            )
25            .toList(),
26        gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
27          maxCrossAxisExtent: 200,
28          childAspectRatio: 3 / 2,
29          crossAxisSpacing: 20,
30          mainAxisSpacing: 20,
31        ),
32      ),
33    );
34  }
35}
 1import 'package:delimeals/screens/category_meals_screen.dart';
 2import 'package:flutter/material.dart';
 3
 4class CategoryItem extends StatelessWidget {
 5  final String id;
 6  final String title;
 7  final Color color;
 8
 9  CategoryItem(this.id, this.title, this.color);
10
11  void selectCategory(BuildContext context) {
12    Navigator.of(context).pushNamed(
13      CategoryMealsScreen.routeName,
14      arguments: {
15        'id': id,
16        'title': title,
17      },
18    );
19  }
20
21  @override
22  Widget build(BuildContext context) {
23    return InkWell(
24      onTap: () => selectCategory(context),
25      splashColor: Theme.of(context).primaryColor,
26      borderRadius: BorderRadius.circular(15),
27      child: Container(
28        padding: const EdgeInsets.all(15),
29        child: Text(
30          title,
31          style: Theme.of(context).textTheme.headline6,
32        ),
33        decoration: BoxDecoration(
34          gradient: LinearGradient(
35            colors: [
36              color.withOpacity(0.5),
37              color,
38            ],
39            begin: Alignment.topLeft,
40            end: Alignment.bottomRight,
41          ),
42          borderRadius: BorderRadius.circular(15),
43        ),
44      ),
45    );
46  }
47}
 1import 'package:flutter/material.dart';
 2
 3class CategoryMealsScreen extends StatelessWidget {
 4  static const routeName = '/category-meals';
 5
 6  @override
 7  Widget build(BuildContext context) {
 8    final routeArgs =
 9        ModalRoute.of(context).settings.arguments as Map<String, String>;
10
11    final categoryId = routeArgs['id'];
12    final categoryTitle = routeArgs['title'];
13
14    return Scaffold(
15      appBar: AppBar(
16        title: Text(
17          categoryTitle,
18        ),
19      ),
20      body: Center(
21        child: Text(
22          "${'The Recipes For The Category : ' + categoryTitle}",
23        ),
24      ),
25    );
26  }
27}
 1import 'package:flutter/material.dart';
 2
 3class Category {
 4  final String id;
 5  final String title;
 6  final Color color;
 7  const Category({
 8    @required this.id,
 9    @required this.title,
10    this.color = Colors.orange,
11  });
12}   
  • 09:15 - 10:15 : Création de CategoryMealsScreen
Code jusque là (2)
 1import 'package:delimeals/screens/categories_screen.dart';
 2import 'package:delimeals/screens/category_meals_screen.dart';
 3import 'package:flutter/material.dart';
 4
 5void main() {
 6  runApp(MyApp());
 7}
 8
 9class MyApp extends StatelessWidget {
10  @override
11  Widget build(BuildContext context) {
12    return MaterialApp(
13      title: 'DeliMeals',
14      theme: ThemeData(
15        primarySwatch: Colors.pink,
16        accentColor: Colors.amber,
17        canvasColor: Color.fromRGBO(255, 254, 229, 1),
18        fontFamily: 'Raleway',
19        textTheme: TextTheme(
20          headline6: TextStyle(
21            fontWeight: FontWeight.bold,
22          ),
23        ),
24      ),
25      routes: {
26        '/': (context) => CategoriesScreen(),
27        CategoryMealsScreen.routeName: (context) => CategoryMealsScreen()
28      },
29    );
30  }
31}
32
33class MyHomePage extends StatefulWidget {
34  @override
35  _MyHomePageState createState() => _MyHomePageState();
36}
37
38class _MyHomePageState extends State<MyHomePage> {
39  @override
40  Widget build(BuildContext context) {
41    return Scaffold(
42      appBar: AppBar(
43        title: Text('DeliMeals'),
44      ),
45      body: Center(
46        child: Text('Navigation Time!'),
47      ),
48    );
49  }
50}
 1import 'package:delimeals/dummy_data.dart';
 2import 'package:delimeals/widgets/category_item.dart';
 3import 'package:flutter/material.dart';
 4import 'package:flutter/widgets.dart';
 5
 6class CategoriesScreen extends StatelessWidget {
 7  @override
 8  Widget build(BuildContext context) {
 9    return Scaffold(
10      appBar: AppBar(
11        title: const Text(
12          'DeliMeals',
13        ),
14      ),
15      body: GridView(
16        padding: const EdgeInsets.all(25),
17        children: DUMMY_CATEGORIES
18            .map(
19              (catData) => CategoryItem(
20                catData.id,
21                catData.title,
22                catData.color,
23              ),
24            )
25            .toList(),
26        gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
27          maxCrossAxisExtent: 200,
28          childAspectRatio: 3 / 2,
29          crossAxisSpacing: 20,
30          mainAxisSpacing: 20,
31        ),
32      ),
33    );
34  }
35}
 1import 'package:delimeals/screens/category_meals_screen.dart';
 2import 'package:flutter/material.dart';
 3
 4class CategoryItem extends StatelessWidget {
 5  final String id;
 6  final String title;
 7  final Color color;
 8
 9  CategoryItem(this.id, this.title, this.color);
10
11  void selectCategory(BuildContext context) {
12    Navigator.of(context).pushNamed(
13      CategoryMealsScreen.routeName,
14      arguments: {
15        'id': id,
16        'title': title,
17      },
18    );
19  }
20
21  @override
22  Widget build(BuildContext context) {
23    return InkWell(
24      onTap: () => selectCategory(context),
25      splashColor: Theme.of(context).primaryColor,
26      borderRadius: BorderRadius.circular(15),
27      child: Container(
28        padding: const EdgeInsets.all(15),
29        child: Text(
30          title,
31          style: Theme.of(context).textTheme.headline6,
32        ),
33        decoration: BoxDecoration(
34          gradient: LinearGradient(
35            colors: [
36              color.withOpacity(0.5),
37              color,
38            ],
39            begin: Alignment.topLeft,
40            end: Alignment.bottomRight,
41          ),
42          borderRadius: BorderRadius.circular(15),
43        ),
44      ),
45    );
46  }
47}
 1import 'package:delimeals/dummy_data.dart';
 2import 'package:delimeals/widgets/meal_item.dart';
 3import 'package:flutter/material.dart';
 4
 5class CategoryMealsScreen extends StatelessWidget {
 6  static const routeName = '/category-meals';
 7
 8  @override
 9  Widget build(BuildContext context) {
10    final routeArgs =
11        ModalRoute.of(context).settings.arguments as Map<String, String>;
12    final categoryId = routeArgs['id'];
13    final categoryTitle = routeArgs['title'];
14
15    final categoryMeals = DUMMY_MEALS.where((meal) {
16      return meal.categories.contains(categoryId);
17    }).toList();
18
19    return Scaffold(
20      appBar: AppBar(
21        title: Text(
22          categoryTitle,
23        ),
24      ),
25      body: ListView.builder(
26        itemBuilder: (context, index) {
27          return MealItem(
28            title: categoryMeals[index].title,
29            imageUrl: categoryMeals[index].imageUrl,
30            duration: categoryMeals[index].duration,
31            complexity: categoryMeals[index].complexity,
32            affordability: categoryMeals[index].affordability,
33          );
34        },
35        itemCount: categoryMeals.length,
36      ),
37    );
38  }
39}
  1import 'package:delimeals/models/meal.dart';
  2import 'package:flutter/material.dart';
  3
  4class MealItem extends StatelessWidget {
  5  final String title;
  6  final String imageUrl;
  7  final int duration;
  8  final Complexity complexity;
  9  final Affordability affordability;
 10
 11  MealItem({
 12    @required this.title,
 13    @required this.imageUrl,
 14    @required this.duration,
 15    @required this.complexity,
 16    @required this.affordability,
 17  });
 18
 19  String get complexityText {
 20    switch (complexity) {
 21      case Complexity.Simple:
 22        return 'Simple';
 23        break;
 24      case Complexity.Challenging:
 25        return 'Challenging';
 26        break;
 27      case Complexity.Hard:
 28        return 'Hard';
 29        break;
 30      default:
 31        return 'Unknown';
 32    }
 33  }
 34
 35  String get affordabilityText {
 36    switch (affordability) {
 37      case Affordability.Affordable:
 38        return 'Affordable';
 39        break;
 40      case Affordability.Pricey:
 41        return 'Pricey';
 42        break;
 43      case Affordability.Luxurious:
 44        return 'Luxurious';
 45        break;
 46      default:
 47        return 'Unknown';
 48    }
 49  }
 50
 51  void selectMeal() {}
 52
 53  @override
 54  Widget build(BuildContext context) {
 55    return InkWell(
 56      onTap: selectMeal,
 57      child: Card(
 58        shape: RoundedRectangleBorder(
 59          borderRadius: BorderRadius.circular(15),
 60        ),
 61        elevation: 4,
 62        margin: EdgeInsets.all(10),
 63        child: Column(
 64          children: <Widget>[
 65            Stack(
 66              children: <Widget>[
 67                ClipRRect(
 68                  borderRadius: BorderRadius.only(
 69                    topLeft: Radius.circular(15),
 70                    topRight: Radius.circular(15),
 71                  ),
 72                  child: Image.network(
 73                    imageUrl,
 74                    height: 250,
 75                    width: double.infinity,
 76                    fit: BoxFit.cover,
 77                  ),
 78                ),
 79                Positioned(
 80                  bottom: 20,
 81                  right: 10,
 82                  child: Container(
 83                    width: 300,
 84                    color: Colors.black54,
 85                    padding: EdgeInsets.symmetric(
 86                      vertical: 5,
 87                      horizontal: 20,
 88                    ),
 89                    child: Text(
 90                      title,
 91                      style: TextStyle(
 92                        fontSize: 26,
 93                        color: Colors.white,
 94                        fontFamily: 'Raleway',
 95                      ),
 96                      softWrap: true,
 97                      overflow: TextOverflow.fade,
 98                    ),
 99                  ),
100                ),
101              ],
102            ),
103            Padding(
104              padding: EdgeInsets.all(20),
105              child: Row(
106                mainAxisAlignment: MainAxisAlignment.spaceAround,
107                children: <Widget>[
108                  Row(
109                    children: <Widget>[
110                      Icon(Icons.schedule),
111                      SizedBox(width: 6),
112                      Text('$duration min'),
113                    ],
114                  ),
115                  Row(
116                    children: <Widget>[
117                      Icon(Icons.work),
118                      SizedBox(width: 6),
119                      Text(complexityText),
120                    ],
121                  ),
122                  Row(
123                    children: <Widget>[
124                      Icon(Icons.attach_money),
125                      SizedBox(width: 6),
126                      Text(affordabilityText)
127                    ],
128                  )
129                ],
130              ),
131            ),
132          ],
133        ),
134      ),
135    );
136  }
137}
 1import 'package:flutter/foundation.dart';
 2
 3enum Complexity {
 4  Simple,
 5  Challenging,
 6  Hard,
 7}
 8enum Affordability {
 9  Affordable,
10  Pricey,
11  Luxurious,
12}
13
14class Meal {
15  final String id;
16  final List<String> categories;
17  final String title;
18  final String imageUrl;
19  final List<String> ingredients;
20  final List<String> steps;
21  final int duration;
22  final Complexity complexity;
23  final Affordability affordability;
24  final bool isGlutenFree;
25  final bool isLactoseFree;
26  final bool isVegan;
27  final bool isVegetarian;
28  const Meal({
29    @required this.id,
30    @required this.categories,
31    @required this.title,
32    @required this.imageUrl,
33    @required this.ingredients,
34    @required this.steps,
35    @required this.duration,
36    @required this.complexity,
37    @required this.affordability,
38    @required this.isGlutenFree,
39    @required this.isLactoseFree,
40    @required this.isVegan,
41    @required this.isVegetarian,
42  });
43}
  • 10:30 - 11:15 : Création de MealDetailScreen

Code jusque là (3)

 1import 'package:delimeals/screens/categories_screen.dart';
 2import 'package:delimeals/screens/category_meals_screen.dart';
 3import 'package:delimeals/screens/meal_detail_screen.dart';
 4import 'package:flutter/material.dart';
 5
 6void main() {
 7  runApp(MyApp());
 8}
 9
10class MyApp extends StatelessWidget {
11  @override
12  Widget build(BuildContext context) {
13    return MaterialApp(
14      title: 'DeliMeals',
15      theme: ThemeData(
16        primarySwatch: Colors.pink,
17        accentColor: Colors.amber,
18        canvasColor: Color.fromRGBO(255, 254, 229, 1),
19        fontFamily: 'Raleway',
20        textTheme: TextTheme(
21          headline6: TextStyle(
22            fontWeight: FontWeight.bold,
23          ),
24        ),
25      ),
26      routes: {
27        '/': (context) => CategoriesScreen(),
28        CategoryMealsScreen.routeName: (context) => CategoryMealsScreen(),
29        MealDetailScreen.routeName: (context) => MealDetailScreen(),
30      },
31    );
32  }
33}
34
35class MyHomePage extends StatefulWidget {
36  @override
37  _MyHomePageState createState() => _MyHomePageState();
38}
39
40class _MyHomePageState extends State<MyHomePage> {
41  @override
42  Widget build(BuildContext context) {
43    return Scaffold(
44      appBar: AppBar(
45        title: Text('DeliMeals'),
46      ),
47      body: Center(
48        child: Text('Navigation Time!'),
49      ),
50    );
51  }
52}
 1import 'package:delimeals/dummy_data.dart';
 2import 'package:delimeals/widgets/category_item.dart';
 3import 'package:flutter/material.dart';
 4import 'package:flutter/widgets.dart';
 5
 6class CategoriesScreen extends StatelessWidget {
 7  @override
 8  Widget build(BuildContext context) {
 9    return Scaffold(
10      appBar: AppBar(
11        title: const Text(
12          'DeliMeals',
13        ),
14      ),
15      body: GridView(
16        padding: const EdgeInsets.all(25),
17        children: DUMMY_CATEGORIES
18            .map(
19              (catData) => CategoryItem(
20                catData.id,
21                catData.title,
22                catData.color,
23              ),
24            )
25            .toList(),
26        gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
27          maxCrossAxisExtent: 200,
28          childAspectRatio: 3 / 2,
29          crossAxisSpacing: 20,
30          mainAxisSpacing: 20,
31        ),
32      ),
33    );
34  }
35}
 1import 'package:delimeals/screens/category_meals_screen.dart';
 2import 'package:flutter/material.dart';
 3
 4class CategoryItem extends StatelessWidget {
 5  final String id;
 6  final String title;
 7  final Color color;
 8
 9  CategoryItem(this.id, this.title, this.color);
10
11  void selectCategory(BuildContext context) {
12    Navigator.of(context).pushNamed(
13      CategoryMealsScreen.routeName,
14      arguments: {
15        'id': id,
16        'title': title,
17      },
18    );
19  }
20
21  @override
22  Widget build(BuildContext context) {
23    return InkWell(
24      onTap: () => selectCategory(context),
25      splashColor: Theme.of(context).primaryColor,
26      borderRadius: BorderRadius.circular(15),
27      child: Container(
28        padding: const EdgeInsets.all(15),
29        child: Text(
30          title,
31          style: Theme.of(context).textTheme.headline6,
32        ),
33        decoration: BoxDecoration(
34          gradient: LinearGradient(
35            colors: [
36              color.withOpacity(0.5),
37              color,
38            ],
39            begin: Alignment.topLeft,
40            end: Alignment.bottomRight,
41          ),
42          borderRadius: BorderRadius.circular(15),
43        ),
44      ),
45    );
46  }
47}
 1import 'package:delimeals/dummy_data.dart';
 2import 'package:delimeals/widgets/meal_item.dart';
 3import 'package:flutter/material.dart';
 4
 5class CategoryMealsScreen extends StatelessWidget {
 6  static const routeName = '/category-meals';
 7
 8  @override
 9  Widget build(BuildContext context) {
10    final routeArgs =
11        ModalRoute.of(context).settings.arguments as Map<String, String>;
12    final categoryId = routeArgs['id'];
13    final categoryTitle = routeArgs['title'];
14
15    final categoryMeals = DUMMY_MEALS.where((meal) {
16      return meal.categories.contains(categoryId);
17    }).toList();
18
19    return Scaffold(
20      appBar: AppBar(
21        title: Text(
22          categoryTitle,
23        ),
24      ),
25      body: ListView.builder(
26        itemBuilder: (context, index) {
27          return MealItem(
28            id: categoryMeals[index].id,
29            title: categoryMeals[index].title,
30            imageUrl: categoryMeals[index].imageUrl,
31            duration: categoryMeals[index].duration,
32            complexity: categoryMeals[index].complexity,
33            affordability: categoryMeals[index].affordability,
34          );
35        },
36        itemCount: categoryMeals.length,
37      ),
38    );
39  }
40}
  1import 'package:delimeals/models/meal.dart';
  2import 'package:delimeals/screens/meal_detail_screen.dart';
  3import 'package:flutter/material.dart';
  4
  5class MealItem extends StatelessWidget {
  6  final String id;
  7  final String title;
  8  final String imageUrl;
  9  final int duration;
 10  final Complexity complexity;
 11  final Affordability affordability;
 12
 13  MealItem({
 14    @required this.id,
 15    @required this.title,
 16    @required this.imageUrl,
 17    @required this.duration,
 18    @required this.complexity,
 19    @required this.affordability,
 20  });
 21
 22  String get complexityText {
 23    switch (complexity) {
 24      case Complexity.Simple:
 25        return 'Simple';
 26        break;
 27      case Complexity.Challenging:
 28        return 'Challenging';
 29        break;
 30      case Complexity.Hard:
 31        return 'Hard';
 32        break;
 33      default:
 34        return 'Unknown';
 35    }
 36  }
 37
 38  String get affordabilityText {
 39    switch (affordability) {
 40      case Affordability.Affordable:
 41        return 'Affordable';
 42        break;
 43      case Affordability.Pricey:
 44        return 'Pricey';
 45        break;
 46      case Affordability.Luxurious:
 47        return 'Luxurious';
 48        break;
 49      default:
 50        return 'Unknown';
 51    }
 52  }
 53
 54  void selectMeal(BuildContext context) {
 55    Navigator.of(context).pushNamed(MealDetailScreen.routeName, arguments: id);
 56  }
 57
 58  @override
 59  Widget build(BuildContext context) {
 60    return InkWell(
 61      onTap: () => selectMeal(context),
 62      child: Card(
 63        shape: RoundedRectangleBorder(
 64          borderRadius: BorderRadius.circular(15),
 65        ),
 66        elevation: 4,
 67        margin: EdgeInsets.all(10),
 68        child: Column(
 69          children: <Widget>[
 70            Stack(
 71              children: <Widget>[
 72                ClipRRect(
 73                  borderRadius: BorderRadius.only(
 74                    topLeft: Radius.circular(15),
 75                    topRight: Radius.circular(15),
 76                  ),
 77                  child: Image.network(
 78                    imageUrl,
 79                    height: 250,
 80                    width: double.infinity,
 81                    fit: BoxFit.cover,
 82                  ),
 83                ),
 84                Positioned(
 85                  bottom: 20,
 86                  right: 10,
 87                  child: Container(
 88                    width: 300,
 89                    color: Colors.black54,
 90                    padding: EdgeInsets.symmetric(
 91                      vertical: 5,
 92                      horizontal: 20,
 93                    ),
 94                    child: Text(
 95                      title,
 96                      style: TextStyle(
 97                        fontSize: 26,
 98                        color: Colors.white,
 99                        fontFamily: 'Raleway',
100                      ),
101                      softWrap: true,
102                      overflow: TextOverflow.fade,
103                    ),
104                  ),
105                ),
106              ],
107            ),
108            Padding(
109              padding: EdgeInsets.all(20),
110              child: Row(
111                mainAxisAlignment: MainAxisAlignment.spaceAround,
112                children: <Widget>[
113                  Row(
114                    children: <Widget>[
115                      Icon(Icons.schedule),
116                      SizedBox(width: 6),
117                      Text('$duration min'),
118                    ],
119                  ),
120                  Row(
121                    children: <Widget>[
122                      Icon(Icons.work),
123                      SizedBox(width: 6),
124                      Text(complexityText),
125                    ],
126                  ),
127                  Row(
128                    children: <Widget>[
129                      Icon(Icons.attach_money),
130                      SizedBox(width: 6),
131                      Text(affordabilityText)
132                    ],
133                  )
134                ],
135              ),
136            ),
137          ],
138        ),
139      ),
140    );
141  }
142}
 1import 'package:delimeals/dummy_data.dart';
 2import 'package:flutter/material.dart';
 3
 4class MealDetailScreen extends StatelessWidget {
 5  static const routeName = '/meal-detail';
 6
 7  Widget buildSectionTitle(BuildContext context, String text) {
 8    return Container(
 9      margin: EdgeInsets.symmetric(vertical: 10),
10      child: Text(
11        text,
12        style: Theme.of(context).textTheme.headline6,
13      ),
14    );
15  }
16
17  Widget buildContainer({Widget child}) {
18    return Container(
19      decoration: BoxDecoration(
20        color: Colors.white,
21        border: Border.all(color: Colors.grey),
22        borderRadius: BorderRadius.circular(10),
23      ),
24      padding: EdgeInsets.all(10),
25      margin: EdgeInsets.all(10),
26      height: 150,
27      width: 300,
28      child: child,
29    );
30  }
31
32  @override
33  Widget build(BuildContext context) {
34    final mealId = ModalRoute.of(context).settings.arguments as String;
35    final selectedMeal = DUMMY_MEALS.firstWhere((meal) => meal.id == mealId);
36
37    return Scaffold(
38      appBar: AppBar(
39        title: Text('${selectedMeal.title}'),
40      ),
41      body: SingleChildScrollView(
42        child: Column(
43          children: <Widget>[
44            Container(
45              height: 300,
46              width: double.infinity,
47              child: Image.network(
48                selectedMeal.imageUrl,
49                fit: BoxFit.cover,
50              ),
51            ),
52            buildSectionTitle(context, 'Ingredients'),
53            buildContainer(
54              child: ListView.builder(
55                itemBuilder: (context, index) => Card(
56                  color: Theme.of(context).accentColor,
57                  child: Padding(
58                    padding: const EdgeInsets.symmetric(
59                      vertical: 5,
60                      horizontal: 10,
61                    ),
62                    child: Text(selectedMeal.ingredients[index]),
63                  ),
64                ),
65                itemCount: selectedMeal.ingredients.length,
66              ),
67            ),
68            buildSectionTitle(context, 'Steps'),
69            buildContainer(
70              child: ListView.builder(
71                itemBuilder: (context, index) => Column(
72                  children: <Widget>[
73                    ListTile(
74                      leading: CircleAvatar(
75                        child: Text('# ${(index + 1)}'),
76                      ),
77                      title: Text(
78                        selectedMeal.steps[index],
79                      ),
80                    ),
81                    Divider(),
82                  ],
83                ),
84                itemCount: selectedMeal.steps.length,
85              ),
86            ),
87          ],
88        ),
89      ),
90    );
91  }
92}