package com.suno.android.common_mvi import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.plus interface Mvi { val state: StateFlow val effects: SharedFlow fun sendEvent( event: Event, ) } abstract class MviViewModel( processorFactory: MviProcessorFactory, initialState: State, ) : ViewModel(), Mvi { private val processor by lazy { processorFactory.create( tag = this, initialState = initialState, coroutineScope = viewModelScope, reducer = ::reduceEvent, ) } protected val logger = processor.logger override val state: StateFlow = processor.state override val effects: SharedFlow = processor.effects override fun sendEvent( event: Event, ) = processor.sendEvent(event) protected fun emitEffect( effect: Effect, ) = processor.emitEffect(effect) protected fun emitAnalyticEffect( analyticEffect: AnalyticEffect, ) = processor.analyticEffect(analyticEffect) protected val upstreamFlows: FlowBinder by lazy { FlowBinder( scope = viewModelScope, dispatch = ::sendEvent, logError = { throwable -> logger.e(throwable) }, ) } @Deprecated( message = "Use Internal Events, Keep State Updates in Reducer", level = DeprecationLevel.WARNING, ) protected fun updateState( reducer: (State) -> State, ) = processor.updateState(reducer) protected abstract suspend fun reduceEvent( currentState: State, event: Event, emitEffect: suspend (Effect) -> Unit, ): State } interface Disposable { fun onClear() } abstract class MviController( processorFactory: MviProcessorFactory, coroutineScope: CoroutineScope, initialState: State, ) : Mvi, Disposable { private val processor by lazy { processorFactory.create( tag = this, initialState = initialState, coroutineScope = coroutineScope, reducer = ::reduceEvent, ) } protected val logger = processor.logger override val state: StateFlow = processor.state override val effects: SharedFlow = processor.effects override fun sendEvent( event: Event, ) = processor.sendEvent(event) protected fun emitEffect( effect: Effect, ) = processor.emitEffect(effect) protected fun emitAnalyticEffect( analyticEffect: AnalyticEffect, ) = processor.analyticEffect(analyticEffect) @Deprecated( message = "Use Internal Events, Keep State Updates in Reducer", level = DeprecationLevel.WARNING, ) protected fun updateState( reducer: (State) -> State, ) = processor.updateState(reducer) protected val upstreamFlows: FlowBinder by lazy { FlowBinder( scope = controllerScope, dispatch = ::sendEvent, logError = { throwable -> logger.e(throwable) }, ) } protected abstract suspend fun reduceEvent( currentState: State, event: Event, emitEffect: suspend (Effect) -> Unit, ): State private val controllerJob = SupervisorJob() protected val controllerScope: CoroutineScope = coroutineScope + controllerJob override fun onClear() { controllerJob.cancel() } }