A clean-architecture Android app for exploring GitHub users and repositories with a modern UI and a solid offline-first data layer.
Why: This project demonstrates production-ready Android practices—modularization, dependency injection, caching, pagination, testing, and CI—implemented on top of the public GitHub REST API.
- 🔎 Search GitHub users with input debounce and error handling
- 👤 User details: avatar, bio, followers, following, public repos
- 📴 Offline-first cache & refresh strategy
- Language: Kotlin
- UI: XML (View system) with RecyclerView (Good Hub Views 😉)
- Architecture: Clean Architecture + MVVM (unidirectional data flow)
- DI: Hilt
- Networking: Retrofit + OkHttp + (Moshi)
- Persistence: Room
- Pagination: Paging 3
- Async: Coroutines + Flow
- Image Loading: Glide
- CI: GitHub Actions (build + test)
root
├─ app/ # Presentation layer, DI entry points
└─ core/ # Data + Domain + common utilities
Core layering guideline
app/
├─ detail
├─ di # UseCase modules
├─ home
├─ image_preview
└─ profile
core/
├─ data # DTO, retrofit services, db, repository impl
├─ di
├─ domain # entities, use cases, repository interfaces
├─ ui
└─ utils # helper, etc.
- Uses GitHub REST API v3 (public endpoints).
- Unauthenticated requests are limited to 60 req/hour. For development, set a personal access token to increase the limit.
Create local.properties (or use a Gradle build config / environment variable):
BASE_URL=https://api.github.com/
API_TOKEN=ghp_xxx # optional; if present, send as: Authorization: token <TOKEN>Add an Interceptor to inject the token when present.
- NetworkBoundResource-style flow for list/detail
- Room as single source of truth
- Stale‑While‑Revalidate for fast cold starts
- Paging 3 for infinite scroll of users/repos
[UI] Views/Adapters ─▶ ViewModel (StateFlow)
▲ │
│ ▼
Navigation UseCases (domain)
│
▼
Repository (domain)
│
┌─────────┴─────────┐
▼ ▼
Retrofit Room DB
(remote src) (local src)
Principles
- Immutable UI state (data classes)
- Clear error types (sealed classes)
- Dispatcher injection for testability
- Strict dependency direction: UI → Domain → Data
- Clone
git clone https://github.com/Alfiyansya/GoodHubViews.git
cd GoodHubViews- Configure secrets (optional, for higher rate limits)
- Add
API_KEYtolocal.propertiesor usegradle.properties+BuildConfig.
- Build
./gradlew clean assembleDebug- Run tests
./gradlew test
# Instrumented tests (if any)
./gradlew connectedAndroidTest- Unit tests for use cases & repositories
- Fake/Mock API & DB
- Flow assertions with Turbine
- Robolectric/UI tests (optional)
- Gradle Kotlin DSL (
*.kts) - Optional: Ktlint/Detekt via Gradle plugins
- GitHub Actions workflow under
.github/workflows/triggers on PR and pushes to main - Jobs:
build,test(extend with lint, unit/UITest matrix as needed)
- Never commit tokens or API keys
- Use Gradle secrets/
local.properties/CI variables
- [✅] Release APKs via GitHub Actions
- Advanced filters (location, language)
- Manage & clear user search history
- UI test suite
- Fork and create a feature branch
- Use conventional commit messages
- Open a PR with a clear description and demo
This project is licensed under the MIT License.
- GitHub REST API v3
- Android Jetpack libraries
// Retrofit / OkHttp
implementation("com.squareup.retrofit2:retrofit:2.11.0")
implementation("com.squareup.retrofit2:converter-moshi:2.11.0")
implementation("com.squareup.okhttp3:okhttp:4.12.0")
// Hilt
kapt("com.google.dagger:hilt-compiler:2.52")
implementation("com.google.dagger:hilt-android:2.52")
// Room
implementation("androidx.room:room-runtime:2.6.1")
kapt("androidx.room:room-compiler:2.6.1")
implementation("androidx.room:room-ktx:2.6.1")
// Paging 3
implementation("androidx.paging:paging-runtime-ktx:3.3.2")
// Coroutines
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0")
// Glide
implementation("com.github.bumptech.glide:glide:4.16.0")
kapt("com.github.bumptech.glide:compiler:4.16.0")Replace versions with what you actually use. This section is optional but handy for readers.


