| Compose (client) | Spring boot (server) |
|---|---|
A simple TV show tracking mobile app. It uses TMDB for all the media.
You can download for $2.99 or host your own. There are currently over 100 people using the app, and I plan to maintain the server forever. There is also an export button in the settings screen.
PRs are welcome.
- Add custom lists
- Sync with Trakt.tv
- Sharing lists (design tbd)
- App-wide setting to show only TV shows or only Movies
- Save movie/show filter selection in user preferences
- Region picker override setting
- Filters in discover screen, eg. by genre
- Watchlist sort by: added, year, name
- Search watchlisted items
- Install java if you haven't already
- Set environment variables:
export BOOT_JWT_PRIVATE_KEY="your_random_key" export BOOT_TMDB_TOKEN="your_tmdb_token" export GOOGLE_APPLICATION_CREDENTIALS="firebase_json_file_for_push_notifications" export BOOT_KEY_DSN_SENTRY=sentry_key export BOOT_DATABASE_USERNAME=your_db_username export BOOT_DATABASE_PASSWORD=your_db_pw export BOOT_DATABASE_URL=jdbc:postgresql://your_db_address export PORT=8080 - Run
./gradlew bootRun - Open http://localhost:8080/ and check if running (should show 403 page)
- Install postgres on your system
- Create a database and run the migrations (./gradlew flywayMigrate)
- Update environment variables to your database credentials
- Run the app again
- Download Android Studio (or the android sdk executable)
- Set the private keys as environment variables:
export ANDROID_KEY_DSN_SENTRY=optional_sentry_key export ANDROID_KEY_POSTHOG=optional_posthog_key export ANDROID_SERVER_URL=ip_of_your_tvnote_api export ANDROID_SERVER_PORT=8080 export ANDROID_OMDB_TOKEN=optional_omdb_token export ANDROID_RAPID_API_IMDB_TOKEN=optional_tapid_api_token - Run
./gradlew assembleDebug - Install the apk on your android device
- Download XCode
- Open the
./opsAppfolder in XCode - Copy Secrets.plist.example into Secrets.plist and fill your keys.
- Run the app on your ios device
You need to have a TMDB API key, you can get one here.
I started this project with two goals:
- Experiment with a Compose Multiplatform app while keeping the experience as native as possible.
- Track the TV shows I watch.
The Android codebase is fairly straightforward, there are two differences from an android-only codebase
- having expect/actual interfaces instead of just
interface. - Using multiplatform libraries over the jvm/android industry standard libraries:
- Ktor instead of Retrofit.
- Landscapist (image loader) instead of coil/glide/etc.
- SQLdelight instead of room.
- Kotlinx serialization instead of Gson.
- Certain compose multiplatform APIs are different than android compose APIs, eg Res.drawable codegen instead of R.drawable cml vectors.
- Sentry was particularly confusing to implement into the 3 builds
The iOS codebase uses SwiftUI for the navigation components because this was the only way to have the native animation when opening a screen. Although I wasn't able to achieve the topbar and navbar native interactions with scrollable content (ie the blur background transition), I'm not super happy with this on iOS, but it's a compose issue.
I've found other quirks with Compose on iOS, such as keyboard responsiveness and rendering delays, but compose-ios is indeed in alpha.
Overall compose multiplatform was definitely time-efficient, but the user experience compromises are significant. If I was to build a production app I would still use Kotlin multiplatform, but consume the view state in swift and build all the iOS UI in SwiftUI to ensure a native UX while still not duplicating most of the codebase.
The only impact to the web project was extracting the API types to a different Gradle module that I can share with the Compose project, which is really nice. With multiple projects I would have had to copy paste these models.







