“30 Days Of Flutter” with FlutLab: Code Party 10

Myroslava Drobnych
7 min readFeb 24, 2021

The team of the #30DaysOfFlutter event tries to make every Live Stream useful and interesting. Great Flutter Developer Jeroen Meijer (Jay) is an integral part of this team. Jay can hold the audience’s attention by a simple session of live-coding. His “Rocket Guide” App will become mainstream among Flutter enthusiasts soon. Join us to take part in an exciting journey that will definitely extend your knowledge in Flutter.

You have 3 options here to get to speed with our current project:

  1. Get “Rocket Guide” — Part 1 from FlutLab Widget Bay. Click the “Fork to FlutLab IDE” button, and the project will appear in your profile.

2. Get “Rocket Guide” — Part 1 from GitHub https://github.com/mdrobnych/rocket_guide_part_1 . This repo is a replica of the original code from FlutterCommunity GitHub

3. Start from scratch:

No matter how you started your journey, you will end up with a working “Rocket Guide” project. Click the “Build Project” button to run it. You can click on one of the rockets inside the Web Emulator to see “Rocket Guide” in action.

I hope you want to continue our flight. Let’s go …

  1. Open main.dart and copy this link https://api.spacexdata.com/v4/rockets

2. Open a new tab in the browser and paste the link. You will see the JSON list. This list contains a description of rockets.

3. Go to pubspec.yaml file and add http: ^0.12.2 to the dependencies. This is a composable, Future-based library for making HTTP requests.

4. Open the backend.dart file and add this to imports:

import 'package:http/http.dart' as http;
import
'dart:convert';

5. Add this part to the backend.dart file too (look at the screenshot below) and press Ctrl+S for saving and formatting:

final response = await http.get(url);if (response.statusCode != 200) {
throw Exception(response.reasonPhrase);
}
final body = response.body;
final jsonData = json.decode(body) as List;
final rockets = jsonData.map((jsonMap) {
return Rocket(
id: jsonMap['id'],
name: jsonMap['name'],
description: jsonMap['description'],
active: jsonMap['active'],
boosters: jsonMap['boosters'],
flickrImages: List<String>.from(jsonMap['flickr_images']),
);
}).toList();

6. Replace return const[…]; with return rockets;

7. Press the “Hot Reload” or the “Build Project” button.

8. Wonderful, we’ve got data from API. However, our code looks quite complex. Let’s transfer JSON to the Rocket class.

factory Rocket.fromJson(Map<String, dynamic> json) {
return Rocket(
id: json['id'],
name: json['name'],
description: json['description'],
active: json['active'],
boosters: json['boosters'],
flickrImages: List<String>.from(json['flickr_images']),
);
}

9. Replace final rockets = jsonData.map(…).toList(); with final rockets = jsonData.map((jsonObject) => Rocket.fromJson(jsonObject)).toList();

Click “Hot Reload” to see changes immediately!

10. As you could see, JSON provides us with much more information than we’re showing now. Let’s add more details to the rocket description.

Replace class Rocket (…) with:

class Rocket {
const Rocket({
@required this.id,
@required this.name,
@required this.description,
@required this.active,
@required this.boosters,
@required this.flickrImages,
@required this.firstFlight,
@required this.height,
@required this.diameter,
@required this.mass,
@required this.wikipedia,
});
final String id;
final String name;
final String description;
final bool active;
final int boosters;
final List<String> flickrImages;
final DateTime firstFlight;
final double height;
final double diameter;
final double mass;
final String wikipedia;
factory Rocket.fromJson(Map<String, dynamic> json) {
return Rocket(
id: json['id'],
name: json['name'],
description: json['description'],
active: json['active'],
boosters: json['boosters'],
flickrImages: List<String>.from(json['flickr_images']),
firstFlight: DateTime.parse(json['first_flight']),
height: (json['height']['meters'] as num).toDouble(),
diameter: (json['diameter']['meters'] as num).toDouble(),
mass: (json['mass']['kg'] as num).toDouble(),
wikipedia: json['wikipedia'],
);
}
}

11. Open the rocket_details_screen.dart file and add these lines of code:

Text('${rocket.firstFlight}'),
Text('${rocket.height}'),
Text('${rocket.diameter}'),
Text('${rocket.mass}'),
Text('${rocket.wikipedia}'),

12. Click the “Hot Reload” or “Build Project” button.

13. The description of our rocket is already displayed, but it doesn’t look good. We need to do something about it ;)

Go to pubspec.yaml and add ant_icons: ^1.0.0 package to the dependencies. This is a Flutter package for Ant Icons.

14. Open the theme.dart file. Let’s add dividerTheme and elevatedButtonTheme . Remove all content from the theme.dart file and paste this code:

import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class AppTheme {
static ThemeData light() {
final textTheme = _getTextTheme(brightness: Brightness.light);
return ThemeData(
primaryColor: _primaryColor,
accentColor: _accentColor,
textTheme: textTheme,
primaryTextTheme: textTheme,
dividerTheme: _dividerTheme,
elevatedButtonTheme: _elevatedButtonTheme,
);
}
static ThemeData dark() {
final textTheme = _getTextTheme(brightness: Brightness.dark);

return ThemeData(
brightness: Brightness.dark,
primaryColor: _primaryColor,
accentColor: _accentColor,
textTheme: textTheme,
primaryTextTheme: textTheme,
dividerTheme: _dividerTheme,
elevatedButtonTheme: _elevatedButtonTheme,
);
}
static const _primaryColor = Colors.black;
static const _accentColor = Colors.white;
static const _dividerTheme = DividerThemeData(
indent: 16.0,
space: 0.0,
);
static final _elevatedButtonTheme = ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
primary: _primaryColor,
onPrimary: _accentColor,
),
);
static _getTextTheme({@required Brightness brightness}) {
final themeData = ThemeData(brightness: brightness);

return GoogleFonts.exo2TextTheme(themeData.textTheme).copyWith(
headline1: GoogleFonts.orbitron(),
headline2: GoogleFonts.orbitron(),
headline3: GoogleFonts.orbitron(),
headline4: GoogleFonts.orbitron(),
headline5: GoogleFonts.orbitron(),
headline6: GoogleFonts.orbitron(),
);
}
}

15. Open rocket_details_screen.dart and add this import:

import 'package:ant_icons/ant_icons.dart';

Find ListView(…) in the body of our Scaffold. Change the code inside children[…] with this (look at the screenshot below):

if (rocket.flickrImages.isNotEmpty) _ImageHeader(rocket: rocket),
ListTile(
title: Text(
rocket.name,
style: textTheme.headline6,
),
subtitle: rocket.active ? null : Text('Inactive'),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
rocket.description,
style: textTheme.subtitle1,
),
),

Press the “Build Project” button or “Hot Reload”.

16. Let’s add one more detail:

ListTile(
leading: const Icon(AntIcons.calendar),
title: Text('${rocket.firstFlight}'),
),

Click “Hot Reload”. Wow, an icon appeared on the screen :-)

17. Let’s show more information in the rocket’s description.

const Divider(),
ListTile(
leading: const Icon(AntIcons.column_width),
title: Text('${rocket.diameter} m'),
subtitle: const Text('in diameter'),
),
const Divider(),
ListTile(
leading: const Icon(AntIcons.colum_height),
title: Text('${rocket.height} m'),
subtitle: const Text('in height'),
),
const Divider(),
ListTile(
leading: const Icon(AntIcons.arrow_down),
title: Text('${rocket.mass} kg'),
subtitle: Text('total mass'),
),

Click the “Hot Reload” button. It looks much better now!

18. Let’s introduce some changes to the firstFlight

final Rocket rocket;bool get _hasAlreadyFlown => rocket.firstFlight.isBefore(DateTime.now());int get _daysSinceFirstFlight => rocket.firstFlight.difference(DateTime.now()).abs().inDays;String get _firstFlightLabel {
final date = rocket.firstFlight;
return '${date.year}-${date.month}-${date.day}';
}

19. Now we have to show FirstFlight on the screen. Replace

ListTile(
leading: const Icon(AntIcons.calendar),
title: Text(‘${rocket.firstFlight}’),
),

with this

ListTile(
leading: const Icon(AntIcons.calendar),
title: Text(
_hasAlreadyFlown
? '$_daysSinceFirstFlight days since first flight'
: '$_daysSinceFirstFlight days until first flight',
),
subtitle: Text(
_hasAlreadyFlown
? 'First flew on $_firstFlightLabel'
: 'Scheduled to fly on $_firstFlightLabel',
),
),

Click “Hot Reload”!

20. Let’s add the Wikipedia Button now.

Padding(
padding: const EdgeInsets.all(16.0),
child: SizedBox(
height: 56.0,
child: ElevatedButton(
onPressed: () {},
child: Center(
child: Text('View Wikipedia Article'),
),
),
),
),

21. Open pubspec.yaml and add url_launcher: ^5.7.10 plugin to the dependencies. This is a Flutter plugin for launching a URL in the mobile platform.

Go to rocket_details_screen.dart and import that plugin:

import 'package:url_launcher/url_launcher.dart';

22. Find onPressed{} and add launch(rocket.wikipedia); to it (look at the screenshot below).

23. Press the “Build Project” button. Great! Let’s check the Wikipedia link.

Click the “Link to the web view” icon. Your app will open in the new browser tab.

Click the “View Wikipedia article” button to read an article about the chosen rocket.

If you need more information about the “Rocket Guide” app watch the #30DaysOfFlutter live stream record.

Awesome! You finished the 23th-day of the agenda #30DaysOfFlutter!

Next version of “Rocket Guide”: “30 Days Of Flutter” with FlutLab: Code Party 11

If you’ve stacked with some problems, visit FlutLab Widget Bay and find the source code of this challenge under the 30 Days Of Flutter category. You can just fork this Widget Bay project into your FlutLab account and play with it.
Good luck!

--

--