```fun ProgressThingy(duration: Long, running: Flo...
# coroutines
u
Copy code
fun ProgressThingy(duration: Long, running: Flow<Boolean>): Flow<Float> {
    return callbackFlow {
        val animator = ValueAnimator.ofFloat(0F, 1F)
        animator.duration = duration
        animator.addUpdateListener {
            trySend(it.animatedFraction)
        }
        animator.addListener(onCancel = {
            cancel()
        })
        animator.start()

        running.collect {
            if (it) animator.resume() else animator.pause()
        }

        awaitClose {
            animator.cancel()
        }
    }
}
does anyone see a problem with collecting the running signal like that within the callback flow scope? it appears to work fine
ok turns out the
collect
obviosuly suspends so awaitClose is never registered since
running
never completes Any idea I could do this pattern? Rx used it
j
You could launch the collection in a coroutine so you can reach
awaitClose
u
doh.. thank you!
If I could ask, now it suspend on the awaitClose until the flow is canceled. How could I make it complete when the animator completes?
Im aware that it completes once the lambda returns, sooo idk
j
You can make the callback flow complete by calling
close()
on the channel it gives you, but I don't know the animator API so not sure how to know it is complete
u
oh, interesting that its not wrapped
j
What do you mean?
u
that I have to talk to the channel directly, not via some indirection as with trySend
hm there is a
close
in there as well
j
trySend
is provided by the producer scope I believe, and close should be also provided the same way
u
yea so why leak the channel reference like that
j
I don't believe it's meant to be hidden. Rather, the producer scope provides convenient "shortcuts", but the basics are there if you need them (like pass the channel around etc)
u
alright so the
close
is same as calling
channel.close
?
j
I believe so yes, but I can't check because I'm afk. You should be able to check that in the IDE by navigating to the declaration. I would bet it calls channel.close()
u
well it doesnt but it does behave as expected
Copy code
public override fun close(cause: Throwable?): Boolean {
        val closed = Closed<E>(cause)
        /*
         * Try to commit close by adding a close token to the end of the queue.
         * Successful -> we're now responsible for closing receivers
         * Not successful -> help closing pending receivers to maintain invariant
         * "if (!close()) next send will throw"
         */
        val closeAdded = queue.addLastIfPrev(closed) { it !is Closed<*> }
        val actuallyClosed = if (closeAdded) closed else queue.prevNode as Closed<*>
        helpClose(actuallyClosed)
        if (closeAdded) invokeOnCloseHandler(cause)
        return closeAdded // true if we have closed
    }