A modern Android application that catalogs, details, and compares superheroes from the Superhero API. Built using modern Android development practices, Clean Architecture, and Jetpack Compose.
super-hero-app-demo.webm
- Hero Archive Search: Search heroes with a debounced (300ms) query, requiring at least 3 characters. Includes random hero recommendations for initial onboarding.
- Hero Details Screen: Displays comprehensive metadata for a superhero including full power stats, detailed biography, work locations, and relatives.
- Head-to-Head Comparison: Compare the stats of two different superheroes side-by-side using bidirectional comparison bars.
- Offline Support & Caching: All REST requests are cached locally for 7 days using OkHttp network cache (50MB storage), providing excellent offline resilience.
- Shared Element Transitions: Uses Compose Navigation 3 and
SharedTransitionLayoutto animate hero banners smoothly from the archive grid to the detailed page. - Vanguard Kinetic Design System: Harmonious dark mode design utilizing custom typographic styles, custom segmented progress bars, and hexagonal cropping frameworks.
The project implements Clean Architecture with a unidirectional dependency flow. Presentation and Data modules depend inward on the pure-Kotlin Domain module.
graph TD
subgraph Presentation Layer
app[app Module]
feat_archive[features:archive]
feat_compare[features:comparison]
end
subgraph Design System
ds[core:design_system]
end
subgraph Data / Infrastructure Layer
net[core:network]
end
subgraph Core Domain Layer
dom[domain Module]
end
%% Dependency Connections
app --> feat_archive
app --> feat_compare
app --> net
app --> dom
feat_archive --> ds
feat_compare --> ds
feat_archive --> dom
feat_compare --> dom
net --> dom
- Domain Layer has zero framework dependencies. It represents the core business models, repositories, and use cases.
- Data Layer deals with network interfaces, OkHttp caching, and custom interceptors to sanitize API JSON formatting anomalies.
- Presentation Layer uses Jetpack Compose with unidirectional data flow (MVI/MVVM). ViewModels handle state changes and talk exclusively to Domain use cases.
The app is modularized into specialized modules to guarantee separation of concerns:
| Module | Type | Description |
|---|---|---|
:domain |
Pure Kotlin | Domain models (SuperHero, PowerStats, etc.), use cases, and repository interfaces. |
:core:network |
Android Library | API definitions, JSON serialization, SanitizeJsonInterceptor (resolves escaped slash/quote issues), and cache enforcement. |
:core:design_system |
Android Library | Styling, theme (VanguardKineticTheme), colors, typography, shapes, and custom UI views (segmented capability bars). |
:features:archive |
Android Library | Search view models, grid layouts, detailed information pages, and banner transitions. |
:features:comparison |
Android Library | UI layouts and business logic for comparing two heroes. |
:app |
Android Application | Main coordinator, Hilt integration, and route definitions (ScreenRoute). |
- Composite Build (
build-logic): Shared Kotlin DSL compilation configurations are defined underbuild-logicvia precompiled script plugins:android.application.gradle.kts(SDK versions compileSdk = 37, minSdk = 28, targetSdk = 37)android.library.gradle.ktsandroid.compose.gradle.kts
- Version Catalog: Dependencies are centralized inside
gradle/libs.versions.tomlfor modular updates.
Tests are split between local JVM tests and repository fakes:
- Gradle Test Fixtures: The
:domainmodule uses thetestFixturesplugin to shareFakeSuperHeroRepositoryacross downstream test compilation environments. - Coroutine Dispatchers: Unit tests run using JUnit 4 and a custom
MainDispatcherRuleto manage standard coroutines dispatchers under test threads.
- Android Studio Ladybug or newer.
- JDK 21 configured.
- Register and get a token on Superhero API.
- Add your token to the
local.propertiesfile:SUPERHERO_ACCESS_TOKEN=your_token_here
Run the debug application assemble command:
./gradlew assembleDebug