Mobile · 2025
Melodify
A small Spotify-style Android app: a catalog, playback, and favorites kept on the phone.
Melodify media, 2 items. Use the arrow keys to move.
Illustration. Not a screenshot of the app.
I built Melodify as a small Spotify-style Android app: a catalog to browse, a track to play, and a way to keep the songs I like on the phone.
The problem
A music app that only streams is a music app that stops when the account does. I wanted the browsing, the playback, and the favorites without a streaming login behind them. The catalog still had to feel like a catalog: something you move through, not a single file picker.
The person it frustrates is anyone who just wants to hear the track and save it. A favorites list that lives only on a server is gone when the request fails. A player that dies when you leave the screen is not a player. It was worth building the small version of that loop on the device.
How I built it
The app is Kotlin 1.7 and Android Jetpack. The UI is Jetpack Compose, with a bottom navigation bar so the catalog, the player, and the favorites are three places you can actually reach. Fragments and Navigation are how those places are wired. The structure is MVVM, so the screen is not the thing that owns the catalog.
The catalog comes from a mock REST API, JSON-Server, called through Retrofit. I did not want a fake list hardcoded in the composable, because the screen should be the thing that renders a response. Retrofit is the client. A real streaming service was not the point of the app.
Favorites are the part that has to survive. Room caches them on the phone, so a song I marked stays marked without another round trip. Playback is Google ExoPlayer, one player for the app rather than a player that restarts every time the screen changes. Coil loads the images. Hilt constructs the pieces. Ktor is in the project alongside Retrofit.
Room is why the favorites are local, and ExoPlayer is why playback is one object instead of a button that happens to make noise. The mock API is why the catalog can change without a new build of the screens.
Challenges and what I learned
A catalog, a player, and a favorite are three lifetimes. The catalog can come from JSON-Server and disappear. The player has to keep going while you move between the bottom-nav destinations. The favorite has to be in Room, or it was never really saved. Putting those three on one phone, with MVVM so the screen does not own all three, was the actual shape of the app.

Let's talk ↗









