A modern Android anime browsing application built with Jetpack Compose and implementing an offline-first architecture with local Room caching and network sync via Paging 3 RemoteMediator.
- π¬ Top Anime Browsing β Browse a curated list of top-rated anime with detailed information
- π± Offline-First Architecture β Works seamlessly with or without internet connectivity
- π Automatic Network Sync β Paging 3 RemoteMediator syncs data when connectivity is restored
- πΎ Local Persistence β Room database caches anime data for instant access
- π¨ Modern UI β Built with Jetpack Compose and Material Design 3
- π Type-Safe Navigation β AndroidX Navigation 3 with serializable destinations
- π Dependency Injection β Hilt + Dagger 2 for clean dependency management
- UI Framework: Jetpack Compose + Material Design 3
- Navigation: AndroidX Navigation 3 (type-safe routes with
@Serializabledestinations) - Architecture: MVVM (ViewModel + Repository pattern)
- Networking: Retrofit 3 + OkHttp 5 + KotlinX Serialization
- Data Persistence: Room 2.8 with RemoteMediator for offline-first paging
- Paging: Paging 3 with lazy loading and remote sync
- Image Loading: Coil 3
- Dependency Injection: Hilt + Dagger 2 (KSP code generation)
- Build System: Gradle with Kotlin 2.3.10 + KSP compiler
- Testing: JUnit 4, Espresso, Mockk
API: Jikan API v4 (anime database REST API)
AniFlow follows Clean Architecture principles with three layers:
-
core/data: Data layer containing network requests, local database, repositories, and mappersnetwork/: Retrofit service, DTOs, customApiResult<T>wrapper for error handlinglocal/: Room database, entities, DAOsrepository/: Repository implementations (interface incore/domain)paging/: RemoteMediator for Paging 3 synchronizationdi/: Hilt dependency injection modules
-
core/domain: Domain layer containing business logic and contracts- Models: Pure Kotlin
data classrepresentations of domain entities - Repository interfaces: Defined in domain, implemented in data layer
- Use cases: Business logic independent of UI framework
- Models: Pure Kotlin
feature/anime/: Feature-specific UI and presentation logichome/: Home screen with anime list displaycomponents/: Reusable feature-specific composablesnavigation/: Destinations and navigation graph registration
ui/: Shared UI components and themingnavigation/: Root navigation host configurationtheme/: Material 3 color tokens, typography, shapes
app/src/main/java/com/codeitsolo/aniflow/
βββ core/
β βββ data/ # Data layer
β β βββ network/
β β β βββ service/AnimeService.kt
β β β βββ dto/ # API DTOs
β β β βββ model/ApiResult<T> # Success/Error/Exception wrapper
β β β βββ adapter/ # Retrofit call adapter
β β βββ local/
β β β βββ db/AniFlowDatabase.kt
β β β βββ entity/ # Room entities
β β β βββ dao/ # Data Access Objects
β β βββ repository/ # Repository implementations
β β βββ mapper/ # DTO/Entity β Domain mappers
β β βββ paging/TopAnimeRemoteMediator.kt
β β βββ di/ # Hilt modules
β βββ domain/
β βββ model/ # Domain models
β βββ repository/ # Repository interfaces
βββ feature/
β βββ anime/
β βββ home/ # Home screen
β βββ components/ # Feature composables
β βββ navigation/
βββ ui/
β βββ navigation/AppNavHost.kt
β βββ theme/ # Material 3 tokens
β βββ components/ # Global components
βββ AniFlowApp.kt # @HiltAndroidApp entry
βββ MainActivity.kt # Compose activity host
- Android Studio Jellyfish or newer
- Android SDK 26+ (API 26 - Android 8.0)
- JDK 11 or higher
- Git
-
Clone the repository:
git clone https://github.com/yourusername/AniFlow.git cd AniFlow -
Open in Android Studio:
- File β Open β Select the AniFlow directory
- Let Gradle sync complete
-
(Optional) Configure local.properties:
- Create
local.propertiesin the root directory - Add SDK path:
sdk.dir=/path/to/android/sdk
- Create
./gradlew :app:assembleDebug./gradlew :app:installDebug./gradlew :app:compileDebugKotlin./gradlew :app:assembleRelease./gradlew clean./gradlew :app:testDebugUnitTest./gradlew :app:connectedDebugAndroidTest./gradlew :app:testDebugUnitTest :app:connectedDebugAndroidTest- Local Room database is the source of truth for UI
- RemoteMediator syncs from API on demand (REFRESH, APPEND)
- Pager combines local DB + remote sync into
Flow<PagingData<Anime>>
Custom sealed interface wrapping Retrofit responses:
when (result) {
is ApiSuccess -> { /* handle success */ }
is ApiError -> { /* handle API error */ }
is ApiException -> { /* handle exception */ }
}Destinations are @Serializable data objects, not string routes:
@Serializable
data object Home : NavKey
@Serializable
data object Details : NavKeyHandles pagination with automatic database sync via RemoteMediator.load()
ViewModels expose Flow<PagingData<T>> for composables to consume
- Namespace:
com.codeitsolo.aniflow - Min SDK: 26 (Android 8.0)
- Target SDK: 36 (Android 15)
- Java: Version 11
- Kotlin: 2.3.10
All versions centralized in gradle/libs.versions.toml:
- Reference as
libs.retrofit,libs.room.runtime, etc. - Update in
.tomlfile, not inbuild.gradle.kts
| Issue | Solution |
|---|---|
| Navigation fails to compile | Ensure all destinations extend NavKey and are @Serializable |
| Hilt injection not found | Add @AndroidEntryPoint to Activity, @HiltViewModel to ViewModel |
| RemoteMediator not triggered | Verify it's passed to Pager() with correct pagingSourceFactory |
| Paging shows duplicates | Ensure RemoteMediator uses database.withTransaction{} correctly |
| JSON deserialization fails | Verify DTO field names match API response, check ignoreUnknownKeys |
| KSP cache issues | Run ./gradlew clean then rebuild |
MIT License Β© 2026 CodeItSolo