Skip to content

Commit

Permalink
State разделен на мутабельную и немутабельную часть, FlowState переим…
Browse files Browse the repository at this point in the history
…енован
  • Loading branch information
Alexey Ryabkov committed Oct 2, 2024
1 parent c7f8789 commit 4311a67
Show file tree
Hide file tree
Showing 18 changed files with 46 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
package ru.surfstudio.mvi.core.reducer

import ru.surfstudio.mvi.core.event.Event
import ru.surfstudio.mvi.core.state.MutableState
import ru.surfstudio.mvi.core.state.StateHolder

/**
* [Reducer] in terms of `Redux`:
Expand All @@ -26,9 +26,9 @@ import ru.surfstudio.mvi.core.state.MutableState
*
* [Reducers documentation](https://redux.js.org/basics/reducers)
*/
interface Reducer<E : Event, State> : Reactor<E, MutableState<State, *>> {
interface Reducer<E : Event, State> : Reactor<E, StateHolder<State>> {

override fun react(sh: MutableState<State, *>, event: E) {
override fun react(sh: StateHolder<State>, event: E) {
val oldState = sh.currentState
val newState = reduce(oldState, event)
if (isStateChanged(oldState, newState)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ package ru.surfstudio.mvi.core.state
/**
* State that could be modified by emitting new value
*/
interface MutableState<State, ImmutableStateStream> : ImmutableState<State, ImmutableStateStream> {
interface MutableState<State> {

/**
* Emits [newState] and notifies all subscribers
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ru.surfstudio.mvi.core.state

import kotlinx.coroutines.flow.Flow

/**
* State that could be observed and changed.
*/
interface StateHolder<S>: MutableState<S>, ImmutableState<S, Flow<S>>
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ package ru.surfstudio.mvi.flow

import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import ru.surfstudio.mvi.core.state.MutableState
import ru.surfstudio.mvi.core.state.StateHolder

/**
* State implementing with Coroutines Flow, that could be observed and changed.
*/
class FlowState<S>(initialState: S): MutableState<S, Flow<S>> {
class FlowStateHolder<S>(initialState: S) : StateHolder<S> {

private val mutableFlow = MutableStateFlow(initialState)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import ru.surfstudio.mvi.core.reducer.Reducer
import ru.surfstudio.mvi.flow.DslFlowMiddleware
import ru.surfstudio.mvi.flow.FlowBinder
import ru.surfstudio.mvi.flow.FlowEventHub
import ru.surfstudio.mvi.flow.FlowState
import ru.surfstudio.mvi.flow.FlowStateHolder

/**
* An interface of ViewModel providing implementations of observable
Expand All @@ -45,11 +45,11 @@ abstract class MviViewModel<E : Event> : ViewModel(), FlowBinder {
*/
abstract class MviStatefulViewModel<S : Any, E : Event>: MviViewModel<E>() {

abstract val state: FlowState<S>
abstract val stateHolder: FlowStateHolder<S>
abstract val reducer: Reducer<E, S>

/** Must be called in descendant class `init` */
override fun bindFlow() {
viewModelScope.bind(hub, middleware, state, reducer)
viewModelScope.bind(hub, middleware, stateHolder, reducer)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ interface MviStatefulView<S : Any, E : Event> : MviView<E> {
*/
fun observeState(collector: suspend (S) -> Unit) {
uiScope.launch(Dispatchers.Main) {
viewModel.state
viewModel.stateHolder
.observeState()
.collect { collector(it) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import ru.surfstudio.mvi.vm.MviStatefulViewModel
infix fun <S : Any, E : Event> MviStatefulViewModel<S, E>.renders(
render: @Composable ComposedViewContext<E>.(S) -> Unit
) {
val state by state.observeState().collectAsState(initial = state.currentState)
val state by stateHolder.observeState().collectAsState(initial = stateHolder.currentState)
val scope = rememberCoroutineScope()

val composedViewContext = ComposedViewContext<E> { event ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import ru.surfstudio.mvi.core.event.Event
import ru.surfstudio.mvi.core.reducer.Reducer
import ru.surfstudio.mvi.flow.DslFlowMiddleware
import ru.surfstudio.mvi.flow.FlowEventHub
import ru.surfstudio.mvi.flow.FlowState
import ru.surfstudio.mvi.flow.FlowStateHolder
import ru.surfstudio.mvi.vm.MviStatefulViewModel
import ru.surfstudio.mvi.vm.android.MviStatefulView

Expand Down Expand Up @@ -99,7 +99,7 @@ class TestViewModel(
reducer: TestReducer
) : MviStatefulViewModel<TestState, TestEvent>() {

override val state: FlowState<TestState> = FlowState(TestState())
override val stateHolder: FlowStateHolder<TestState> = FlowStateHolder(TestState())
override val hub: FlowEventHub<TestEvent> = FlowEventHub()
override val reducer: Reducer<TestEvent, TestState> = reducer
override val middleware: DslFlowMiddleware<TestEvent> = middleware
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class MviCoreTest : BaseFlowTest() {

@Test
fun testStateChanges() = runTest {
val flow = testView?.viewModel?.state?.observeState()
val flow = testView?.viewModel?.stateHolder?.observeState()

Assert.assertEquals(flow?.firstOrNull()?.state, INITIAL_STATE_VALUE)
testView?.emit(TestEvent.Data("test"))
Expand All @@ -57,7 +57,7 @@ class MviCoreTest : BaseFlowTest() {

@Test
fun testStateUnchangedOnLogic() = runTest {
val flow = testView?.viewModel?.state?.observeState()
val flow = testView?.viewModel?.stateHolder?.observeState()

Assert.assertEquals(flow?.firstOrNull()?.state, INITIAL_STATE_VALUE)
testView?.emit(TestEvent.Logic)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ interface MVIErrorHandlerView<S : Any, E : Event> {
*/
fun observeState(collector: suspend (S) -> Unit) {
uiScope.launch(Dispatchers.Main) {
viewModel.state
viewModel.stateHolder
.observeState()
.collect { collector(it) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
package ru.surfstudio.mvi.flow.app.compose.standard

import ru.surfstudio.mvi.flow.FlowState
import ru.surfstudio.mvi.flow.FlowStateHolder
import ru.surfstudio.mvi.flow.app.reused.error.ErrorHandlerImpl
import ru.surfstudio.mvi.flow.app.network.IpNetworkCreator
import ru.surfstudio.mvi.flow.app.reused.NetworkCommandEvent
Expand All @@ -29,7 +29,7 @@ import ru.surfstudio.mvi.vm.compose.emitCommand
class ComposeViewModel : MviErrorHandlerViewModel<NetworkState, NetworkEvent>(),
CommandObserver<NetworkEvent, NetworkCommandEvent> {

override val state: FlowState<NetworkState> = FlowState(NetworkState())
override val stateHolder: FlowStateHolder<NetworkState> = FlowStateHolder(NetworkState())
override val middleware: ComposeMiddleware =
ComposeMiddleware(IpNetworkCreator.repository)
override val reducer: NetworkReducer = NetworkReducer(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
package ru.surfstudio.mvi.flow.app.handler

import kotlinx.coroutines.CoroutineDispatcher
import ru.surfstudio.mvi.flow.FlowState
import ru.surfstudio.mvi.flow.FlowStateHolder
import ru.surfstudio.mvi.flow.app.reused.error.ErrorHandlerImpl
import ru.surfstudio.mvi.flow.app.network.IpRepository
import ru.surfstudio.mvi.flow.app.reused.NetworkCommandEvent
Expand All @@ -34,7 +34,7 @@ class HandlerViewModel(
) : MviErrorHandlerViewModel<NetworkState, NetworkEvent>(),
CommandObserver<NetworkEvent, NetworkCommandEvent> {

override val state: FlowState<NetworkState> = FlowState(NetworkState())
override val stateHolder: FlowStateHolder<NetworkState> = FlowStateHolder(NetworkState())
override val middleware: HandlerMiddleware =
HandlerMiddleware(loadOnStart, repository, dispatcher)
override val reducer: NetworkReducer = NetworkReducer(ErrorHandlerImpl(), ::emitCommand)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import ru.surfstudio.mvi.flow.app.handler.HandlerActivity
import ru.surfstudio.mvi.flow.app.simple.request.RequestState
import ru.surfstudio.mvi.vm.android.MviStatefulView

class SimpleActivity : AppCompatActivity(), MviStatefulView<SimpleState, SimpleEvent> {
internal class SimpleActivity : AppCompatActivity(), MviStatefulView<SimpleState, SimpleEvent> {

override val viewModel by viewModels<SimpleViewModel>()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import ru.surfstudio.mvi.core.event.Event
import ru.surfstudio.mvi.core.event.MviLifecycleEvent
import ru.surfstudio.mvi.flow.app.simple.request.RequestState

sealed class SimpleEvent : Event {
internal sealed class SimpleEvent : Event {

data class LifecycleEvent(override var event: Lifecycle.Event) : SimpleEvent(),
MviLifecycleEvent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,23 @@ import androidx.lifecycle.Lifecycle
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import ru.surfstudio.mvi.flow.BaseFlowMiddleware
import ru.surfstudio.mvi.flow.FlowState
import ru.surfstudio.mvi.flow.FlowStateHolder
import ru.surfstudio.mvi.flow.app.simple.request.RequestState
import ru.surfstudio.mvi.flow.app.simple.SimpleEvent.*
import java.io.IOException

class SimpleMiddleware(
private val state: FlowState<SimpleState>
internal class SimpleMiddleware(
private val stateHolder: FlowStateHolder<SimpleState>
) : BaseFlowMiddleware<SimpleEvent> {

private val state: SimpleState
get() = stateHolder.currentState

override fun transform(eventStream: Flow<SimpleEvent>): Flow<SimpleEvent> {
return eventStream.transformations {
addAll(
StartLoadingClick::class
filter { state.currentState.request == RequestState.None }
filter { state.request == RequestState.None }
streamToStream { requestFlow(it) },
SimpleClick::class react {
println("debug react sample")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ package ru.surfstudio.mvi.flow.app.simple
import ru.surfstudio.mvi.core.reducer.Reducer
import ru.surfstudio.mvi.flow.app.simple.request.RequestState

data class SimpleState(
internal data class SimpleState(
val title: String = "Кликай меня полностью",
val counter: Int = 42,
val request: RequestState = RequestState.None
)

class SimpleReducer: Reducer<SimpleEvent, SimpleState> {
internal class SimpleReducer: Reducer<SimpleEvent, SimpleState> {

override fun reduce(state: SimpleState, event: SimpleEvent): SimpleState {
return when(event) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,16 @@
*/
package ru.surfstudio.mvi.flow.app.simple

import ru.surfstudio.mvi.flow.FlowState
import ru.surfstudio.mvi.flow.FlowStateHolder
import ru.surfstudio.mvi.vm.MviStatefulViewModel

class SimpleViewModel : MviStatefulViewModel<SimpleState, SimpleEvent>() {
internal class SimpleViewModel : MviStatefulViewModel<SimpleState, SimpleEvent>() {

override val state: FlowState<SimpleState> = FlowState(SimpleState())
override val middleware: SimpleMiddleware = SimpleMiddleware(state)
override val stateHolder: FlowStateHolder<SimpleState> = FlowStateHolder(SimpleState())
override val middleware: SimpleMiddleware = SimpleMiddleware(stateHolder)
override val reducer: SimpleReducer = SimpleReducer()

init {
bindFlow()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ abstract class BaseMviScreenTest : BaseUnitTest() {
expectedStatesChecks: List<(S) -> Boolean>
) {
runTimeoutTest {
state.observeState().test {
stateHolder.observeState().test {
startEvent?.let { hub.emit(startEvent) }
(expectedStatesChecks.indices).forEach { index ->
val state = awaitItem()
Expand All @@ -111,7 +111,7 @@ abstract class BaseMviScreenTest : BaseUnitTest() {
expectedFinalStateCheck: (S) -> Boolean
) {
runTimeoutTest {
state.observeState().test {
stateHolder.observeState().test {
startEvents?.let { startEvents.forEach { hub.emit(it) } }
while (true) {
val state = awaitItem()
Expand All @@ -133,7 +133,7 @@ abstract class BaseMviScreenTest : BaseUnitTest() {
runTimeoutTest {
merge(
hub.observe().flatMapLatest { flowOf(MviData<S, E>(event = it)) },
state.observeState().flatMapLatest { flowOf(MviData(state = it)) },
stateHolder.observeState().flatMapLatest { flowOf(MviData(state = it)) },
).test {
startAction()
(expectedData.indices).forEach { index ->
Expand Down

0 comments on commit 4311a67

Please sign in to comment.