A Movie & TV Show discovery app for Android, consuming the TMDB API. Designed to demonstrate production-quality architecture, comprehensive testing, and polished UX patterns.
🔗 Also check out PokemonDbFlutter — a similar project modularised by layer instead of by feature.
| Concern | Library |
|---|---|
| State management | StateFlow / ViewModel |
| Networking | Retrofit 2.11, OkHttp 4.12 |
| Local cache | Room 2.6 |
| Image loading | Coil 3 (OkHttp engine) |
| DI | Hilt 2.54 |
| Pagination | Paging 3 |
| Navigation | Navigation Compose 2.8 |
| Async | Kotlin Coroutines 1.9 |
| Testing | JUnit 4, Mockito, MockWebServer, Turbine |
The project is modularised by feature following Clean Architecture principles. Each feature module enforces strict dependency boundaries between layers.
┌──────────────────────────────────────────┐
│ ui │ Jetpack Compose screens & components
├──────────────────────────────────────────┤
│ presentation │ ViewModel, StateFlow UI state
├──────────────────────────────────────────┤
│ domain │ Use Cases, Entity Models (pure Kotlin)
├──────────────────────────────────────────┤
│ repository │ Coordinates Data & Local sources
├─────────────────────┬────────────────────┤
│ data │ local │ Retrofit (REST API) │ Room (cache)
└─────────────────────┴────────────────────┘
- ui — Jetpack Compose screens and components. No business logic.
- presentation — ViewModel exposing
StateFlowUI state. No Android UI dependencies. - domain — Pure Kotlin. Contains use cases and entity models. Zero Android dependencies.
- repository — Orchestrates remote and local sources, handles mapping and error handling.
- data — Fetches data from the TMDB API via Retrofit and maps responses to domain models.
- local — Reads/writes to a Room database for offline caching.
Each feature follows this same layered structure. Shared logic lives in the core and base modules to avoid duplication:
app/ → Entry point, navigation graph, theme
core/
├── data/ → Shared networking utilities & base classes
├── domain/ → Shared domain models & base use case
└── presentation/ → Shared UI state, base ViewModel helpers
feature/
├── popular/
│ ├── base/ → Shared popular-list logic (paging, UI)
│ ├── movies/ → Movies-specific implementation
│ └── tv/ → TV-specific implementation
├── details/
│ ├── base/ → Shared detail screen logic
│ ├── movies/ → Movie detail screen
│ └── tv/ → TV detail screen
└── cast/
├── base/ → Shared cast logic
├── movies/ → Movie cast screen
└── tv/ → TV cast screen
Comprehensive unit tests across every module and layer.
- Domain — use case logic tested in isolation with fakes
- Repository — data-source orchestration tested with Mockito
- Data — Retrofit responses validated against
MockWebServer - Presentation — ViewModel state emissions verified using Turbine + Coroutines Test
- Local — Room DAO queries tested with an in-memory database
Full support for system light and dark themes via Material 3 dynamic theming.
Skeleton shimmer placeholders keep the UI responsive while data is loading.
SubcomposeAsyncImage via Coil + OkHttp provides smooth, flicker-free image loading. A dedicated fallback composable is shown when images are unavailable.
The lists use Paging 3 with LazyVerticalStaggeredGrid to load content incrementally as the user scrolls.
Descriptive error messages are shown when requests fail, with a refresh action to retry.
Subtle audio feedback on interactions using SoundPool.
sound_effects.webm
Content descriptions are applied to all interactive and image elements to support screen readers and assistive technologies. All user-facing strings are defined in strings.xml.




