Thank you for your interest in contributing to CleanSweep! We're excited to have your help in making the app better. This document outlines our guidelines to ensure a smooth and effective collaboration process for everyone.
The best way to contribute is by getting involved in the discussion. All feature proposals and bug reports should start as a GitHub Issue.
- Found a Bug? Open a Bug Report. Please be as detailed as possible, including your device model, Android version, and steps to reproduce the issue.
- Have a Feature Idea? Propose a New Feature. Explain the problem you're trying to solve and how your proposed feature would address it.
Please search the existing issues before creating a new one to avoid duplicates.
To maintain project quality and clarity, we follow a structured development process:
- Proposal (Issue): Every change starts with a GitHub Issue. This is where the problem or feature is defined and discussed. This step prevents wasted effort on a change that might not align with the project's goals.
- Discussion & Approval: The project maintainers will review the issue. For new features, when needed, we will discuss the proposed solution and agree on a high-level plan before any code is written.
- Implementation (Pull Request): Once the plan is approved, you can begin implementation. Create a Pull Request (PR) and link it to the original issue. Please keep PRs focused on a single issue.
To ensure the codebase remains clean, stable, and maintainable, all contributions must adhere to our core architectural principles.
The app is built on a Model-View-ViewModel (MVVM) architecture with a strict UDF pattern. State should flow down from the ViewModel to the UI, and events should flow up from the UI to the ViewModel.
This is a critical, non-negotiable principle for all UI code. To ensure components are reusable, testable, and have clear API contracts, we must avoid passing entire UiState objects to child composables.
Instead, a composable function must only accept the specific parameters it actually needs.
Rationale:
- Reusability & Previewability: A component that accepts simple types (
String,Boolean,() -> Unit) is trivial to reuse anywhere and to preview in Android Studio. - API Clarity: The function's signature becomes a perfect, self-documenting contract of its dependencies.
- Encapsulation: It prevents a child component from accessing or depending on state it has no business knowing about.
Example:
// This component is fragile and hard to reuse because it depends on the entire state.
@Composable
fun MyComponent(uiState: SwiperUiState) {
Text(uiState.currentItem.displayName)
Button(enabled = !uiState.isLoading) { /* ... */ }
}// This component has a clear, reusable, and protected API.
@Composable
fun MyComponent(
displayName: String,
isLoading: Boolean,
onButtonClicked: () -> Unit
) {
Text(displayName)
Button(enabled = !isLoading, onClick = onButtonClicked) { /* ... */ }
}When your changes are ready, please submit a Pull Request with the following:
- A clear title that summarizes the change (e.g.,
[FEAT] Add folder exclusion to duplicate scan). - A description explaining what the change is and why it's being made.
- A link to the GitHub Issue it resolves (e.g.,
Closes #123). - Ensure your code is formatted according to the project's existing style.
Thank you for helping make CleanSweep a better app!