commonMain.Mobius.kt Maven / Gradle / Ivy
package kt.mobius
import kt.mobius.disposables.Disposable
import kt.mobius.functions.Consumer
import kt.mobius.functions.Producer
import kt.mobius.runners.DefaultWorkRunners
import kt.mobius.runners.ImmediateWorkRunner
import kt.mobius.runners.WorkRunner
import kotlin.js.JsName
import kotlin.jvm.JvmStatic
object Mobius {
private object NOOP_INIT : Init {
override fun init(model: Any): First {
return First.first(model)
}
}
private object NOOP_EVENT_SOURCE : EventSource {
override fun subscribe(eventConsumer: Consumer): Disposable {
return Disposable { }
}
}
private object NOOP_LOGGER : MobiusLoop.Logger {
override fun beforeInit(model: Any) {
/* noop */
}
override fun afterInit(model: Any, result: First) {
/* noop */
}
override fun exceptionDuringInit(model: Any, exception: Throwable) {
println("error initialising from model: '$model' - $exception")
println(exception)
}
override fun beforeUpdate(model: Any, event: Any) {
/* noop */
}
override fun afterUpdate(model: Any, event: Any, result: Next) {
/* noop */
}
override fun exceptionDuringUpdate(model: Any, event: Any, exception: Throwable) {
println("error updating model: '$model' with event: '$event' - $exception")
println(exception)
}
}
/**
* Create a [MobiusLoop.Builder] to help you configure a [MobiusLoop] before starting it.
*
* Once done configuring the loop you can start the loop using [MobiusLoop.Factory.startFrom]
*
* @param update the [Update] function of the loop
* @param effectHandler the [Connectable] effect handler of the loop
* @return a [MobiusLoop.Builder] instance that you can further configure before starting the loop
*/
@Suppress("UNCHECKED_CAST")
@JvmStatic
@JsName("loop")
fun loop(
update: Update,
effectHandler: Connectable
): MobiusLoop.Builder {
val defaultWorkRunners = DefaultWorkRunners()
return Builder(
update,
effectHandler,
NOOP_INIT as Init,
NOOP_EVENT_SOURCE as EventSource,
defaultWorkRunners.eventWorkRunnerProducer(),
defaultWorkRunners.effectWorkRunnerProducer(),
NOOP_LOGGER as MobiusLoop.Logger
)
}
/**
* Create a [MobiusLoop.Controller] that allows you to start, stop, and restart MobiusLoops.
*
* @param loopFactory a factory for creating loops
* @param defaultModel the model the controller should start from
* @return a new controller
*/
@JvmStatic
@JsName("controller")
fun controller(loopFactory: MobiusLoop.Factory, defaultModel: M): MobiusLoop.Controller {
return MobiusLoopController(loopFactory, defaultModel, ImmediateWorkRunner())
}
/**
* Create a [MobiusLoop.Controller] that allows you to start, stop, and restart MobiusLoops.
*
* @param loopFactory a factory for creating loops
* @param defaultModel the model the controller should start from
* @param modelRunner the WorkRunner to use when observing model changes
* @return a new controller
*/
@JvmStatic
@JsName("controllerWithModelRunner")
fun controller(
loopFactory: MobiusLoop.Factory,
defaultModel: M,
modelRunner: WorkRunner
): MobiusLoop.Controller {
return MobiusLoopController(loopFactory, defaultModel, modelRunner)
}
data class Builder(
private val update: Update,
private val effectHandler: Connectable,
private val init: Init,
private val eventSource: EventSource,
private val eventRunner: Producer,
private val effectRunner: Producer,
private val logger: MobiusLoop.Logger
) : MobiusLoop.Builder {
override fun init(init: Init): MobiusLoop.Builder {
return copy(init = init)
}
override fun eventSource(eventSource: EventSource): MobiusLoop.Builder {
return copy(eventSource = eventSource)
}
override fun eventSources(vararg eventSources: EventSource): MobiusLoop.Builder {
return copy(eventSource = MergedEventSource.from(*eventSources))
}
override fun logger(logger: MobiusLoop.Logger): MobiusLoop.Builder {
return copy(logger = logger)
}
override fun eventRunner(eventRunner: Producer): MobiusLoop.Builder {
return copy(eventRunner = eventRunner)
}
override fun effectRunner(effectRunner: Producer): MobiusLoop.Builder {
return copy(effectRunner = effectRunner)
}
override fun startFrom(startModel: M): MobiusLoop {
val loggingInit = LoggingInit(init, logger)
val loggingUpdate = LoggingUpdate(update, logger)
return MobiusLoop.create(
MobiusStore.create(loggingInit, loggingUpdate, startModel),
effectHandler,
eventSource,
eventRunner.get(),
effectRunner.get()
)
}
}
}