Real World Example

Zomato Order Tracking

The order screen subscribes to a stream of status updates from the server. The flow maps raw statuses to UI text, drops duplicates, stops after delivery, and shows a fallback message if the connection breaks.

server events ─► distinctUntilChanged ─► map to UI text ─► transformWhile (stop at DELIVERED)
                                                                    ─► catch (show "reconnecting")
                                                                    ─► collect (update screen)

Code

Example

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

enum class Status { PLACED, ACCEPTED, PREPARING, PICKED_UP, ON_THE_WAY, DELIVERED }

fun orderUpdates(orderId: String): Flow<Status> = flow {
    val serverEvents = listOf(
        Status.PLACED, Status.ACCEPTED, Status.ACCEPTED, Status.PREPARING,
        Status.PICKED_UP, Status.ON_THE_WAY, Status.ON_THE_WAY, Status.DELIVERED, Status.DELIVERED,
    )
    for (s in serverEvents) {
        delay(30)
        emit(s)
    }
}

fun Status.toUiText(eta: Int) = when (this) {
    Status.PLACED -> "Order placed"
    Status.ACCEPTED -> "Restaurant accepted your order"
    Status.PREPARING -> "Food is being prepared (ETA $eta min)"
    Status.PICKED_UP -> "Rider picked up your order"
    Status.ON_THE_WAY -> "Rider is on the way (ETA $eta min)"
    Status.DELIVERED -> "Delivered. Enjoy your meal!"
}

fun main() = runBlocking {
    orderUpdates("ZMT-8842")
        .distinctUntilChanged()
        .transformWhile { status ->
            emit(status.toUiText(eta = 35 - status.ordinal * 7))
            status != Status.DELIVERED
        }
        .onCompletion { println("[tracking closed]") }
        .catch { emit("Connection lost, reconnecting...") }
        .collect { println(it) }
}

Output

Order placed
Restaurant accepted your order
Food is being prepared (ETA 21 min)
Rider picked up your order
Rider is on the way (ETA 7 min)
Delivered. Enjoy your meal!
[tracking closed]