A Kotlin Multiplatform app built with Compose Multiplatform that lets you browse, search, and discover movies using The Movie Database (TMDB) API. Runs on Android and iOS from a single shared codebase.
| Feature | Description |
|---|---|
| Browse Movies | Paginated grid of popular, top-rated, upcoming, and now-playing movies |
| Movie Details | Backdrop image, rating, release date, genres, overview, and trailers |
| Search | Debounced search with inline results as you type |
| Wishlist | Add/remove favorites persisted locally with swipe-to-delete |
| Deep Links | Open movies, search, and favorites from external links (Rinku) |
| Theming | Dynamic Material 3 with dark/light mode support |
| Cross-Platform | Shared UI and business logic for Android & iOS |
Android
iOS
| Category | Libraries |
|---|---|
| UI | Compose Multiplatform 1.10.3, Material 3, Navigation Compose |
| Networking | Ktor 3.4.2 (OkHttp / Darwin engines), kotlinx-serialization |
| Image Loading | Coil 3 (ktor3 network engine) |
| Database | Room 2.8.4 with sqlite-bundled |
| Dependency Injection | Koin 4.2.1 (annotations + KSP + Koin Compiler) |
| State Management | Coroutines, StateFlow, MVI pattern (BaseViewModel) |
| Architecture | Clean Architecture (data/domain/feature layers) |
| Logging | Kermit 2.1.0 |
| Deep Links | Rinku 1.6.0 |
| Build Config | BuildKonfig 0.18.0 |
| CI | Bitrise + GitHub Actions |
| Crash Reporting | Firebase Crashlytics |
| Analytics / Performance | Kotzilla 2.0.8 |
| Linting | Detekt 1.23.8 |
| Coverage | Kover 0.9.8 |
| Dependency Audit | Popcorn Guineapig 3.1.7 |
The app follows Clean Architecture with strict module dependency rules enforced by Popcorn Guineapig:
composeApp (UI orchestrator)
│
├── feature:* → depends on domain, designsystem, platform
├── domain → LEAF — pure business logic, no project dependencies
├── data → depends ONLY on domain (implements repository interfaces)
├── designsystem → LEAF — no project dependencies
└── platform → LEAF — no project dependencies
Data flow:
UI (Screen composable)
→ ViewModel (intent → state via StateFlow)
→ UseCase (business logic)
→ Repository interface (domain layer)
→ MoviesDataRepository (data layer)
→ ApiService (Ktor → TMDB API)
→ FavoriteMoviesDAO (Room → SQLite)
| Route | Screen |
|---|---|
/movies |
Main movie grid with category filter tabs |
/details/{movieId} |
Movie detail page |
/search |
Search screen |
/wishlist |
Favorites list |
Deep links via Rinku: movie/{id}, search?query=, favorite
src/
├── composeApp/ # NavHost, DI aggregator, RootApp
├── data/ # ApiService, DTOs, DAOs, DatabaseProvider, Mappers
├── domain/ # Domain models, Repository interfaces, UseCases
├── designsystem/ # Theme, Colors, shared UI (cards, toolbars, icons, AsyncImage)
├── platform/ # Navigation, PagingController, BaseViewModel, Logging, VideoPlayer
├── feature-movies/ # Movie grid with filter tabs + pagination
├── feature-details/ # Movie detail (backdrop, rating, favorite, info)
├── feature-search/ # Debounced search with results
├── feature-wishlist/ # Favorites list with swipe-to-delete
├── androidApp/ # Android entry point (Application, MainActivity)
├── iosApp/ # Xcode project
└── build-logic/ # Convention plugins (KMP, Koin Compiler, Popcorn GP)
- Android Studio (latest stable)
- Xcode (latest stable) — for iOS
- JDK 21
- A TMDB API key (see below)
-
Clone the repository
git clone https://github.com/gabrielbmoro/MovieDB-App.git
-
Open in Android Studio
- File → Open → select the
src/directory
- File → Open → select the
-
Get a TMDB API token
- Create an account at themoviedb.org
- Copy your Bearer token
- Add it to
src/local.properties:MOVIE_DB_API_TOKEN=your_bearer_token_here
-
Run the app
Platform Instructions Android Select the androidApprun configuration in Android Studio and hit RuniOS Open iosApp/iosApp.xcodeprojin Xcode, build, and run on a simulator
Contributions are welcome! Please check the Contributor Covenant Code of Conduct and our contribution guidelines.
- Report issues: GitHub Issues
- Submit PRs: Open a pull request with a clear description of your changes
- Wiki: See the project Wiki for more documentation
This project is licensed under the MIT License — see the license file for details.