ComposeTemplate is a Jetpack Compose template application that follows Clean Architecture and modularization best practices. It simplifies the process of setting up a well-structured Compose application by providing a template with a predefined folder structure. ✨
Report Bug
Request Feature
ComposeTemplate is a Jetpack Compose template application that follows Clean Architecture and modularization best practices. It simplifies the process of setting up a well-structured Compose application by providing a template with a predefined folder structure. ✨
- Kotlin - Modern programming language for Android
- Modern Architecture - UDF Architecture pattern
- Jetpack Compose - Modern UI toolkit
- Material 3 - Material Design 3 components
- Navigation3 - Type-safe navigation library
- Retrofit - HTTP client for Android
- Gson - JSON serialization/deserialization
- Hilt - Dependency injection framework
- Kotlin Coroutines - Asynchronous programming
- Kotlin Serialization - Type-safe serialization
- jUnit - Unit testing framework
- MockK - Mocking library for Kotlin
- Truth - Fluent assertions for Java and Android
The project follows Clean Architecture principles with clear separation of concerns and uses Convention Plugins for build configuration. The project is also modularized by feature.
ComposeTemplate/
├── app/ # Main application module
├── core/ # Core module with shared utilities
│ ├── data/ # Data storage implementations
│ ├── network/ # Network layer utilities
│ └── preferences/ # Shared preferences utilities
├── contract/ # Shared navigation routes and contracts
├── feature/
│ ├── example/ # Example feature module
│ │ ├── data/ # Data layer (repositories, API services)
│ │ ├── domain/ # Domain layer (use cases, business logic)
│ │ ├── navigation/ # Navigation layer (routes, navigation logic)
│ │ └── presentation/ # Presentation layer (UI, ViewModels)
│ ├──...
├── build-logic/ # Build configuration
│ ├── convention/ # Convention plugins
│ │ └── src/main/kotlin/com/ytapps/composetemplate/convention/
│ │ ├── AndroidApplicationConventionPlugin.kt
│ │ ├── AndroidComposeConventionPlugin.kt
│ │ ├── AndroidHiltConventionPlugin.kt
│ │ ├── AndroidLibraryConventionPlugin.kt
│ │ ├── FeatureConventionPlugin.kt
│ │ ├── TestConventionPlugin.kt
│ │ ├── KotlinAndroid.kt
│ │ └── ProjectExtensions.kt
│ └── README.md # Build logic documentation
└── gradle/
└── libs.versions.toml # Version catalog
## Configuration Files
├── gradle.properties # Gradle configuration and API URLs
├── local.properties # Local development properties (gitignored)
├── .gitignore # Git ignore rules
├── initializer.sh # Project initialization script
└── settings.gradle.kts # Gradle settings
This project uses modern Gradle build configuration with Convention Plugins and Version Catalog for maintainable and scalable build logic.
Located in build-logic/convention/, these plugins encapsulate common build configuration:
composetemplate.android.application: Base Android app configuration (SDK versions, Kotlin setup)composetemplate.android.application.compose: Jetpack Compose setup with common dependenciescomposetemplate.android.hilt: Hilt dependency injection configurationcomposetemplate.android.library: Android library module configurationcomposetemplate.test: Common testing dependencies (JUnit, Truth, MockK, Espresso)composetemplate.feature: Base dependencies for feature modules (:core, :contract)
Benefits:
- ✅ Centralized build configuration
- ✅ Reduced duplication across modules (60+ lines eliminated)
- ✅ Type-safe Kotlin DSL
- ✅ Easy to maintain and update
- ✅ Consistent testing setup across all modules
All dependencies and versions are managed in gradle/libs.versions.toml:
[versions]
minSdk = "23"
compileSdk = "36"
targetSdk = "36"
versionCode = "1"
versionName = "1.0.0"
kotlin = "2.2.10"
[libraries]
androidx-core = { module = "androidx.core:core-ktx", version.ref = "androidx-core" }Benefits:
- ✅ Single source of truth for versions
- ✅ Type-safe dependency accessors
- ✅ Easy version updates
- ✅ Shared across all modules
For detailed build configuration documentation, see build-logic/README.md.
- Navigation3 Integration: Uses the latest Navigation3 library with type-safe navigation
- Custom NavigationManager: Flexible navigation management with back stack handling
- Bottom Navigation Bar: Material 3 adaptive bottom navigation bar
- Route-based Navigation: Serializable route objects for type-safe navigation
- Navigation Methods:
navigate()- Navigate to a new screennavigateBack()- Navigate back in the stacknavigateOver()- Navigate over a specific routenavigateToTop()- Navigate to top of stackselectTab()- Select bottom bar tab
- Splash Screen: Initial screen with routing logic
- Login Screen: Authentication screen with login flow
- Home Screen: Main home screen with navigation examples
- Search Screen: Search functionality screen
- Profile Screen: User profile screen
- List Screen: List view example
- Detail Screen: Detail view example
- Retrofit Integration: Configured with Gson converter
- DefaultInterceptor: Automatic token injection and refresh token handling
- Adds Authorization header to all requests
- Handles 401 Unauthorized responses
- Automatic token refresh on authentication failure
- BaseRepository: Safe API call wrapper with error handling
safeCall()function for error-safe network calls- Returns
Result<T>sealed class (Success/Error)
- PreferencesManager: Local data storage using SharedPreferences
- Token management (access token, token type)
- User credentials storage
- User session management
- Repository Pattern: Clean separation between data sources
- Mapper Pattern: Data model transformation between layers
- Hilt Integration: Full dependency injection setup
- ProviderModule: Provides network components (Retrofit, OkHttp, Gson)
- BinderModule: Binds interfaces to implementations
- Singleton Components: Properly scoped dependencies
- Unit Tests: Comprehensive test coverage with JUnit
- MockK: Mocking framework for Kotlin
- Truth: Fluent assertions library
- Test Examples:
- Repository tests
- ViewModel tests
- Mapper tests
- Use case tests
- Base repository tests
- Material 3 Design: Latest Material Design components
- Custom Theme: Themed colors and typography
- Adaptive Navigation: Material 3 adaptive navigation components
- Compose UI: Fully built with Jetpack Compose
- Header and Refresh Token Interceptor: Automatic token management with refresh token support
- Safe Network Calls: Error-handled network function
- Flexible Navigation Structure: Custom navigation manager with Navigation3
- Preferences Manager: Local data storage with SharedPreferences
- Auth Flow: Complete authentication flow with token management
- Clean Architecture: Complete separation of Data, Domain, and Presentation layers
- Unit Tests: All structures tested with JUnit and MockK
- End-to-End Examples: Complete examples for all architecture layers
- Android Studio Hedgehog (2023.1.1) or later
- JDK 17 or later
- Android SDK with API level 23 (Android 6.0) or higher
- Gradle 8.13.0 or later
- Clone the repository
git clone https://github.com/mustafayigitt/ComposeTemplate.git
cd ComposeTemplate- Configure Base URLs
Create or update gradle.properties in the project root with your API base URLs:
BASE_URL_DEBUG=https://your-debug-api-url.com/
BASE_URL=https://your-production-api-url.com/- Run the Initializer Script
To create a new project using this template:
chmod +x initializer.sh
./initializer.shThe script provides an interactive setup with:
- Input Validation: Ensures valid application ID and name formats
- Configuration Summary: Shows all settings before proceeding
- Confirmation Prompt: Asks for confirmation before creating the project
When prompted:
- Enter your
applicationId(e.g.,com.example.myapp)- Must be lowercase with at least 2 segments (e.g.,
com.example) - Only letters, numbers, and underscores allowed
- Must be lowercase with at least 2 segments (e.g.,
- Enter your
applicationName(e.g.,MyApp)- Must start with a letter
- Only alphanumeric characters allowed
The script will:
- ✅ Validate your inputs
- ✅ Create a new project directory with your application name
- ✅ Restructure all source directories (app + build-logic)
- ✅ Replace all package names and references
- ✅ Update convention plugin package names and IDs
- ✅ Generate a proper
.gitignorefile - ✅ Initialize a new git repository with an initial commit
- ✅ Clean up template-specific files
- ✅ Provide clear next steps
- Open the Project
Open the newly created project in Android Studio:
- If using the template directly: Open
ComposeTemplatefolder - If using initializer: Open the created project folder (e.g.,
../MyApp)
- Sync and Build
- Sync Gradle files
- Build the project (Build > Make Project)
- Run on an emulator or device
The project uses build variants for different environments:
- Debug: Uses
BASE_URL_DEBUGfromgradle.properties - Release: Uses
BASE_URLfromgradle.properties
- minSdk: 23 (Android 6.0)
- targetSdk: 36
- compileSdk: 36
- Java Version: 17
- Kotlin Version: 2.2.10
All dependencies are managed through gradle/libs.versions.toml using Version Catalogs. Key dependencies include:
- Compose BOM: 2024.06.00
- Hilt: 2.57.1
- Retrofit: 2.11.0
- Navigation3: 1.0.0
- Kotlin: 2.2.10
- Kotlin Serialization: 2.1.21
- Kotlin Coroutines: 1.7.3
- Create Route Object (in
feature/yourfeature/navigation/YourFeatureRoute.kt):
@Serializable
data object YourFeatureRoute : INavigationItem {
override val route: String = "route_your_feature"
}- Create Screen Provider (in
feature/yourfeature/presentation/YourFeatureScreenProvider.kt):
class YourFeatureScreenProvider @Inject constructor() : IScreenProvider {
@Composable
override fun provideScreen(
route: INavigationItem,
navigationManager: INavigationManager
): Boolean {
return when (route) {
is YourFeatureRoute -> {
YourFeatureScreen(navigationManager)
true
}
else -> false
}
}
}- Create Screen Composable (in
feature/yourfeature/presentation/YourFeatureScreen.kt):
@Composable
fun YourFeatureScreen(
navigationManager: INavigationManager,
) {
// Your UI implementation
}- Register Screen Provider in your DI module.
- Create API Service (in
feature/yourfeature/data/remote/YourService.kt):
interface YourService {
@POST("your-endpoint")
suspend fun yourMethod(@Body request: YourRequestModel): Response<YourResponseModel>
}- Create Repository (in
feature/yourfeature/data/repository/YourRepository.kt):
class YourRepository @Inject constructor(
private val yourService: YourService
) : BaseRepository(), IYourRepository {
override suspend fun yourMethod(): Result<YourResponseModel> {
return safeCall {
yourService.yourMethod(YourRequestModel())
}
}
}- Use in ViewModel:
@HiltViewModel
class YourViewModel @Inject constructor(
private val repository: IYourRepository
) : ViewModel() {
fun loadData() {
viewModelScope.launch {
when (val result = repository.yourMethod()) {
is Result.Success -> {
// Handle success
}
is Result.Error -> {
// Handle error
}
}
}
}
}// Navigate to a new screen
navigationManager.navigate(YourFeature)
// Navigate back
navigationManager.navigateBack()
// Navigate over a specific route
navigationManager.navigateOver(NewRoute, OldRoute)
// Navigate to top of stack
navigationManager.navigateToTop(Home)// In your repository or use case
@Inject constructor(
private val prefs: IPreferencesManager
) {
// Save data
prefs.saveString("key", "value")
// Get data
val value = prefs.getString("key", "default")
// Save credentials (for auth)
prefs.saveCredentials(authResponse)
}This project follows Clean Architecture principles with three main layers:
- Responsibility: Data sources (remote API, local storage)
- Components: Repositories, Data Models, API Services, Local Storage
- Location:
feature/*/data/package
- Responsibility: Business logic and use cases
- Components: Use Cases, Domain Models, Repository Interfaces, Mappers
- Location:
feature/*/domain/package
- Responsibility: UI and user interactions
- Components: ViewModels, UI States, Composable Screens, Routes
- Location:
feature/*/presentation/package
- Responsibility: Shared navigation routes and UI contracts
- Components: Main route definitions, Bottom bar item definitions, Navigation contracts
- Location:
contract/package
- Responsibility: Shared utilities and base classes
- Components: Base classes, Navigation, DI modules, Theme, API utilities
- Location:
core/package
The project includes comprehensive unit tests. Run tests with:
./gradlew test- Repository Tests: Test data layer logic
- ViewModel Tests: Test presentation layer logic
- Mapper Tests: Test data transformation
- Use Case Tests: Test business logic
Example test:
@Test
fun `test login success`() = runBlocking {
// Given
val authRequestModel = AuthRequestModel(email = "email", password = "password")
val authResponseModel = AuthResponseModel(
accessToken = "token",
refreshToken = "refresh",
tokenType = "Bearer",
expiresIn = "3600"
)
coEvery { authService.login(authRequestModel) } returns Response.success(authResponseModel)
// When
val result = authRepository.login("email", "password")
// Then
assertThat(result).isInstanceOf(Result.Success::class.java)
coVerify { preferencesManager.setAccessToken("token") }
}Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated.
- If you have suggestions for adding or removing projects, feel free to open an issue to discuss it, or directly create a pull request after you edit the README.md file with necessary changes.
- Please make sure you check your spelling and grammar.
- Create individual PR for each suggestion.
- Fork the Project
- Create your 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 licensed under the Apache License 2.0 - see the LICENSE file for details.
