All Downloads are FREE. Search and download functionalities are using the official Maven repository.

me.aartikov.sesame.loading.simple.internal.LoadingLoop.kt Maven / Gradle / Ivy

package me.aartikov.sesame.loading.simple.internal

import me.aartikov.sesame.loading.simple.Loading.Event
import me.aartikov.sesame.loading.simple.Loading.State
import me.aartikov.sesame.loading.simple.isEmpty
import me.aartikov.sesame.loop.*

internal sealed class Action {
    data class Load(val fresh: Boolean, val reset: Boolean) : Action()
    data class Cancel(val reset: Boolean) : Action()
    data class MutateData(val transform: (T) -> T) : Action()

    data class DataLoaded(val data: T) : Action()
    object EmptyDataLoaded : Action()
    data class LoadingError(val throwable: Throwable) : Action()

    data class DataObserved(val data: T) : Action()
    object EmptyDataObserved : Action()
}

internal sealed class Effect {
    data class Load(val fresh: Boolean) : Effect()
    object CancelLoading : Effect()
    data class EmitEvent(val event: Event) : Effect()
}

internal typealias LoadingLoop = Loop, Action, Effect>

internal class LoadingReducer : Reducer, Action, Effect> {

    override fun reduce(state: State, action: Action): Next, Effect> = when (action) {

        is Action.Load -> {
            if (action.reset) {
                next(
                    State.Loading,
                    Effect.Load(action.fresh)
                )
            } else {
                when (state) {
                    is State.Empty -> next(
                        State.Loading,
                        Effect.Load(action.fresh)
                    )
                    is State.Data -> when (state.refreshing) {
                        false -> next(
                            State.Data(data = state.data, refreshing = true),
                            Effect.Load(action.fresh)
                        )
                        true -> nothing()
                    }
                    is State.Error -> next(
                        State.Loading,
                        Effect.Load(action.fresh)
                    )
                    else -> nothing()
                }
            }
        }

        is Action.Cancel -> {
            if (action.reset) {
                next(
                    State.Empty,
                    Effect.CancelLoading
                )
            } else {
                when (state) {
                    is State.Loading -> next(
                        State.Empty,
                        Effect.CancelLoading
                    )
                    is State.Data -> when (state.refreshing) {
                        false -> nothing()
                        true -> next(
                            State.Data(state.data),
                            Effect.CancelLoading
                        )
                    }
                    else -> nothing()
                }
            }
        }

        is Action.DataLoaded -> {
            when (state) {
                is State.Loading -> next(State.Data(action.data))
                is State.Data -> when (state.refreshing) {
                    false -> nothing()
                    true -> next(State.Data(action.data))
                }
                else -> nothing()
            }
        }

        is Action.EmptyDataLoaded -> {
            when (state) {
                is State.Loading -> next(State.Empty)
                is State.Data -> when (state.refreshing) {
                    false -> nothing()
                    true -> next(State.Empty)
                }
                else -> nothing()
            }
        }

        is Action.LoadingError -> {
            when (state) {
                is State.Loading -> next(
                    State.Error(action.throwable),
                    Effect.EmitEvent(Event.Error(action.throwable, state))
                )
                is State.Data -> when (state.refreshing) {
                    false -> nothing()
                    true -> next(
                        State.Data(state.data),
                        Effect.EmitEvent(Event.Error(action.throwable, state))
                    )
                }
                else -> nothing()
            }
        }

        is Action.DataObserved -> {
            when (state) {
                is State.Empty -> next(State.Data(action.data))
                is State.Loading -> next(State.Data(action.data, refreshing = true))
                is State.Data -> next(State.Data(action.data, refreshing = state.refreshing))
                is State.Error -> next(State.Data(action.data))
            }
        }

        is Action.EmptyDataObserved -> {
            when (state) {
                is State.Data -> when (state.refreshing) {
                    false -> next(State.Empty)
                    true -> next(State.Loading)
                }
                else -> nothing()
            }
        }

        is Action.MutateData -> when (state) {
            is State.Data -> {
                val newData = action.transform(state.data)
                when {
                    !isEmpty(newData) -> next(state.copy(data = newData))
                    state.refreshing -> next(State.Loading)
                    else -> next(State.Empty)
                }
            }
            else -> nothing()
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy