Transit Departure Board
Build an Android app in Kotlin that shows the next departures from your bus, tram or train stops: save your favorite stops, open one to see the upcoming departures (line, destination and minutes until it leaves), and pull down to refresh. Departures come from a public transit API (or a simple JSON file you host while learning), your saved stops are stored with Room, and the last loaded departures are kept so the app still shows something useful without a connection, clearly marked as not current. It's a good first Android app that uses the internet: you'll learn Jetpack Compose screens, calling an API and parsing JSON, Room for saved data, ViewModels and state, and handling loading, error and offline states.
- Estimate
- ~8.5h
- Steps
- 6
- Completed by
- 0
- Proposed by
- codeseed.app
Jetpack Compose · Room · Ktor or Retrofit
Project roadmap
- 01
Choose the data source
~1hPick a transit API that works for your city (many publish free real-time data), or, to start simply, host a JSON file with stops and departures (for example as a GitHub Gist). Write README.md describing the requests (search stops and departures for a stop) and the JSON fields you use, and the screens (saved stops, search, and departures). Create a Compose project and add Room, kotlinx.serialization and an HTTP client (such as Ktor or Retrofit). Done when: README.md describes the data source and screens.
- 02
Model the data
~1.5hWrite @Serializable data classes for stops and departures, and a repository with functions to search stops and load departures, turning network and parsing errors into a clear error type. Create a Room entity for saved stops (id, name and an optional nickname) and one for the last departures loaded per stop with the time they were fetched. Done when: a unit test parses a saved JSON response, and Room saves a stop.
- 03
Save favorite stops
~1.5hBuild a search screen that finds stops by name and saves one to favorites, and a home screen listing saved stops from a Room Flow, with swipe to delete and an empty state. Done when: stops can be found, saved and removed, and saved stops remain after restarting.
- 04
Show departures
~1.5hBuild a departures screen that loads a stop's departures through a ViewModel, showing a loading state, then each departure's line, destination and minutes until it leaves (Now for under a minute, and a delay in red when the data includes it). Add pull-to-refresh and update the minutes every 30 seconds while the screen is open. Done when: departures appear and refresh for a saved stop.
- 05
Handle errors and offline use
~1.5hWhen loading fails, show the last departures saved in Room with a banner such as Offline, updated 12 minutes ago, removing departures that have already left, and a Retry button. Show a clear message when there's no saved data. Done when: in airplane mode, the app shows the last known departures with the banner instead of an error screen.
- 06
Test it
~1.5hWrite tests: JSON parsing (valid and missing fields), the minutes-until-departure calculation, the ViewModel with a fake repository (loading, success, error and offline fallback), and Room DAO tests. Done when: all tests pass.
Resources
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack