A showcase Android app built with Jetpack Compose and MVVM. Uses a single-activity Compose UI, Room, Hilt, and a clear layered architecture.
- Model: Domain models (
Task,TaskPriority) and data entities (TaskEntity) kept separate. - View: Pure Compose UI; no logic in composables beyond calling ViewModel.
- ViewModel: UI state via
StateFlow, one-way data flow, use cases for business operations.
| Layer | Technology |
|---|---|
| UI | Jetpack Compose, Material 3, Navigation Compose |
| State | StateFlow + collectAsState() |
| DI | Hilt (ViewModel and Repository scoping) |
| Local DB | Room (DAO, DB, migrations-ready) |
| Async | Kotlin Coroutines + Flow |
| Architecture | Repository pattern, Use cases (domain layer) |
- Single source of truth: Repository abstracts data; ViewModels never touch Room/DAO directly.
- Reactive streams:
Flowfrom DAO → Repository → Use case → ViewModel → UI. - Use cases: One responsibility per use case (GetAllTasks, SearchTasks, AddTask, etc.).
- Scoped ViewModels:
hiltViewModel()per Nav graph destination so each screen has correct scope (e.g. detail screen for a specifictaskId). - UI state modeling: Dedicated
*UiStatedata classes (loading, error, content). - Navigation: Type-safe route constants and
NavHostwith arguments (taskId). - Dependency injection: Interface for repository in domain, implementation in data; Hilt modules for DB and DAO.
app/src/main/java/com/showcase/app/
├── data/
│ ├── local/ # Room: entities, DAO, Database
│ └── repository/ # Repository implementations
├── di/ # Hilt modules
├── domain/
│ ├── model/ # Domain models
│ ├── repository/ # Repository interfaces
│ └── usecase/ # Use cases
├── ui/
│ ├── addtask/ # Add task screen + ViewModel
│ ├── navigation/ # Nav routes + NavHost
│ ├── taskdetail/ # Task detail screen + ViewModel
│ ├── tasklist/ # Task list screen + ViewModel
│ └── theme/ # Material 3 theme + typography
├── MainActivity.kt
└── ShowcaseApplication.kt
- Open the project in Android Studio (Hedgehog or newer recommended).
- Let Android Studio create
local.propertieswith your SDK path (or set Settings → Android SDK and note the path). - Sync Gradle and run on an emulator or device (API 26+).
Gradle needs the Android SDK path. Use either ANDROID_HOME or a local.properties file.
Using ANDROID_HOME (no local.properties needed):
# Default SDK path when installed via Android Studio on macOS:
export ANDROID_HOME=$HOME/Library/Android/sdk
# If your SDK is elsewhere, use that path instead (e.g. from Android Studio → Settings → Android SDK).
./gradlew installDebugUsing local.properties (so you don’t set ANDROID_HOME every time):
# Create the file (use your actual SDK path; common on macOS: $HOME/Library/Android/sdk)
echo "sdk.dir=$HOME/Library/Android/sdk" > local.properties
./gradlew installDebugIf you see "SDK location not found", the path in local.properties or ANDROID_HOME is wrong or the SDK isn’t installed. Install the SDK via Android Studio (Tools → SDK Manager) and use the path shown there.
- Task list: Loads from Room, shows priority and completion.
- Search: Reactive search over title/description via Flow.
- Add task: Form with title, description, priority; validation and error state.
- Task detail: View task, toggle complete, delete (with back navigation).
- Persistence: All data stored in Room; survives process death.
- Add RemoteMediator or offline-first with a remote API.
- Add unit tests for ViewModels and use cases.
- Add UI tests with Compose Testing.
- Add saved state for search query (e.g.
SavedStateHandle). - Add exportSchema = true and migration tests for Room.



