Skip to content

Commit

Permalink
Merge pull request #5 from tunjid/jobReturn
Browse files Browse the repository at this point in the history
Return the job launched in StateFlowProducer
  • Loading branch information
tunjid authored Feb 15, 2024
2 parents 0e11465 + f1bb768 commit 2bedec6
Show file tree
Hide file tree
Showing 12 changed files with 53 additions and 80 deletions.
4 changes: 0 additions & 4 deletions core/src/commonMain/kotlin/com/tunjid/mutator/Mutator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ package com.tunjid.mutator
*/
typealias Mutation<State> = State.() -> State

interface Mutator<State : Any> {
suspend fun mutate(mutation: Mutation<State>)
}

typealias StateHolder<State> = StateProducer<State>

interface StateProducer<State : Any> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,15 @@
package com.tunjid.mutator.coroutines

import com.tunjid.mutator.Mutation
import com.tunjid.mutator.Mutator
import com.tunjid.mutator.StateProducer
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapMerge
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch

fun <State : Any> CoroutineScope.stateFlowProducer(
Expand All @@ -50,15 +48,13 @@ class StateFlowProducer<State : Any> internal constructor(
started: SharingStarted = SharingStarted.WhileSubscribed(),
inputs: List<Flow<Mutation<State>>>
) : StateProducer<StateFlow<State>> {
private val parallelExecutedTasks = MutableSharedFlow<Flow<Mutation<State>>>()
private val mutationChannel = Channel<Mutation<State>>()
private val mutationSender = FlowCollector(mutationChannel::send)

override val state = scope.produceState(
initialState = initialState,
started = started,
inputs = inputs + parallelExecutedTasks.flatMapMerge(
concurrency = Int.MAX_VALUE,
transform = { it }
)
inputs = inputs + mutationChannel.receiveAsFlow()
)

/**
Expand All @@ -69,20 +65,8 @@ class StateFlowProducer<State : Any> internal constructor(
* a collector begins to collect from [state].
*/
fun launch(
block: suspend Mutator<State>.() -> Unit
) {
scope.launch {
// Suspend till downstream is connected
parallelExecutedTasks.subscriptionCount.first { it > 0 }
parallelExecutedTasks.emit(flow {
block(this.asMutator())
})
}
block: suspend FlowCollector<Mutation<State>>.() -> Unit
): Job = scope.launch {
block(mutationSender)
}
}

private fun <State : Any> FlowCollector<Mutation<State>>.asMutator() = object : Mutator<State> {
override suspend fun mutate(mutation: Mutation<State>) {
this@asMutator.emit(mutation)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ class Snail7StateHolder(
val state: StateFlow<Snail7State> = stateProducer.state
fun setSnailColor(index: Int) = stateProducer.launch {
mutate { copy(color = colors[index]) }
emit { copy(color = colors[index]) }
}
fun setProgress(progress: Float) = stateProducer.launch {
mutate { copy(progress = progress) }
emit { copy(progress = progress) }
}
}
""".trimIndent()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@ class Snail8StateHolder(
...
fun setMode(isDark: Boolean) = stateProducer.launch {
mutate { copy(isDark = isDark) }
emit { copy(isDark = isDark) }
/* Collect from a flow that animates color changes */
interpolateColors(
startColors = state.value.colors.map(Color::argb).toIntArray(),
endColors = MutedColors.colors(isDark).map(Color::argb).toIntArray()
).collect { (progress, colors) ->
mutate {
emit {
copy(
colorInterpolationProgress = progress,
colors = colors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,15 @@ class Snail9StateHolder(
fun setMode(isDark: Boolean) = stateProducer.launch {
if (state.value.isInterpolating) return@launch
mutate { copy(isDark = isDark, isInterpolating = true) }
emit { copy(isDark = isDark, isInterpolating = true) }
interpolateColors(
...
).collect { (progress, colors) ->
mutate {
emit {
copy(...)
}
}
mutate { copy(isInterpolating = false) }
emit { copy(isInterpolating = false) }
}
}
""".trimIndent()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ val Snail10State.cardColor: Color get() = colors.last()
val Snail10State.textColor: Color get() = if (cardColor.isBright()) Color.Black else Color.LightGray

class Snail10StateHolder(
private val scope: CoroutineScope
scope: CoroutineScope
) {

private var setModeJob: Job? = null
Expand All @@ -87,22 +87,22 @@ class Snail10StateHolder(
val state: StateFlow<Snail10State> = stateProducer.state

fun setSnailColor(index: Int) = stateProducer.launch {
mutate { copy(colorIndex = index) }
emit { copy(colorIndex = index) }
}

fun setProgress(progress: Float) = stateProducer.launch {
mutate { copy(progress = progress) }
emit { copy(progress = progress) }
}

fun setMode(isDark: Boolean) = stateProducer.launch {
setModeJob?.cancel()
setModeJob = currentCoroutineContext()[Job]
mutate { copy(isDark = isDark) }
emit { copy(isDark = isDark) }
interpolateColors(
startColors = state.value.colors.map(Color::argb).toIntArray(),
endColors = MutedColors.colors(isDark).map(Color::argb).toIntArray()
).collect { (progress, colors) ->
mutate {
emit {
copy(
colorInterpolationProgress = progress,
colors = colors
Expand Down Expand Up @@ -148,7 +148,13 @@ fun Snail10() {
colors = state.colors,
onColorClicked = {
stateHolder.setSnailColor(it)
udfStateHolder.accept(Event.UserTriggered(metadata = Marble.Metadata.Tint(state.colors[it])))
udfStateHolder.accept(
Event.UserTriggered(
metadata = Marble.Metadata.Tint(
state.colors[it]
)
)
)
}
)
SnailText(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@ class Snail7StateHolder(
val state: StateFlow<Snail7State> = stateProducer.state

fun setSnailColor(index: Int) = stateProducer.launch {
mutate { copy(color = colors[index]) }
emit { copy(color = colors[index]) }
}

fun setProgress(progress: Float) = stateProducer.launch {
mutate { copy(progress = progress) }
emit { copy(progress = progress) }
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ val Snail8State.cardColor: Color get() = colors.last()
val Snail8State.textColor: Color get() = if (cardColor.isBright()) Color.Black else Color.LightGray

class Snail8StateHolder(
private val scope: CoroutineScope
scope: CoroutineScope
) {

private val speed: Flow<Speed> = scope.speedFlow()
Expand All @@ -84,21 +84,21 @@ class Snail8StateHolder(
val state: StateFlow<Snail8State> = stateProducer.state

fun setSnailColor(index: Int) = stateProducer.launch {
mutate { copy(colorIndex = index) }
emit { copy(colorIndex = index) }
}

fun setProgress(progress: Float) = stateProducer.launch {
mutate { copy(progress = progress) }
emit { copy(progress = progress) }
}

fun setMode(isDark: Boolean) = stateProducer.launch {
mutate { copy(isDark = isDark) }
emit { copy(isDark = isDark) }
// Collect from a flow that animates color changes
interpolateColors(
startColors = state.value.colors.map(Color::argb).toIntArray(),
endColors = MutedColors.colors(isDark).map(Color::argb).toIntArray()
).collect { (progress, colors) ->
mutate {
emit {
copy(
colorInterpolationProgress = progress,
colors = colors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ val Snail9State.cardColor: Color get() = colors.last()
val Snail9State.textColor: Color get() = if (cardColor.isBright()) Color.Black else Color.LightGray

class Snail9StateHolder(
private val scope: CoroutineScope
scope: CoroutineScope
) {

private val speed: Flow<Speed> = scope.speedFlow()
Expand All @@ -85,28 +85,28 @@ class Snail9StateHolder(
val state: StateFlow<Snail9State> = stateProducer.state

fun setSnailColor(index: Int) = stateProducer.launch {
mutate { copy(colorIndex = index) }
emit { copy(colorIndex = index) }
}

fun setProgress(progress: Float) = stateProducer.launch {
mutate { copy(progress = progress) }
emit { copy(progress = progress) }
}

fun setMode(isDark: Boolean) = stateProducer.launch {
if (state.value.isInterpolating) return@launch
mutate { copy(isDark = isDark, isInterpolating = true) }
emit { copy(isDark = isDark, isInterpolating = true) }
interpolateColors(
startColors = state.value.colors.map(Color::argb).toIntArray(),
endColors = MutedColors.colors(isDark).map(Color::argb).toIntArray()
).collect { (progress, colors) ->
mutate {
emit {
copy(
colorInterpolationProgress = progress,
colors = colors
)
}
}
mutate { copy(isInterpolating = false) }
emit { copy(isInterpolating = false) }
}
}

Expand Down
2 changes: 1 addition & 1 deletion docs/demo.js

Large diffs are not rendered by default.

23 changes: 10 additions & 13 deletions docs/demo.js.LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,36 +1,33 @@
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/

/*!
* Determine if an object is a Buffer
*
* @author Feross Aboukhadijeh <https://feross.org>
* @license MIT
*/

/** @license React v0.20.2
* scheduler.production.min.js
/**
* @license React
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/** @license React v17.0.2
* react-dom.production.min.js
/**
* @license React
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/** @license React v17.0.2
* react-is.production.min.js
/**
* @license React
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
Expand All @@ -39,7 +36,7 @@ object-assign
*/

/** @license React v17.0.2
* react.production.min.js
* react-is.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
Expand Down
12 changes: 1 addition & 11 deletions docs/demo.js.map

Large diffs are not rendered by default.

0 comments on commit 2bedec6

Please sign in to comment.