Skip to content

Adrc95/ComicVineAppSample

Repository files navigation

ComicVineAppSample

ComicVineAppSample is a sample Android application that explores modern Android development around the Comic Vine API.

The project focuses on a small but complete feature set:

  • character listing with pagination
  • character search
  • character detail
  • local favorites
  • light, dark, and automatic theme modes

The codebase is organized as a multi-module project and follows a clean separation between UI, domain, and data concerns.

Table of Contents

  • Overview
  • Features
  • Architecture
  • Modules
  • Tech Stack
  • Data Flow
  • Testing
  • Project Setup
  • Quality Checks

Overview

This app fetches Comic Vine characters from the network, persists them locally with Room, stores UI configuration with DataStore, and exposes everything to the UI using Kotlin Flow.

The current implementation uses an offline-first approach for the main flows:

  • the UI observes Room as the source of truth
  • the repository refreshes data from the API when needed
  • detail data enriches the local cache when long descriptions are missing
  • favorites are updated locally and reflected automatically through Room emissions

Features

  • Browse Comic Vine characters with paginated loading
  • Search characters by name from the current cached list
  • Open a character detail screen with long description fallback
  • Save and remove favorites locally
  • Reactive favorites screen backed by Room Flow
  • Theme switching with light, dark, and follow-system modes
  • Android Splash Screen API integration

Architecture

The app is structured around:

  • MVVM for presentation logic
  • Clean Architecture style boundaries between UI, domain, and data
  • Single Activity + Navigation Component
  • Offline-first repository flows for list, detail, and favorites

At a high level:

  1. The UI collects StateFlow from the ViewModel.
  2. The ViewModel coordinates use cases and maps domain models into display models.
  3. The domain layer defines business models, repositories, and use cases.
  4. The data layer defines repository implementations and datasource contracts.
  5. Infrastructure modules implement those contracts for Room, Retrofit, and DataStore.
  6. Room acts as the local source of truth, while Retrofit refreshes the cache when necessary.

Modules

:app

Android-specific layer containing:

  • Activities and Fragments
  • ViewModels
  • UI display models and mappers
  • application startup and navigation
  • Hilt entry point and app-level composition

:domain

Pure business layer containing:

  • domain models
  • repository contracts
  • use cases
  • failure abstractions

:data

Implementation layer containing:

  • repository implementations
  • datasource contracts
  • repository Hilt bindings

:core:network

Infrastructure module containing:

  • Retrofit services
  • network datasource implementation
  • OkHttp interceptors
  • network-specific mappers
  • Hilt bindings for remote datasource

:core:database

Infrastructure module containing:

  • Room database and DAO
  • local datasource implementation
  • entity mappers
  • Hilt bindings for local character datasource

:core:datastore

Infrastructure module containing:

  • DataStore preferences implementation
  • theme persistence mapping
  • Hilt bindings for local configuration datasource

:testing

Shared test support module containing:

  • test builders for domain and fixture models
  • fake repository implementations for unit tests
  • reusable helpers consumed by feature and core module tests

Tech Stack

  • Kotlin
  • Coroutines and Flow
  • ViewModel
  • Navigation Component with Safe Args
  • Room
  • Retrofit
  • OkHttp
  • Kotlinx Serialization
  • Hilt
  • Arrow Either
  • DataStore
  • Glide
  • Lottie
  • SwipeRevealLayout
  • Detekt
  • JUnit4
  • AndroidX Test
  • MockWebServer

Data Flow

Characters list

  • MainViewModel observes characters through a use case
  • the repository exposes Room data as Flow
  • on first collection, the repository refreshes from the API
  • paginated requests update Room and the UI reacts automatically

Character detail

  • DetailViewModel observes one character from Room
  • if the cached entry does not have the long description, the repository fetches the detail endpoint
  • the local entity is updated and the UI refreshes automatically

Favorites

  • favorites are stored locally in Room
  • the favorites screen observes Flow<List<...>>
  • removing a favorite updates the database and the screen reacts without manual reloads

Module Dependency Direction

The project is organized so dependency direction stays consistent:

  • :app depends on :domain, :data, and the :core:* modules as the Hilt composition root
  • :data depends on :domain
  • :core:network depends on :data and :domain
  • :core:database depends on :data and :domain
  • :core:datastore depends on :data and :domain

This means datasource contracts live in :data, while concrete implementations live in the corresponding :core:* modules.

                +------------------+
                |       :app       |
                | UI + Hilt root   |
                +---------+--------+
                          |
          +---------------+---------------+
          |                               |
          v                               v
   +-------------+                +---------------+
   |   :domain   |                |     :data     |
   | use cases   |<---------------| repos + ports |
   | models      |                +-------+-------+
   +-------------+                        |
                                          |
                    +---------------------+---------------------+
                    |                     |                     |
                    v                     v                     v
          +----------------+    +----------------+    +-----------------+
          | :core:network  |    | :core:database |    | :core:datastore |
          | Retrofit/OkHttp|    | Room           |    | DataStore       |
          +----------------+    +----------------+    +-----------------+

Package Shape

  • app/src/main/java/.../ui: screens, adapters, UI mappers, ViewModels
  • app/src/test/java/...: app unit tests
  • app/src/androidTest/java/...: repository integration tests and test DI
  • domain/src/main/java/...: models, repository interfaces, use cases, failures
  • domain/src/test/java/...: use case unit tests
  • data/src/main/java/.../datasource: datasource contracts
  • data/src/main/java/.../repository: repository implementations
  • core/*/src/main/java/.../di: Hilt modules and bindings
  • core/*/src/main/java/.../datasource: concrete datasource implementations
  • core/*/src/test/java/...: core unit tests
  • core/*/src/androidTest/java/...: Android integration tests where framework components are required
  • testing/src/main/java/...: shared builders and fake repositories

Testing

The project now includes both unit and integration coverage across modules.

Unit tests

  • :domain covers use cases
  • :app covers ViewModels and UI mappers
  • :core:network covers response mapping and remote datasource behavior
  • :core:database covers entity mapping and database utility wrappers
  • :core:datastore covers preference mapping and local configuration persistence

Run all JVM unit tests with:

./gradlew test

Run a specific module, for example:

./gradlew :app:testDebugUnitTest
./gradlew :domain:test
./gradlew :core:network:testDebugUnitTest

Integration tests

  • :app:androidTest verifies repository behavior end to end with Hilt test modules, in-memory Room, test DataStore, and MockWebServer
  • :core:database:androidTest verifies DAO behavior against a real Room database

Run integration tests with:

./gradlew :app:connectedDebugAndroidTest
./gradlew :core:database:connectedDebugAndroidTest

Test support

  • network fixtures live under app/src/androidTest/assets and core/network/src/test/resources
  • the :testing module centralizes builders and fake repositories to keep tests consistent and reduce duplication

Project Setup

Requirements

  • Android Studio with recent Android Gradle Plugin support
  • JDK 17

API Key

This project requires a Comic Vine API key.

Create or update local.properties in the project root with:

COMIC_VINE_API_KEY=<your_api_key>

You can get an API key from:

Build

To compile the app:

./gradlew :app:compileDebugKotlin

Quality Checks

Run Detekt:

./gradlew detekt

Common local verification commands:

./gradlew test
./gradlew :app:connectedDebugAndroidTest
./gradlew :core:database:connectedDebugAndroidTest
./gradlew detekt

About

ComicVineAppSample is a sample Android application that explores modern Android development around the Comic Vine API.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages