added mediators for logging
This commit is contained in:
parent
468b1ef820
commit
eb32192b34
|
|
@ -5,6 +5,7 @@ dependencies {
|
|||
implementation project(":navigation-base")
|
||||
implementation project(":lifecycle")
|
||||
implementation project(":kotlin-extensions")
|
||||
implementation project(":logging")
|
||||
|
||||
implementation("androidx.core:core-ktx")
|
||||
implementation("androidx.appcompat:appcompat")
|
||||
|
|
@ -23,6 +24,8 @@ dependencies {
|
|||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android")
|
||||
|
||||
implementation("com.tylerthrailkill.helpers:pretty-print:2.0.2")
|
||||
|
||||
def fragmentVersion = "1.2.1"
|
||||
def lifecycleVersion = "2.2.0"
|
||||
def coroutinesVersion = "1.3.7"
|
||||
|
|
|
|||
|
|
@ -1,12 +1,19 @@
|
|||
package ru.touchin.roboswag.mvi_arch.core
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.Transformations
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.launch
|
||||
import ru.touchin.mvi_arch.BuildConfig
|
||||
import ru.touchin.roboswag.mvi_arch.marker.ViewAction
|
||||
import ru.touchin.roboswag.mvi_arch.marker.ViewState
|
||||
import ru.touchin.roboswag.mvi_arch.mediator.LoggingMediator
|
||||
import ru.touchin.roboswag.mvi_arch.mediator.MediatorStore
|
||||
|
||||
/**
|
||||
* Base [ViewModel] to use in MVI architecture.
|
||||
|
|
@ -33,6 +40,12 @@ abstract class MviViewModel<NavArgs : Parcelable, Action : ViewAction, State : V
|
|||
protected val handle: SavedStateHandle
|
||||
) : ViewModel() {
|
||||
|
||||
private val mediatorStore = MediatorStore(
|
||||
listOfNotNull(
|
||||
LoggingMediator(this::class.simpleName!!).takeIf { BuildConfig.DEBUG }
|
||||
)
|
||||
)
|
||||
|
||||
protected val navArgs: NavArgs = handle.get(MviFragment.INIT_ARGS_KEY) ?: throw IllegalStateException("Nav args mustn't be null")
|
||||
|
||||
protected val _state = MutableLiveData(initialState)
|
||||
|
|
@ -41,6 +54,22 @@ abstract class MviViewModel<NavArgs : Parcelable, Action : ViewAction, State : V
|
|||
protected val currentState: State
|
||||
get() = _state.value ?: initialState
|
||||
|
||||
abstract fun dispatchAction(action: Action)
|
||||
private val stateMediatorObserver = Observer<State>(mediatorStore::onNewState)
|
||||
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
state.observeForever(stateMediatorObserver)
|
||||
}
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
open fun dispatchAction(action: Action) {
|
||||
mediatorStore.onAction(action)
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
super.onCleared()
|
||||
state.removeObserver(stateMediatorObserver)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,9 +14,12 @@ import kotlinx.coroutines.flow.filterNotNull
|
|||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import ru.touchin.mvi_arch.BuildConfig
|
||||
import ru.touchin.roboswag.mvi_arch.marker.SideEffect
|
||||
import ru.touchin.roboswag.mvi_arch.marker.StateChange
|
||||
import ru.touchin.roboswag.mvi_arch.marker.ViewState
|
||||
import ru.touchin.roboswag.mvi_arch.mediator.LoggingMediator
|
||||
import ru.touchin.roboswag.mvi_arch.mediator.MediatorStore
|
||||
|
||||
abstract class Store<Change : StateChange, Effect : SideEffect, State : ViewState>(
|
||||
initialState: State
|
||||
|
|
@ -32,6 +35,12 @@ abstract class Store<Change : StateChange, Effect : SideEffect, State : ViewStat
|
|||
|
||||
private val childStores: MutableList<ChildStore<*, *, *>> = mutableListOf()
|
||||
|
||||
private val mediatorStore = MediatorStore(
|
||||
listOfNotNull(
|
||||
LoggingMediator(this::class.simpleName!!).takeIf { BuildConfig.DEBUG }
|
||||
)
|
||||
)
|
||||
|
||||
init {
|
||||
storeScope.launch {
|
||||
effects
|
||||
|
|
@ -43,10 +52,13 @@ abstract class Store<Change : StateChange, Effect : SideEffect, State : ViewStat
|
|||
}
|
||||
|
||||
fun changeState(change: Change) {
|
||||
mediatorStore.onStateChange(change)
|
||||
|
||||
val (newState, newEffect) = reduce(currentState, change)
|
||||
|
||||
if (currentState != newState) {
|
||||
state.value = newState
|
||||
mediatorStore.onNewState(newState)
|
||||
}
|
||||
|
||||
childStores.forEach { childStore ->
|
||||
|
|
@ -55,6 +67,7 @@ abstract class Store<Change : StateChange, Effect : SideEffect, State : ViewStat
|
|||
|
||||
newEffect?.let {
|
||||
effects.offer(it)
|
||||
mediatorStore.onEffect(it)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
package ru.touchin.roboswag.mvi_arch.mediator
|
||||
|
||||
import com.tylerthrailkill.helpers.prettyprint.pp
|
||||
import ru.touchin.roboswag.core.log.Lc
|
||||
import ru.touchin.roboswag.mvi_arch.marker.SideEffect
|
||||
import ru.touchin.roboswag.mvi_arch.marker.StateChange
|
||||
import ru.touchin.roboswag.mvi_arch.marker.ViewAction
|
||||
import ru.touchin.roboswag.mvi_arch.marker.ViewState
|
||||
|
||||
class LoggingMediator(private val objectName: String) : Mediator {
|
||||
override fun onEffect(effect: SideEffect) {
|
||||
logObject(
|
||||
prefix = "New Effect:\n",
|
||||
obj = effect
|
||||
)
|
||||
}
|
||||
|
||||
override fun onAction(action: ViewAction) {
|
||||
logObject(
|
||||
prefix = "New Action:\n",
|
||||
obj = action
|
||||
)
|
||||
}
|
||||
|
||||
override fun onNewState(state: ViewState) {
|
||||
logObject(
|
||||
prefix = "New State:\n",
|
||||
obj = state
|
||||
)
|
||||
}
|
||||
|
||||
override fun onStateChange(change: StateChange) {
|
||||
logObject(
|
||||
prefix = "New State change:\n",
|
||||
obj = change
|
||||
)
|
||||
}
|
||||
|
||||
private fun <T> logObject(
|
||||
prefix: String,
|
||||
obj: T
|
||||
) {
|
||||
val builder = StringBuilder()
|
||||
pp(obj = obj, writeTo = builder)
|
||||
|
||||
val prettyOutput = builder.toString()
|
||||
Lc.d("$objectName: $prefix$prettyOutput\n")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package ru.touchin.roboswag.mvi_arch.mediator
|
||||
|
||||
import ru.touchin.roboswag.mvi_arch.marker.SideEffect
|
||||
import ru.touchin.roboswag.mvi_arch.marker.StateChange
|
||||
import ru.touchin.roboswag.mvi_arch.marker.ViewAction
|
||||
import ru.touchin.roboswag.mvi_arch.marker.ViewState
|
||||
|
||||
interface Mediator {
|
||||
|
||||
fun onEffect(effect: SideEffect)
|
||||
|
||||
fun onAction(action: ViewAction)
|
||||
|
||||
fun onNewState(state: ViewState)
|
||||
|
||||
fun onStateChange(change: StateChange)
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package ru.touchin.roboswag.mvi_arch.mediator
|
||||
|
||||
import ru.touchin.roboswag.mvi_arch.marker.SideEffect
|
||||
import ru.touchin.roboswag.mvi_arch.marker.StateChange
|
||||
import ru.touchin.roboswag.mvi_arch.marker.ViewAction
|
||||
import ru.touchin.roboswag.mvi_arch.marker.ViewState
|
||||
|
||||
class MediatorStore(private val mediators: List<Mediator>) : Mediator {
|
||||
|
||||
override fun onAction(action: ViewAction) {
|
||||
mediators.forEach { it.onAction(action) }
|
||||
}
|
||||
|
||||
override fun onEffect(effect: SideEffect) {
|
||||
mediators.forEach { it.onEffect(effect) }
|
||||
}
|
||||
|
||||
override fun onNewState(state: ViewState) {
|
||||
mediators.forEach { it.onNewState(state) }
|
||||
}
|
||||
|
||||
override fun onStateChange(change: StateChange) {
|
||||
mediators.forEach { it.onStateChange(change) }
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue