Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Checking state during action execution #45

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -1,6 +1,5 @@
package io.uniflow.core.flow

import io.uniflow.core.flow.data.UIEvent
import io.uniflow.core.flow.data.UIState
import io.uniflow.core.logger.UniFlowLogger
import io.uniflow.core.threading.launchOnIO
Expand All @@ -21,7 +20,7 @@ class ActionDispatcher(

fun action(onAction: ActionFunction<UIState>): ActionFlow = action(onAction) { error, state -> dataFlow.onError(error, state, this) }

fun action(onAction: ActionFunction<UIState>, onError: ActionErrorFunction): ActionFlow = ActionFlow(onAction, onError).also {
fun action(onAction: ActionFunction<UIState>, onError: ActionErrorFunction): ActionFlow = ActionFlow(UIState::class, onAction, onError).also {
coroutineScope.launchOnIO {
UniFlowLogger.debug("$tag - enqueue: $it")
reducer.enqueueAction(it)
Expand All @@ -32,16 +31,11 @@ class ActionDispatcher(

@Suppress("UNCHECKED_CAST")
fun <T : UIState> actionOn(stateClass: KClass<T>, onAction: ActionFunction<T>, onError: ActionErrorFunction): ActionFlow {
val currentState = getCurrentState()
return if (stateClass.isInstance(currentState)) {
val action = ActionFlow(onAction as ActionFunction<UIState>, onError)
coroutineScope.launchOnIO {
UniFlowLogger.debug("$tag - enqueue: $action")
reducer.enqueueAction(action)
}
action
} else {
action { sendEvent { UIEvent.BadOrWrongState(currentState) } }
val action = ActionFlow(stateClass as KClass<UIState>, onAction as ActionFunction<UIState>, onError)
coroutineScope.launchOnIO {
UniFlowLogger.debug("$tag - enqueue: $action")
reducer.enqueueAction(action)
}
return action
}
}
Expand Up @@ -4,6 +4,7 @@ import io.uniflow.core.flow.data.UIData
import io.uniflow.core.flow.data.UIEvent
import io.uniflow.core.flow.data.UIState
import kotlinx.coroutines.flow.FlowCollector
import kotlin.reflect.KClass


typealias ActionFunction<T> = suspend ActionFlow.(T) -> (Unit)
Expand All @@ -16,6 +17,7 @@ enum class UIDataUpdateType {
data class UIDataUpdate(val data: UIData, val type: UIDataUpdateType = UIDataUpdateType.PUBLISH)

class ActionFlow(
val klass: KClass<UIState>,
val onSuccess: ActionFunction<UIState>,
val onError: ActionErrorFunction
) {
Expand Down
25 changes: 15 additions & 10 deletions uniflow-core/src/main/kotlin/io/uniflow/core/flow/ActionReducer.kt
@@ -1,6 +1,7 @@
package io.uniflow.core.flow

import io.uniflow.core.dispatcher.UniFlowDispatcher
import io.uniflow.core.flow.data.UIEvent
import io.uniflow.core.flow.data.UIState
import io.uniflow.core.logger.UniFlowLogger
import kotlinx.coroutines.*
Expand All @@ -9,6 +10,7 @@ import kotlinx.coroutines.channels.actor
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.onCompletion
import kotlin.reflect.KClass

@OptIn(ObsoleteCoroutinesApi::class)
class ActionReducer(
Expand Down Expand Up @@ -36,20 +38,23 @@ class ActionReducer(
actor.send(action)
}

@Suppress("UNCHECKED_CAST")
private suspend fun reduceAction(action: ActionFlow) {
UniFlowLogger.debug("$tag - execute: $action")
val currentState: UIState = uiDataStore.currentState
try {
val onSuccess = action.onSuccess
flow<UIDataUpdate> {
action.flow = this
onSuccess(action, currentState)
}
.onCompletion {
UniFlowLogger.debug("$tag - completed: $action")
}
.collect { dataUpdate ->
uiDataStore.pushNewData(dataUpdate)
if (!action.klass.isInstance(currentState)) {
enqueueAction(ActionFlow(currentState::class as KClass<UIState>, onSuccess = { sendEvent { UIEvent.BadOrWrongState(currentState) } }, onError = action.onError))
Copy link
Author

@Otacon Otacon Sep 15, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is the correct way of sending a UIEvent.BadOrWrongState internally

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, perhaps we can register the state class when we make an action. In case of simple action, no need of particular class. In actionOn case, we need it

} else {
val onSuccess = action.onSuccess
flow<UIDataUpdate> {
action.flow = this
onSuccess(action, currentState)
}.onCompletion {
UniFlowLogger.debug("$tag - completed: $action")
}.collect { dataUpdate ->
uiDataStore.pushNewData(dataUpdate)
}
}
} catch (e: Exception) {
val onError = action.onError
Expand Down