This project follows Android Actual Clean Architecture, a refined version of Clean Architecture optimized for modern Android development with Jetpack Compose.
- Unidirectional Data Flow (UDF): State flows down from Use Cases to the UI; events flow up from the UI to Use Cases.
- State-Driven UI: The UI is a passive reflection of the current State.
- Use Cases as State Managers: Use Cases are not just "single action" classes. They manage the lifecycle of a specific feature's state,
holding the
StateFlowand coordinating business logic. - Executable State: The State object contains both the data to display and the lambdas (actions) the UI can trigger.
- Strict Layer Separation:
- Domain: Pure Kotlin. No Android dependencies. Contains Entities, Repository Interfaces, and Use Cases.
- Data: Implementation of Repositories. Handles Room, Firebase, API calls, and Mappers.
- UI: Jetpack Compose and ViewModels. ViewModels are "skinny," primarily acting as a bridge between the Domain's State and the UI.
The heart of the application.
- Entities: Plain Kotlin objects representing business data (e.g.,
Project,Task). - Repository Interfaces: Define the contracts for data operations.
- Use Cases:
- Maintain the UI state using
MutableStateFlow. - Expose an immutable
StateFlowto the UI. - Contain business logic and coordinate data flow between repositories.
- Example:
CategoriesUseCasemanages the transition between Dashboard, Category, and Project views.
- Maintain the UI state using
Responsible for providing data to the Domain layer.
- Repository Implementations: Concrete classes that decide whether to fetch data from local (Room) or remote (Firebase) sources.
- Data Sources:
- Local: Room DAOs and Entities.
- Remote: Firebase Realtime Database and Auth.
- Mappers: Extension functions to convert between Data Entities and Domain Entities.
The presentation layer.
- Compose Views: Stateless composables that receive a
Stateobject and render the UI. - ViewModels:
- Inject Use Cases.
- Expose the Use Case's
StateFlow. - Survive configuration changes.
- Navigation: Uses Navigation Compose, driven by state changes in the Use Case.
- Initialization: The
ViewModelis created and gets theStateFlowfrom theUseCase. - Observation: The Composable UI collects the
StateFlowas a Compose State. - Action: The user interacts with the UI (e.g., clicks "Add Project").
- Event: The UI calls a lambda provided in the current
Stateobject (e.g.,state.onAddProject(...)). - Logic: The
UseCasereceives the call, performs business logic, updates theRepository, and updates theMutableStateFlow. - Update: The UI automatically recomposes with the new
State.
- Dependency Injection: Hilt
- Concurrency: Coroutines & Flow
- Local Database: Room
- Cloud Backend: Firebase (Auth & Realtime Database)
- UI: Jetpack Compose with Material 3
- Testing: JUnit, MockK, Turbine (for Flow testing)