There is still no official way to do this (yet) but there is a reasonable recommendation from https://github.com/Kotlin/kotlinx.coroutines/issues/2631#issuecomment-870565860 :
/**
* Does not produce the same value in a raw, so respect "distinct until changed emissions"
* */
class DerivedStateFlow<T>(
private val getValue: () -> T,
private val flow: Flow<T>
) : StateFlow<T> {
override val replayCache: List<T>
get () = listOf(value)
override val value: T
get () = getValue()
@InternalCoroutinesApi
override suspend fun collect(collector: FlowCollector<T>): Nothing {
coroutineScope { flow.distinctUntilChanged().stateIn(this).collect(collector) }
}
}
fun <T1, R> StateFlow<T1>.mapState(transform: (a: T1) -> R): StateFlow<R> {
return DerivedStateFlow(
getValue = { transform(this.value) },
flow = this.map { a -> transform(a) }
)
}
fun <T1, T2, R> combineStates(flow: StateFlow<T1>, flow2: StateFlow<T2>, transform: (a: T1, b: T2) -> R): StateFlow<R> {
return DerivedStateFlow(
getValue = { transform(flow.value, flow2.value) },
flow = combine(flow, flow2) { a, b -> transform(a, b) }
)
}
// and so on