I Am Rick (Episode 4): Rick’s Christmas Jams

Learning Flutter with Rick Grimes and some fine music.

Alexandros Baramilis
9 min readDec 28, 2019

Intro

If you haven’t been following the series so far, check out the previous apps I’ve made:

and the Github repo for the series.

If you’re having trouble installing Flutter on macOS Catalina, check out Setting up Flutter on macOS Catalina.

ALERT: Next episodes are out!

And a few words on why I’m doing this, copied and pasted from Episode 2:

One of the best ways for me to learn something is to write about it, so I’m making this series with the notes that I take as I go through App Brewery’s Flutter Bootcamp. Publishing my notes and code also forces me to maintain a high standard and allows me to easily go back to review or update them.

I’m keeping the Rick Grimes theme alive for as long as I can, because I’m really enjoying having Rick on my phone’s home screen and looking at his pretty face every day. 😄 Don’t worry, App Brewery’s bootcamp doesn’t have Rick in it, but I still highly recommend it if you want to learn Flutter.

Rick’s Christmas Jams

Though not a big fan of Christmas, I admit the vibes have gotten to me, so I decided to make a Christmas special for this episode.

App Brewery’s lesson is making a Xylophone app to play music, so I thought I’ll make an app playing Rick’s Christmas playlist. 🎅🏼

While searching for royalty-free Christmas music on freemusicpublicdomain.com, I stumbled upon this great guitarist Jon Sayles and these beautiful renditions of Christmas songs on the classical guitar.

FYI he’s not even a professional guitarist — he says he works software, for IBM!

His music is freely available and you can find more about it on his personal website.

I love the classical guitar and play some myself too, so Jon if you ever read this, thank you, you made my Christmas :)

The setlist goes as follows:

  1. Nutcracker — Dance of the Sugar Plum Fairy
  2. O Holy Night
  3. God Rest Ye Merry Gentlemen
  4. Silent Night
  5. What Child Is This (Greensleeves)
  6. Hark The Herald Angels Sing
  7. O Little Town of Bethlehem
  8. Oh Come Oh Come Emmanuel
  9. O Come All Ye Faithful
  10. (Bonus Track) Away In The Manger

I also included a bonus track at the end from Maya I’leen & Faith Maziarz just because it was beautiful and I wanted to get to 10 tracks :)

I uploaded all the assets here for ease of use, properly attributed, so you can grab them and use them if you want to build this app, or you can choose your own jams!

Oh and if you think I’m getting too soft, you can grab The Walking Dead Playlist (Updated Frequently with quality and dedication. 17k subscribers!) by Garrett Russell, featuring 178 songs spanning 11 hr 29 min!

It’s good stuff.

Flutter packages

Flutter has a good open-source library of packages written by various contributors (or even the Flutter team itself). We can easily incorporate them into our code so we don’t have to reinvent the wheel every time we need to add a new functionality. What’s more, each package has a score based on Popularity, Health and Maintenance to help us filter the best ones.

The plugin chosen for this episode is audioplayers, as it is the same used in the course and it also has a score of 99!

To install it, I’ll go to the Installing tab of audioplayers and follow the instructions there.

  1. I added audioplayers: ^0.13.5 under cupertino_icons: ^0.1.2 under dependencies:
  2. Now if you go to the top of the pubspec.yaml file in Android Studio you can see some Flutter commands. You can click on Packages get to install the package.
  3. Import it at the top of the code in main.dart: import ‘package:audioplayers/audioplayers.dart';

If you want more info about using packages, so you can read some more here.

For the versioning, we’re using caret syntax, which is easily illustrated through an example:

The string ^2.3.5 means “the range of all versions from 2.3.5 to 3.0.0, not including 3.0.0.”

And based on semantic versioning, if the developers of the package are doing their job correctly, you shouldn’t get any backwards incompatible changes this way, because the developers ‘agree’ not to included any breaking changes without incrementing the major version number.

Playing sound

First of all I’m going to clear all the code we had from Episode 3 and start with a fresh StatelessWidget since we don’t need much state in this app.

void main() => runApp(ChristmasJams());class ChristmasJams extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(...);
}
}

In the first line we’re using a Dart Arrow function, which is a shorthand way of writing:

void main() {
runApp(
ChristmasJams()
);
}

Then I’m going to create a new directory called assets and inside it another directory called christmas_jams and add all the tracks in there. Then I’ll update the pubspec.yaml file to include them like:

assets:
- assets/christmas_jams/

By going through the Readme tab of audioplayers, we can see that for local assets, we have to use the AudioCache class.

By reading the full documentation of AudioCache we see that we have to swap our import statement with the following one:

import 'package:audioplayers/audio_cache.dart';

Playing a file is simple. We just have to do:

final player = AudioCache(prefix: 'christmas_jams/');player.play('1_Nutcracker_Dance_of_the_Sugar_Plum_Fairy.mp3');

I passed the ‘christmas_jams/’ prefix to the AudioCache class since I put all the tracks inside the christmas_jams directory, which is inside the assets directory, which is the default directory that AudioCache looks for files into.

Now we just need a trigger for the user to be able to start the music.

For now, just to test it, I’ll add a FlatButton and add the above code inside its onPressed callback function. For the child I’ll just add a simple Text.

body: FlatButton(
onPressed: () {
final player = AudioCache(prefix: 'christmas_jams/');
player.play('1_Nutcracker_Dance_of_the_Sugar_Plum_Fairy.mp3');
},
child: Text('Play the Nutcracker'),
),

Now you should have the button below and when you tap it you should hear the song :)

Who knew that the ‘Walking Dead red’ would turn out so Christmassy!

Adding more tracks

Function parameters

First I’m going to remove the FlatButton that we used for testing and move its onPressed code into a function that we can reuse.

void playTrack(String filename) {
final player = AudioCache(prefix: 'christmas_jams/');
player.play(filename);
}

This is a function that takes the filename as a parameter so we can pass it different filenames.

You can simply call it like:

playTrack('1_Nutcracker_Dance_of_the_Sugar_Plum_Fairy.mp3');

If we had multiple parameters and we wanted to explicitly use the parameter name when calling the function to avoid confusion, we could use curly braces around the parameters when defining the function, like:

void playTrack({String filename}) {
...
}

Now we have to call the function using the parameter name:

playTrack(filename: '1_Nutcracker_Dance_of_the_Sugar_Plum_Fairy.mp3');

The ListView widget

I went ‘Christmas shopping’ through the Widget catalog and found this handy ListView widget that is perfect for what I want to do here.

It’s basically a scrollable list of children.

I added it like:

body: ListView(
children: <Widget>[
FlatButton(
onPressed: () {
playTrack('1_Nutcracker_Dance_of_the_Sugar_Plum_Fairy.mp3');
},
child: Text('1) Nutcracker - Dance of the Sugar Plum Fairy.mp3'),
),
FlatButton(
onPressed: () {
playTrack('2_O_Holy_Night.mp3');
},
child: Text('2) O Holy Night.mp3'),
),
...

And now I got a list of tracks that I can play:

And what’s even better, if we have more items or if we run out of space (ex. in landscape mode), we can scroll through the items in the list.

Scrollable!

Looks good, but our code for creating the buttons is a bit repetitive.

We can make it simpler by abstracting the code for making the buttons inside a function.

FlatButton buildTrack({String filename, String trackName}) {
return FlatButton(
onPressed: () {
playTrack(filename);
},
child: Text(trackName),
);
}

and then call the function to build the buttons like:

body: ListView(
children: <Widget>[
buildTrack(
filename: '1_Nutcracker_Dance_of_the_Sugar_Plum_Fairy.mp3',
trackName: '1) Nutcracker - Dance of the Sugar Plum Fairy.mp3'),
buildTrack(
filename: '2_O_Holy_Night.mp3',
trackName: '2) O Holy Night.mp3'),
buildTrack(
filename: '3_God_Rest_Ye_Merry_Gentlemen.mp3',
trackName: '3) God Rest Ye Merry Gentlemen.mp3'),

which is a bit more readable than before.

It would be even more readable if Flutter allowed me to use the trackName as the filename but it didn’t like it when I tried to do it. 😅

The best thing about this approach is that if we want to make a change to the style of the buttons, we only have to change one function instead of 10 buttons!

Changing style

So now if I want to change the style of the buttons I only have to change the buildTrack function and not every button separately. So I can change the function to this:

Align buildTrack({String filename, String trackName}) {
return Align(
child: FlatButton.icon(
onPressed: () {
playTrack(filename);
},
icon: Icon(Icons.play_circle_filled),
label: Flexible(
child: Text(trackName),
),
),
alignment: Alignment.centerLeft,
);
}

Let’s break this down.

I used the FlatButton.icon() constructor instead, to make a button that has an Icon. For the icon I used the play_circle_filled icon from the Material Icons Library.

For the label I used the Text widget that I had before but wrapped in a Flexible widget so that it wraps instead of overflowing when the text is long.

Then I wrapped the whole FlatButton inside an Align widget, in order to align all the items of ListView to the left, by setting the alignment property of Align to Alignment.centerLeft. I also had to change the return type of the function to Align instead of FlatButton.

Notice that I didn’t have to change anything else inside ListView!

Ok, actually I added some padding to the top by setting its padding property to EdgeInsets.only(top: 16.0).

And I wrapped the whole ListView inside a SafeArea widget so that the items are not hidden under the iPhone’s cameras when it’s in landscape mode.

And here are the final results:

Nice tunes!

and in landscape mode with scrolling enabled:

Smooth!

That’s it for today! Here’s the final code.

There are a number of other things that we can do to turn this into a better player, like stopping the previous track when the user taps on it again or taps on another track, or playing the next track when the previous one is finished… but I’m not trying to make a proper player here.

I just wanted Rick to be able to show his playlist to the world.

I hope you enjoyed his tunes.

Thanks for reading and I wish you a great 2020! ❤️ 🥳

Next episodes are out!

--

--