E-commerce Android app showcasing modern development practices
MVVM β’ Clean Architecture β’ Jetpack Compose β’ Hilt
π Features β’ π Architecture β’ π Tech Stack β’ π¦ Installation
ProductApp is a learning-focused Android application built with Kotlin and Jetpack Compose. This project demonstrates modern Android development best practices, including:
- π― Clean Architecture principles
- π Reactive programming with StateFlow
- π Dependency Injection with Hilt
- π¨ Modern UI with Jetpack Compose
- π REST API consumption
π This is an educational project developed step-by-step with incremental commits and well-documented architectural decisions.
- β Product Listing - Browse products from FakeStore API
- β Image Loading - Efficient image caching with Coil
- β Pull to Refresh - Update product list
- β Error Handling - Graceful error states with retry mechanism
- β Loading States - Smooth UX with loading indicators
- β Material Design 3 - Modern, beautiful UI components
- β Responsive Layout - Adapts to different screen sizes
- β Dark Theme Support - System-based theme switching
- β Smooth Animations - Native Compose animations
- β State Management - Predictable UI states (Loading/Success/Error)
- β Reactive UI - StateFlow-based reactive updates
- β Type-Safe Navigation - Compose Navigation (planned)
- β Offline Support - Room caching (planned)
The project follows a clean, scalable architecture pattern:
βββββββββββββββββββββββββββββββββββββββββββ
β PRESENTATION LAYER β
β (Compose UI + ViewModels) β
βββββββββββββββββββββββββββββββββββββββββββ€
β DOMAIN LAYER β
β (Use Cases - Planned) β
βββββββββββββββββββββββββββββββββββββββββββ€
β DATA LAYER β
β (Repository + Data Sources) β
βββββββββββββββββββββββββββββββββββββββββββ€
β EXTERNAL SERVICES β
β (Retrofit + FakeStore API) β
βββββββββββββββββββββββββββββββββββββββββββ
app/
βββ ui/
β βββ screen/
β β βββ ProductListScreen.kt β Main product screen
β βββ components/
β β βββ ProductCard.kt β Reusable product card
β β βββ LoadingIndicator.kt β Loading state UI
β β βββ ErrorView.kt β Error state UI
β βββ state/
β β βββ UiState.kt β Sealed class for UI states
β βββ viewmodel/
β βββ ProductViewModel.kt β Business logic & state
β
βββ data/
β βββ model/
β β βββ Product.kt β Data models
β βββ repository/
β β βββ ProductRepository.kt β Single source of truth
β βββ remote/
β βββ ApiService.kt β Retrofit API interface
β
βββ di/
βββ NetworkModule.kt β Hilt DI configuration
ββββββββββββ ββββββββββββββββ ββββββββββββββ βββββββββββ
β UI β βββ> β ViewModel β βββ> β Repository β βββ> β API β
β (Compose)β <βββ β (StateFlow) β <βββ β (Single β <βββ β(Retrofit)β
ββββββββββββ ββββββββββββββββ β Source) β βββββββββββ
ββββββββββββββ
- UI observes ViewModel's StateFlow
- ViewModel requests data from Repository
- Repository fetches from API (or cache - future)
- Data flows back as UiState (Loading β Success/Error)
The app uses a sealed class to represent all possible UI states:
sealed class UiState<out T> {
object Loading : UiState<Nothing>()
data class Success<T>(val data: T) : UiState<T>()
data class Error(val message: String) : UiState<Nothing>()
}- β Type-safe - Compiler guarantees all states are handled
- β Predictable - UI always reflects current state
- β Testable - Easy to unit test state transitions
- β Maintainable - Clear separation of concerns
// ViewModel
private val _uiState = MutableStateFlow<UiState<List<Product>>>(UiState.Loading)
val uiState: StateFlow<UiState<List<Product>>> = _uiState.asStateFlow()
// UI (Compose)
val state by viewModel.uiState.collectAsState()
when (state) {
is UiState.Loading -> LoadingIndicator()
is UiState.Success -> ProductList(state.data)
is UiState.Error -> ErrorView(state.message, onRetry = { viewModel.retry() })
}Kotlin: 1.9.0+
βββ Coroutines - Asynchronous programming
βββ Flow/StateFlow - Reactive streams
Android
βββ compileSdk: 34
βββ minSdk: 24 (Android 7.0)
βββ targetSdk: 34Jetpack Compose
βββ Compose UI: 1.5.4
βββ Compose Material3: 1.1.2
βββ Compose Navigation: 2.7.5 (planned)
βββ Compose Runtime
AndroidX
βββ Core KTX: 1.12.0
βββ Lifecycle ViewModel: 2.6.2
βββ Activity Compose: 1.8.1
βββ Lifecycle Runtime: 2.6.2Retrofit: 2.9.0
βββ Converter Gson - JSON parsing
βββ OkHttp - HTTP client
Image Loading
βββ Coil Compose: 2.5.0Hilt: 2.48
βββ Hilt Android
βββ Hilt CompilerFakeStore API
βββ https://fakestoreapi.com
βββ GET /products - List all products
βββ GET /products/{id} - Product details (planned)
# Required versions
- Android Studio: Hedgehog | 2023.1.1 or newer
- JDK: 17 or higher
- Kotlin: 1.9.0+
- Gradle: 8.0+- Clone the repository
git clone https://github.com/elvynedinson/ProductApp.git
cd ProductApp- Open in Android Studio
# File β Open β Select ProductApp folder- Sync Gradle
# Android Studio will automatically sync
# Or manually: File β Sync Project with Gradle Files- Run the app
# Select device/emulator
# Click Run button or Shift+F10# Debug build
./gradlew assembleDebug
# Release build (requires signing config)
./gradlew assembleRelease
# Install on device
./gradlew installDebug- β Single Responsibility - Each class has one clear purpose
- β Dependency Inversion - Depend on abstractions, not implementations
- β Immutability - Data classes are immutable
- β Type Safety - Leveraging Kotlin's type system
- β Separation of Concerns - UI, Business Logic, Data are separated
- β Unidirectional Data Flow - Data flows in one direction
- β Single Source of Truth - Repository pattern
- β Reactive UI - State-driven UI updates
- β Incremental Development - Small, focused commits
- β Descriptive Commits - Clear commit messages
- β Code Comments - Explaining "why", not "what"
- β Kotlin Conventions - Following official style guide
- β
Efficient Recomposition - Using
rememberandderivedStateOf - β Image Caching - Coil handles caching automatically
- β Coroutine Scoping - Proper lifecycle-aware coroutines
- β State Hoisting - Reusable, stateless composables
The project is being built with testability in mind, though tests are not yet implemented.
This project was built following industry best practices and official documentation:
- Android Developer Guides
- Jetpack Compose Documentation
- Kotlin Coroutines Guide
- Clean Architecture by Uncle Bob
- Google's Architecture Samples
This is a personal learning project, but suggestions and feedback are welcome!
If you want to contribute:
- Fork the repository
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
This project is open source and available under the MIT License.
Elvyn Edinson
Android Developer in training π
- GitHub: @elvynedinson
- LinkedIn: Elvyn Edinson
- Email: elvyn.paucar.ponce@gmail.com
- β Kotlin
- β Jetpack Compose
- β MVVM Architecture
- β Clean Architecture Principles
- β Dependency Injection (Hilt)
- β Reactive Programming (Coroutines, Flow)
- β REST API Integration
- β Material Design 3
- FakeStore API for providing the free REST API
- Android Community for excellent documentation and support
- JetBrains for Kotlin and IntelliJ IDEA
- Google for Android and Jetpack libraries
Lines of Code: ~500 (and growing)
Commits: Incremental and descriptive
Architecture: MVVM + Clean Architecture
UI Framework: 100% Jetpack Compose