Untitled

mail@pastecode.io avatar
unknown
kotlin
2 years ago
2.2 kB
2
Indexable
Never
package com.voraapp.vora.base

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch

abstract class BaseViewModel<S : State, A : Action, E : Effect, H : ActionHandler<S, A>>(
    private val actionHandler: H,
) : ViewModel() {

    abstract val initialState: S

    private val _states: MutableStateFlow<S> by lazy { MutableStateFlow(initialState) }

    val states: StateFlow<S>
        get() = _states

    private val actions = Channel<A>()
    val effects = Channel<E>()

    fun offer(action: A) {
        viewModelScope.launch {
            actions.send(action)
        }
    }

    @Suppress("UNCHECKED_CAST")
    protected fun observeActions() {
        viewModelScope.launch {
            actions.receiveAsFlow().onEach {
                when (val action = actionHandler.handle(states.value, it)) {
                    is EffectResult -> {
                        sendEffects(action.effects as List<E>)
                    }
                    is StateResult -> {
                        println("sinan: state: ${action.state}")
                        _states.emit(action.state as S)
                    }
                }

            }.collect()
        }
    }

    private suspend fun sendEffects(effects: List<E>) {
        effects.forEach {
            this.effects.send(it)
        }
    }

}

abstract class ActionHandler<S : State, A : Action> {
    abstract suspend fun handle(state: S, action: A): Result
}

fun <E : Effect> ActionHandler<*, *>.effect(e: E): Result = EffectResult(listOf(e))
fun <E : Effect> ActionHandler<*, *>.effects(e: List<E>): Result = EffectResult(e)
fun <S : State> ActionHandler<S, *>.state(s: S): Result = StateResult(s)

interface Action

interface State

interface Effect

sealed class Result
internal data class EffectResult(val effects: List<Effect>) : Result()
internal data class StateResult(val state: State) : Result()