Real World Example

API Models in an Android App

Responses from a REST API (via Retrofit + Moshi/Gson/kotlinx.serialization) are mapped to data classes. A separate UI model keeps screens simple.

@Serializable
data class ProductDto(
    val id: Long,
    val title: String,
    val price: Double,
    @SerialName("discount_percent") val discountPercent: Int = 0,
)

data class ProductUi(val id: Long, val title: String, val priceText: String, val hasOffer: Boolean)

fun ProductDto.toUi() = ProductUi(id, title, "Rs %.0f".format(price), discountPercent > 0)

Immutable Screen State with copy

Example

Compose screens keep one immutable state object and replace it with copy() on each event - like this simplified food-delivery cart.

data class CartLine(val dish: String, val price: Int, val qty: Int)

data class CartState(
    val restaurant: String,
    val lines: List<CartLine> = emptyList(),
    val coupon: String? = null,
) {
    val total: Int get() {
        val sum = lines.sumOf { it.price * it.qty }
        return if (coupon == "SAVE50" && sum >= 300) sum - 50 else sum
    }
}

fun CartState.add(dish: String, price: Int): CartState {
    val existing = lines.find { it.dish == dish }
    val newLines = if (existing == null) lines + CartLine(dish, price, 1)
                   else lines.map { if (it.dish == dish) it.copy(qty = it.qty + 1) else it }
    return copy(lines = newLines)
}

fun main() {
    var state = CartState("Paradise Biryani")
    state = state.add("Chicken Biryani", 280)
    state = state.add("Coke", 40)
    state = state.add("Coke", 40)
    println(state.lines)
    println("Total: ${state.total}")
    state = state.copy(coupon = "SAVE50")
    println("Total with coupon: ${state.total}")
}

Output

[CartLine(dish=Chicken Biryani, price=280, qty=1), CartLine(dish=Coke, price=40, qty=2)]
Total: 360
Total with coupon: 310