Alexander Maryanovsky
10/24/2023, 6:19 PMclass Property<out T>(
val flow: Flow<T>
val currentValue: () -> T
) {
fun stateFlow(coroutineScope: CoroutineScope): StateFlow<T> = flow.stateIn(
scope = coroutineScope,
started = SharingStarted.WhileSubscribed(),
initialValue = currentValue()
)
}
fun <T, R> Property<T>.map(transform: (T) -> R): Property<R>{
return Property(
flow = flow.map(transform),
currentValue = { transform(currentValue()) }
)
}
initialValue
and again when the source flow emits a value.Zach Klippenstein (he/him) [MOD]
10/24/2023, 7:26 PMflow.dropFirst().map(transform)
?jw
10/24/2023, 7:27 PMAlexander Maryanovsky
10/24/2023, 7:31 PMStateFlow
is how non-compose state is converted to compose state.Zach Klippenstein (he/him) [MOD]
10/24/2023, 7:50 PMAlexander Maryanovsky
10/24/2023, 7:50 PMZach Klippenstein (he/him) [MOD]
10/24/2023, 8:05 PMtransform(transform(currentValue()))
too?Alexander Maryanovsky
10/24/2023, 8:06 PMclass Prop<out T> (
val flow: Flow<T>,
val initialValue: () -> T
) {
constructor(stateFlow: StateFlow<T>):
this(stateFlow, stateFlow::value)
fun stateIn(scope: CoroutineScope): StateFlow<T> {
return flow.stateIn(
scope = scope,
started = SharingStarted.WhileSubscribed(),
initialValue = initialValue()
)
}
}
fun <T, R> Prop<T>.map(transform: (T) -> R): Prop<R> {
return Prop(
flow = this.flow.drop(1).map(transform),
initialValue = {
transform(this.initialValue())
}
)
}
fun transform1(value: Int): Int {
println("Transform1 $value")
return value*2
}
fun transform2(value: Int): Int {
println("Transform2 $value")
return value+1
}
val stateFlow = MutableStateFlow(1)
val prop = Prop(stateFlow).map(::transform1).map(::transform2)
fun main() = singleWindowApplication {
val value by prop.stateIn(rememberCoroutineScope()).collectAsState()
Text("$value")
LaunchedEffect(Unit) {
delay(2000)
stateFlow.value = 2
}
}
Transform1 1
Transform2 2
Transform1 2
Zach Klippenstein (he/him) [MOD]
10/24/2023, 8:19 PM.map
extension is going to drop one every time. For this to work, you can only drop the actual first element after creating the state flow.constructor(stateFlow: StateFlow<T>):
this(stateFlow.drop(1), stateFlow::value)
if that is always going to be the entry pointmap
extensionAlexander Maryanovsky
10/24/2023, 8:21 PMTransform1 1
Transform2 2
Transform1 2
Transform2 4
Transform1 2
Transform2 4
Zach Klippenstein (he/him) [MOD]
10/24/2023, 8:22 PMmap
drop
is only being called once per chainAlexander Maryanovsky
10/24/2023, 8:28 PMval prop = Prop(stateFlow).map(::transform1)
I'm getting
Transform1 1
Transform1 2
Transform1 2
stateIn
again.Zach Klippenstein (he/him) [MOD]
10/24/2023, 8:56 PMAlexander Maryanovsky
10/25/2023, 7:04 AMfun <T1, T2, R> combine(
prop1: Prop<T1>,
prop2: Prop<T2>,
transform: (T1, T2) -> R
): Prop<R> {
return Prop(
flow = combine(prop1.flow, prop2.flow, transform),
initialValue = { transform(prop1.initialValue(), prop2.initialValue()) }
)
}
Not sure why but this breaks updates to the output when an input changes.
val stateFlow1 = MutableStateFlow(1)
val stateFlow2 = MutableStateFlow(2)
val prop = combine(Prop(stateFlow1), Prop(stateFlow2)) { v1, v2 ->
println("Computing sum")
v1 + v2
}
doesn't get called again when I do stateFlow1.value = 2