This can be created using the channelFlow builder. Maybe there is a simpler way with operators but I couldn't come up with one.
If fetchData() is a one-time fetching suspend function, you could do:
fun <R, T: R, L: R> lazyFlowOfWithLoadStateIfDelayed(cutoffDelay: Long, loadState: L, fetchAction: suspend ()->T): Flow<R> = channelFlow {
val sendLoadingJob = launch {
delay(cutoffDelay)
send(loadState)
}
val value = fetchAction()
sendLoadingJob.cancelAndJoin()
send(value)
}
Usage:
lazyFlowOfWithLoadStateIfDelayed(1000L, Status.Loading) { Status.Data(repository.fetchData()) }
.collect {
when (it) {
is Status.Loading -> // show loading indicator in case no data after X milliseconds
is Status.Data -> // We have received the data.
}
}
Edit: simpler way to build the above using debounce, based on Vivek Gupta's comments and answer. This works because debounce is optimized to pass through the last value of a finite flow immediately.
fun <R, T: R, L: R> lazyFlowOfWithLoadStateIfDelayed(cutoffDelay: Long, loadState: L, fetchAction: suspend ()->T): Flow<R> = flow {
emit(loadState)
emit(fetchAction())
}.debounce(cutoffDelay)
If fetchData() is a flow, for example a flow that infinitely monitors a database, you could build a flow operator that shows a load state only if the first item is slow:
fun <R, T: R, L: R> Flow<T>.emitLoadStateIfDelayed(cutoffDelay: Long, loadState: L): Flow<R> = channelFlow {
val sendLoadingJob = launch {
delay(cutoffDelay)
send(loadState)
}
collect {
sendLoadingJob.cancelAndJoin()
send(it)
}
}
fetchData()? A Flow that emits values every time a repository value changes? Or just a suspend function that does a one-time fetch? If it's a Flow that continually monitors the database, do you only want to show the Loading state if it's the first value that takes a long time?