### Kotlin: Demonstrate cream.kt Automatic Copying vs. Manual Copying Source: https://github.com/tbsten/cream/blob/main/README.md This snippet contrasts the traditional manual approach of copying properties between UI states with the streamlined automatic copying provided by cream.kt. The manual approach is verbose and harder to maintain when properties change, while cream.kt simplifies this to a single function call, improving readability. ```kotlin // Traditional approach // ❌ It is difficult to see which specific data has been added or changed. MyUiState.Success( userName = prevState.userName, // manual copy password = prevState.password, // manual copy data = newData ) // With cream.kt // (toSuccess is generated automatically) // ✅ A quick glance at the data added prevState.toSuccess(data = newData) // automatic copy ``` -------------------------------- ### Kotlin: cream.kt Usage for State Transitions Source: https://github.com/tbsten/cream/blob/main/README.md Illustrates how cream.kt simplifies state transitions in Kotlin. Instead of manually copying properties from a previous state (e.g., Loading) to a new state (e.g., Stable), cream.kt generates a function (e.g., toStable) that handles the property copying automatically, making the code cleaner and less error-prone. ```kotlin val prevState: MyUiState.Loading = TODO() val loadedData: List = TODO() // Before cream.kt MyUiState.Stable( // ⚠️ See here ! userName = prevState.userName, password = prevState.password, loadedData = loadedData, ) // With cream.kt prevState.toStable( loadedData = loadedData, ) ``` -------------------------------- ### Automated State Transition with cream.kt Source: https://github.com/tbsten/cream/blob/main/README.ja.md Demonstrates how cream.kt simplifies state transitions by automatically generating copy functions. Instead of manually copying properties, you can use a generated function like `prevState.toSuccess(data = newData)`, making the code cleaner and highlighting new or changed data. ```kotlin // Traditional approach // ❌ It's hard to tell at a glance which data has been added or changed MyUiState.Success( userName = prevState.userName, // Manual copy password = prevState.password, // Manual copy data = newData ) // Using cream.kt // (toSuccess is automatically generated) // ✅ It's clear that data has been added prevState.toSuccess(data = newData) // Automatic copy ``` -------------------------------- ### Generate Copy Functions for Sealed Class Hierarchy with @CopyToChildren Source: https://context7.com/tbsten/cream/llms.txt The `@CopyToChildren` annotation automatically generates copy functions for all direct children of a sealed interface. This is useful for creating variations of states or events within a sealed hierarchy, simplifying state management and event handling. It requires the `me.tbsten.cream.CopyToChildren` import. ```kotlin import me.tbsten.cream.CopyToChildren @CopyToChildren sealed interface PaymentState { val orderId: String val amount: Double data class Pending( override val orderId: String, override val amount: Double, ) : PaymentState data class Processing( override val orderId: String, override val amount: Double, val processorId: String, ) : PaymentState data class Completed( override val orderId: String, override val amount: Double, val transactionId: String, val completedAt: Long, ) : PaymentState data class Failed( override val orderId: String, override val amount: Double, val errorCode: String, val errorMessage: String, ) : PaymentState } // Usage example in a PaymentProcessor class demonstrating state transitions: class PaymentProcessor { fun processPayment(state: PaymentState.Pending): PaymentState { return try { val processorId = startProcessing() state.copyToPaymentStateProcessing(processorId = processorId) } catch (e: Exception) { state.copyToPaymentStateFailed( errorCode = "PROC_ERROR", errorMessage = e.message ?: "Processing failed" ) } } fun completePayment(state: PaymentState.Processing): PaymentState { val transactionId = finalizeTransaction() return state.copyToPaymentStateCompleted( transactionId = transactionId, completedAt = System.currentTimeMillis() ) } } ``` -------------------------------- ### Generate Forward Copy Functions with @CopyTo Source: https://context7.com/tbsten/cream/llms.txt The `@CopyTo` annotation generates extension functions to copy properties from a source class to specified target classes. This is useful for state transitions, like moving from a loading state to a success or error state, where shared properties are automatically preserved. The generated functions allow overriding specific properties. ```kotlin import me.tbsten.cream.CopyTo @CopyTo(UiState.Success::class, UiState.Error::class) sealed interface UiState { val userId: String val timestamp: Long data class Loading( override val userId: String, override val timestamp: Long, ) : UiState data class Success( override val userId: String, override val timestamp: Long, val data: List, ) : UiState data class Error( override val userId: String, override val timestamp: Long, val message: String, ) : UiState } // Usage in ViewModel: class MyViewModel : ViewModel() { private val _state = MutableStateFlow( UiState.Loading(userId = "user123", timestamp = System.currentTimeMillis()) ) val state: StateFlow = _state.asStateFlow() fun loadData() { viewModelScope.launch { try { val data = repository.fetchData() _state.update { currentState -> // With cream.kt - shared properties automatically copied: (currentState as UiState.Loading).copyToUiStateSuccess(data = data) } } catch (e: Exception) { _state.update { currentState -> (currentState as UiState.Loading).copyToUiStateError(message = e.message ?: "Unknown error") } } } } } ``` -------------------------------- ### KSP Multiplatform Workaround in Kotlin Source: https://github.com/tbsten/cream/blob/main/CLAUDE.md A Kotlin extension function for Gradle `Project` that configures KSP to work with multiplatform projects by setting up intermediate source sets and managing task dependencies. This addresses a limitation in KSP's direct support for `commonMain`. ```kotlin fun Project.setupKspForMultiplatformWorkaround() { kotlin.sourceSets.commonMain { kotlin.srcDir("build/generated/ksp/metadata/commonMain/kotlin") } tasks.configureEach { if (name.startsWith("ksp") && name != "kspCommonMainKotlinMetadata") { dependsOn(tasks.named("kspCommonMainKotlinMetadata")) enabled = false } } } ``` -------------------------------- ### Map Properties Between Classes with @CopyTo.Map and @CopyFrom.Map (Kotlin) Source: https://github.com/tbsten/cream/blob/main/README.md The @CopyTo.Map and @CopyFrom.Map annotations allow mapping properties between source and target classes when their names differ. This is useful for scenarios requiring value copying between properties with non-identical names. ```kotlin @CopyTo(DataModel::class) data class DomainModel( @CopyTo.Map("dataId") val domainId: String, ) data class DataModel( val dataId: String, ) // auto generate fun DomainModel.copyToDataModel( dataId: String = this.domainId, // domainId is mapped to dataId ): DataModel = ... ``` ```kotlin @CopyFrom(DataModel::class) data class DomainModel( @CopyFrom.Map("dataId") val domainId: String, ) data class DataModel( val dataId: String, ) // auto generate fun DataModel.copyToDomainModel( domainId: String = this.dataId, // dataId is mapped to domainId ) ``` -------------------------------- ### Map Properties Between Classes with @CopyTo.Map and @CopyFrom.Map Source: https://github.com/tbsten/cream/blob/main/README.ja.md Use @CopyTo.Map and @CopyFrom.Map to specify property mappings when the source and destination classes have different property names. This is particularly useful for mapping properties during data copying. ```kotlin @CopyTo(DataModel::class) data class DomainModel( @CopyTo.Map("dataId") val domainId: String, ) data class DataModel( val dataId: String, ) // auto genarate fun DomainModel.copyToDataModel( dataId: String = this.domainId, // domainId と dataId がマッピングされます ): DataModel = ... ``` ```kotlin @CopyFrom(DataModel::class) data class DomainModel( @CopyFrom.Map("dataId") val domainId: String, ) data class DataModel( val dataId: String, ) // auto generate fun DataModel.copyToDomainModel( domainId: String = this.dataId, // dataId と domainId がマッピングされます ) ```