Transit Stop Viewer
Build an iPhone app for checking when the next bus or tram leaves from the stops you use. You search for a stop, save it to your favorites, and tap it to see the upcoming departures (line, destination and minutes until it leaves), loaded from a transit data API with URLSession. Your saved stops are stored on the phone with SwiftData, so they're still there next time. The app shows a loading indicator, handles having no internet connection, and lets you pull down to refresh. It's a good first iOS app: you'll learn SwiftUI screens and navigation, loading JSON from the web with async/await, decoding it with Codable, and saving data with SwiftData.
- Estimate
- ~10h
- Steps
- 6
- Completed by
- 0
- Proposed by
- codeseed.app
SwiftUI · SwiftData · URLSession
Project roadmap
- 01
Choose the data source and model it
~1.5hPick a transit API with a free key or no key, or, to start simply, a JSON file you host yourself (for example a GitHub Gist) with stops and departures. Write down its two requests (search stops, get departures for a stop) in README.md, and create Codable structs matching the JSON. Done when: a sample JSON response decodes into your structs in a unit test.
- 02
Create the saved stops list
~1.5hCreate a SwiftUI app with a SwiftData model SavedStop (stop id, name, and an optional nickname such as Home). The main screen lists saved stops with @Query, and can delete one by swiping. Show a friendly message when the list is empty. Done when: stops added in code appear in the list, and are still there after restarting the app.
- 03
Search and save stops
~2hAdd a search screen with a search field (.searchable) that calls the stop search with URLSession and async/await, waiting until the user stops typing for a moment before searching. Tapping a result saves it (unless it's already saved) and goes back. Done when: searching finds stops, and saving one adds it to the main list.
- 04
Show departures
~2hTapping a saved stop opens a screen that loads its departures and shows each one's line, destination and minutes until departure ("Now" when under a minute). Add pull-to-refresh with .refreshable. Show a loading spinner, an error message with a Retry button when the request fails, and a message when there are no departures. Done when: departures load, refresh, and errors are shown clearly.
- 05
Handle edge cases
~1.5hTest with the phone offline, with a stop that no longer exists, and with a response missing fields, and make sure the app never crashes: show a message instead. Make the minutes count update every 30 seconds while the screen is open. Done when: every one of these cases shows a sensible message instead of crashing.
- 06
Test the app
~1.5hWrite unit tests for decoding the JSON (a normal response and one with missing fields) and for the minutes-until-departure calculation, including departures in the past. Write a short checklist in README.md for testing by hand on a device. Done when: the unit tests pass, and the checklist is complete.
Ready to build this?
Get a GitHub repo and start building. Your AI reviewer checks each step as you go.
Tech stack