Skip to content

ComposeTemplate is a Jetpack Compose template application that follows Clean Architecture best practices. It simplifies the process of setting up a well-structured Compose application by providing a template with a predefined folder structure. ✨

License

Notifications You must be signed in to change notification settings

mustafayigitt/ComposeTemplate

Repository files navigation


ComposeTemplate

ComposeTemplate is a Jetpack Compose template application that follows Clean Architecture 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

Contributors Stargazers Issues License

About The Project

Screen Shot

ComposeTemplate is a Jetpack Compose template application that follows Clean Architecture best practices. It simplifies the process of setting up a well-structured Compose application by providing a template with a predefined folder structure. ✨

Built With

Project Structure

The project follows Clean Architecture principles with clear separation of concerns and uses Convention Plugins for build configuration:

ComposeTemplate/
├── app/src/main/java/com/ytapps/composetemplate/
│   ├── core/                          # Core functionality and utilities
│   │   ├── api/                       # API related classes
│   │   │   ├── DefaultInterceptor.kt  # HTTP interceptor for auth headers
│   │   │   └── Result.kt             # Sealed class for API results
│   │   ├── base/                      # Base classes
│   │   │   ├── BaseRepository.kt     # Base repository with safeCall
│   │   │   ├── BaseUiState.kt        # Base UI state class
│   │   │   └── IMapper.kt            # Mapper interface
│   │   ├── di/                        # Dependency injection modules
│   │   │   ├── BinderModule.kt       # Hilt binding module
│   │   │   └── ProviderModule.kt     # Hilt provider module
│   │   ├── navigation/                # Navigation components
│   │   │   ├── NavigationManager.kt  # Custom navigation manager
│   │   │   ├── INavigationItem.kt    # Navigation item interface
│   │   │   └── IBottomBarItem.kt     # Bottom bar item interface
│   │   └── theme/                     # UI theme and components
│   │       ├── component/             # Reusable UI components
│   │       │   ├── AppNavigation.kt  # Main navigation component
│   │       │   └── AppNavigationBar.kt # Bottom navigation bar
│   │       ├── Color.kt              # Color definitions
│   │       ├── Theme.kt              # Material 3 theme
│   │       └── Type.kt               # Typography definitions
│   ├── data/                          # Data layer
│   │   ├── local/                     # Local data sources
│   │   │   ├── PreferencesManager.kt # SharedPreferences manager
│   │   │   └── IPreferencesManager.kt # Preferences interface
│   │   ├── model/                     # Data models
│   │   │   ├── AuthRequestModel.kt   # Auth request DTO
│   │   │   └── AuthResponseModel.kt  # Auth response DTO
│   │   ├── remote/                    # Remote data sources
│   │   │   └── AuthService.kt        # Retrofit API service
│   │   └── repository/                # Repository implementations
│   │       └── AuthRepository.kt     # Authentication repository
│   ├── domain/                         # Domain layer (business logic)
│   │   ├── mapper/                    # Data mappers
│   │   │   └── AuthMapper.kt         # Auth model mapper
│   │   ├── model/                      # Domain models
│   │   │   └── AuthModel.kt          # Auth domain model
│   │   ├── repository/                 # Repository interfaces
│   │   │   └── IAuthRepository.kt     # Auth repository interface
│   │   └── usecase/                    # Use cases
│   │       └── LoginUseCase.kt       # Login use case
│   ├── presentation/                   # Presentation layer (UI)
│   │   ├── detail/                     # Detail screen
│   │   │   ├── DetailRoute.kt
│   │   │   ├── DetailUiState.kt
│   │   │   └── DetailViewModel.kt
│   │   ├── home/                       # Home screen
│   │   │   ├── HomeRoute.kt
│   │   │   └── HomeViewModel.kt
│   │   ├── list/                       # List screen
│   │   │   ├── ListRoute.kt
│   │   │   ├── ListUiState.kt
│   │   │   └── ListViewModel.kt
│   │   ├── login/                      # Login screen
│   │   │   ├── LoginRoute.kt
│   │   │   ├── LoginUiState.kt
│   │   │   └── LoginViewModel.kt
│   │   ├── profile/                     # Profile screen
│   │   │   ├── ProfileRoute.kt
│   │   │   └── ProfileViewModel.kt
│   │   ├── search/                      # Search screen
│   │   │   ├── SearchRoute.kt
│   │   │   └── SearchViewModel.kt
│   │   └── splash/                      # Splash screen
│   │       ├── SplashRoute.kt
│   │       ├── SplashUiState.kt
│   │       └── SplashViewModel.kt
│   ├── util/                            # Utilities
│   │   └── Constants.kt                # App constants
│   ├── App.kt                          # Application class with Hilt
│   └── MainActivity.kt                 # Main activity
├── build-logic/                        # Build configuration
│   ├── convention/                     # Convention plugins
│   │   └── src/main/kotlin/com/ytapps/composetemplate/convention/
│   │       ├── AndroidApplicationConventionPlugin.kt
│   │       ├── AndroidComposeConventionPlugin.kt
│   │       ├── AndroidHiltConventionPlugin.kt
│   │       ├── AndroidLibraryConventionPlugin.kt
│   │       ├── KotlinAndroid.kt
│   │       └── ProjectExtensions.kt
│   └── README.md                       # Build logic documentation
└── gradle/
    └── libs.versions.toml              # Version catalog (dependencies & versions)

Build Configuration

This project uses modern Gradle build configuration with Convention Plugins and Version Catalog for maintainable and scalable build logic.

Convention Plugins

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 dependencies
  • composetemplate.android.hilt: Hilt dependency injection configuration
  • composetemplate.android.library: Android library module configuration

Benefits:

  • ✅ Centralized build configuration
  • ✅ Reduced duplication across modules
  • ✅ Type-safe Kotlin DSL
  • ✅ Easy to maintain and update

Version Catalog

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.

Key Features

Navigation System

  • 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 screen
    • navigateBack() - Navigate back in the stack
    • navigateOver() - Navigate over a specific route
    • navigateToTop() - Navigate to top of stack
    • selectTab() - Select bottom bar tab

Screens Included

  • 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

Network Layer

  • 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)

Data Management

  • 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

Dependency Injection

  • Hilt Integration: Full dependency injection setup
  • ProviderModule: Provides network components (Retrofit, OkHttp, Gson)
  • BinderModule: Binds interfaces to implementations
  • Singleton Components: Properly scoped dependencies

Testing

  • 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

UI/UX

  • 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

Predefined Structures

  • Header and Refresh Token Interceptor: Automatic token management with refresh token support DefaultInterceptor.kt
  • Safe Network Calls: Error-handled network function BaseRepository.kt
  • Flexible Navigation Structure: Custom navigation manager with Navigation3 NavigationManager.kt
  • Preferences Manager: Local data storage with SharedPreferences PreferencesManager.kt
  • Auth Flow: Complete authentication flow with token management AuthRepository.kt
  • Clean Architecture: Complete separation of Data, Domain, and Presentation layers
  • Unit Tests: All structures tested with JUnit and MockK Examples
  • End-to-End Examples: Complete examples for all architecture layers

Getting Started

Prerequisites

  • 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

Installation

  1. Clone the repository
git clone https://github.com/mustafayigitt/ComposeTemplate.git
cd ComposeTemplate
  1. 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/
  1. Run the Initializer Script

To create a new project using this template:

chmod +x initializer.sh
./initializer.sh

The 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
  • 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 .gitignore file
  • ✅ Initialize a new git repository with initial commit
  • ✅ Clean up template-specific files
  • ✅ Provide clear next steps
  1. Open the Project

Open the newly created project in Android Studio:

  • If using the template directly: Open ComposeTemplate folder
  • If using initializer: Open the created project folder (e.g., ../MyApp)
  1. Sync and Build
  • Sync Gradle files
  • Build the project (Build > Make Project)
  • Run on an emulator or device

Configuration

Build Configuration

The project uses build variants for different environments:

  • Debug: Uses BASE_URL_DEBUG from gradle.properties
  • Release: Uses BASE_URL from gradle.properties

Minimum Requirements

  • minSdk: 23 (Android 6.0)
  • targetSdk: 36
  • compileSdk: 36
  • Java Version: 17
  • Kotlin Version: 2.2.10

Dependencies

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

Usage Examples

Creating a New Screen

  1. Create Route Object (in presentation/yourfeature/YourFeatureRoute.kt):
@Serializable
data object YourFeature : INavigationItem {
    override val route: String = "route_your_feature"

    @Composable
    override fun ContentScreen(navigationManager: NavigationManager) {
        YourFeatureScreen(navigationManager = navigationManager)
    }
}
  1. Create Screen Composable:
@Composable
fun YourFeatureScreen(
    navigationManager: NavigationManager,
    viewModel: YourFeatureViewModel = hiltViewModel()
) {
    val uiState by viewModel.uiState.collectAsState()
    
    // Your UI implementation
}
  1. Add to NavigationManager (if needed for bottom bar):
val bottomBarItems: List<IBottomBarItem> = listOf(
    Home,
    Search,
    YourFeature, // Add here
    Profile,
)

Making API Calls

  1. Create API Service (in data/remote/YourService.kt):
interface YourService {
    @POST("your-endpoint")
    suspend fun yourMethod(@Body request: YourRequestModel): Response<YourResponseModel>
}
  1. Create Repository (in 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())
        }
    }
}
  1. 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
                }
            }
        }
    }
}

Navigation Examples

// 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)

Storing Data Locally

// 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)
}

Architecture

This project follows Clean Architecture principles with three main layers:

Data Layer

  • Responsibility: Data sources (remote API, local storage)
  • Components: Repositories, Data Models, API Services, Local Storage
  • Location: data/ package

Domain Layer

  • Responsibility: Business logic and use cases
  • Components: Use Cases, Domain Models, Repository Interfaces, Mappers
  • Location: domain/ package

Presentation Layer

  • Responsibility: UI and user interactions
  • Components: ViewModels, UI States, Composable Screens, Routes
  • Location: presentation/ package

Core Layer

  • Responsibility: Shared utilities and base classes
  • Components: Base classes, Navigation, DI modules, Theme, API utilities
  • Location: core/ package

Testing

The project includes comprehensive unit tests. Run tests with:

./gradlew test

Test Structure

  • 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`() = runTest {
    // Given
    val expectedResult = Result.Success(authResponse)
    coEvery { authService.login(any()) } returns Response.success(authResponse)
    
    // When
    val result = authRepository.login(authRequest)
    
    // Then
    assertThat(result).isInstanceOf(Result.Success::class.java)
}

Contributing

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.

Creating A Pull Request

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

License

This project is licensed under the Apache License 2.0 - see the LICENSE file for details.

About

ComposeTemplate is a Jetpack Compose template application that follows Clean Architecture best practices. It simplifies the process of setting up a well-structured Compose application by providing a template with a predefined folder structure. ✨

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •