Weekend App: TrainFace

From a technical standpoint, my biggest skillset is in iOS development. Nonetheless, it occurred to me last week that I don’t have a terribly recent iOS project to show. As a consultant I wrote a ton of great code that solved my clients’ problems — but all that code stayed with my clients. The SIGILANCE card was my big personal project this year, but for that I was working mostly in JavaCard and Android. I very recently published the latest Bushwick Open Studios app, but even that was maintenance on a codebase I started in 2013. It’s still a solid app; it’s just not something new, and I was feeling the itch this weekend to make something new.

So I made TrainFace, a simple app that displays the status of the New York City subway system in an iPhone app, an Apple Watch app and a custom Apple Watch complication. I spent half of Saturday and half of Sunday on it, and you can check it out on GitHub here.


Screenshot: the TrainFace main interface, listing subway lines and their status. Screenshot: the TrainFace detail interface, showing planned work on the C train Screenshot: the TrainFace main interface as the user rearranges the G train to appear below the L train Screenshot: the TrainFace Apple Watch complication, in the centerpiece of the Modular watch face, showing a table of delays and planned work Screenshot: the TrainFace Apple Watch interface, listing subway lines and their status Screenshot: the TrainFace Apple Watch detail interface, showing delays on the 3 line
Screenshots from the TrainFace app and Apple Watch app.

The rest of this post walks inch by inch through creating the app, linking to commits and showing screenshots at every stage. It’s fun to see how things get made, right?

Note to non-technical readers: a “commit” is sort of like a checkpoint in the process of writing code. I have links to these checkpoints throughout, but you don’t have to click on them; I explain what the code does right here in the post.

2:40 PM: First Commits

Every app has to start somewhere. In this case, the first commit is the most basic of basic iOS apps: a list view and a detail view. That’s not very exciting though, so in the second commit, I add some fake data to make it more interesting.

Work in progress: a bare list showing 1 2 3 4 5 6 7 A C E Work in progress: the same list but with phrases like 'good service' and 'service change' Work in progress: A bare detail page showing planned work on the 7 train
Left: what the app looks like after the first commit. Middle and right: with some fake data.

The next few commits aren’t much more to look at. Since you’ll probably want to prioritize the trains near work and home, I added support for reordering train lines. Also a label telling you when the data was last updated; boring, but necessary. The next commit is fun, though.

4:03 PM: Images and Colors

Given how colorful the screenshots are at the top of the post, you might be surprised to find out that there’s not a single image file embedded in the app. Commit number five adds support for generating subway icons right in the code. The whole shebang is a 57-line method in a category on UIImage. We look up the color of the line based on the MTA style guide, then use Core Graphics to draw the thing ourselves. Later, we’ll use this same method to generate assets for the Apple Watch app.

I’ve always been a huge fan of drawing art in code rather than embedding tons of images; with the explosion of form factors and resolutions, it’s not uncommon to have to embed dozens of PNGs for even a simple app. This app requires icons for 21 subway lines in three resolutions for two devices. Being able to do that with zero assets is a massive win.

Commit number six adds a splash of color to the main view, with color codes for the various levels of frustration a straphanger is likely to encounter. By this commit, the app is starting to look like a real app; all that’s missing is real data.

Work in progress: A list with images for the subway lines: gray circled L; red circled 1, 2 and 3 Work in progress: The list but with more emphasis on the service status: 'Suspended' in red, 'Planned Work' in yellow. The time is 10:23 but the data was updated as 12:52 PM. Screenshot: The list from before but with live data; the time is 10:24 PM and the data was last updated at 10:06 PM.
Left to right: adding images; adding colors; connecting to live data feed (note the timestamp).

With the last commit on Saturday, we move from mock data to real data. In the rightmost screenshot above, the app is connecting to a JSON feed generated right here on my website. It’s based on the MTA service status API, but has some clever logic to parse out the status of individual train lines, and to boil long service advisories down to short, one-sentence summaries. That’s for another blog post, though!

Sunday, 1:49 PM: The Apple Watch app

After getting the app to connect to a live data feed on Saturday, it feels like a step backwards to make an Apple Watch extension filled with fake data. But in a lot of ways, the Apple Watch extension is an app all its own; you have to start from the beginning. In the first commit of the Apple Watch extension, I simulate a bad day at 14th and 6th:

Work in progress: a bare list showing F M and L trains suspended Work in progress: the same list, but with the F train tapped
This interface (left) doesn't do much. When you tap it, it taps (right).

The next commit adds commands to fetch live data and icons; all of a sudden, the app is starting to look like something real:

Screenshot: the list with icons for the train lines and color coded service status for the L, F, M and N lines. Screenshot: the list, but scrolled a bit to reveal the Q line
Scrolling through the list of service status indicators. Useful already!

8:30 PM: Complications

There was a fair amount of sketching out designs for commit number thirteen. A “complication” is fancy word for a custom bit of information you display on the face of your watch. Complications are new to WatchOS 2, and they come in different shapes and sizes, from a tiny icon in the corner to a big centerpiece panel. For the moment, the app only supports one style of complication, the big one, which gives us three lines of text to work with. The app attempts to summarize as much as it can in those three lines:

Screenshot: the apple watch complication selection interface, selecting TrainFace in the modular centerpiece slot Screenshot: the TrainFace Apple Watch complication, in the centerpiece of the Modular watch face, showing planned work on the N Q R A and E trains Screenshot: the TrainFace Apple Watch complication, in the centerpiece of the Modular watch face, showing a service change on the N Q and R trains, as well as planned work on the M C and E trains
Left, selecting the complication. When there is a disruption (middle), the complication displays it in the center line. When there are more (right), the complication discards unnecessary lines to make room.

Known issue: when switching from the two-line to the three-line table, the font weight changes. Not wild about that. Hey, it’s a first draft.

9:25 PM: Last Looks

Rounding out the functionality, it was imperative to implement a detail view for the Apple Watch interface; there’s no sense telling someone that there’s a service change unless you can explain what that service change is.

Screenshot: the TrainFace Apple Watch detail interface, showing planned work on the C line Screenshot: the TrainFace Apple Watch detail interface, showing planned work on the E line Screenshot: the TrainFace Apple Watch detail interface, showing delays on the 3 line
Three different disruptions.

When the MTA publishes disruptions, they publish based on the trunk line that is disrupted; most apps that consume MTA data can only tell you that the ACE is disrupted. Since my feed can parse out disruptions to specific trains on the line, we’re able to show the disruption for the A separately from the disruption for the E. We’re also able to show only the most relevant information to the user; a one-sentence summary of the issue is a huge usability win when you’re glancing at your wrist.

Additional commits later in the evening add support for background refresh and implement refresh logic for the complication, but by 9:25 PM, the weekend app is done.

Closing Thoughts

It’s nice to have a reminder that you’ve still got it. This weekend app reminded me how fun it is to code for iOS, and introduced me to some bleeding-edge features that aren’t even out of beta yet. Is it a polished app? Of course not. But it shows what I’m capable of doing in a couple of days.

Now that the crypto project is launched and out in the world, I’m excited to get back into iOS development. It’s where I live. It’s what I’m great at.