public class BehavioursCoordinator<T> implements FlowableTransformer<T, T> {

    private AssignEmptyState<T> dealWithEmptyState;
    private AssignErrorState<T> assignErrorState;
    private LoadingCoordination<T> loadingCoordinator;
    private NetworkingErrorFeedback<T> networkingErrorFeedback;
    private RefreshToogle<T> refreshToogle;

    public BehavioursCoordinator(AssignEmptyState<T> dealWithEmptyState,
                                 AssignErrorState<T> assignErrorState,
                                 LoadingCoordination<T> loadingCoordinator,
                                 NetworkingErrorFeedback<T> networkingErrorFeedback,
                                 RefreshToogle<T> refreshToogle) {

        this.dealWithEmptyState = dealWithEmptyState;
        this.assignErrorState = assignErrorState;
        this.loadingCoordinator = loadingCoordinator;
        this.networkingErrorFeedback = networkingErrorFeedback;
        this.refreshToogle = refreshToogle;
    }

    @Override public Publisher<T> apply(Flowable<T> upstream) {
        return upstream
                .compose(dealWithEmptyState)
                .compose(assignErrorState)
                .compose(loadingCoordinator)
                .compose(refreshToogle)
                .compose(networkingErrorFeedback);
    }
} public class AssignEmptyState<T> implements FlowableTransformer<T, T> {

    private EmptyStateView view;
    private Scheduler uiScheduler;

    public AssignEmptyState(EmptyStateView view, Scheduler uiScheduler) {
        this.view = view;
        this.uiScheduler = uiScheduler;
    }

    @Override public Publisher<T> apply(Flowable<T> upstream) {

        HideAtStartShowAtError<T> delegate = new HideAtStartShowAtError<>(
                view.hideEmptyState(),
                view.showEmptyState(),
                error -> error instanceof ContentNotFoundError,
                uiScheduler
        );

        return upstream.compose(delegate);
    }

} public interface EmptyStateView {

    Action showEmptyState();

    Action hideEmptyState();

} public class AssignErrorState<T> implements FlowableTransformer<T, T> {

    private ErrorStateView view;
    private Scheduler uiScheduler;

    public AssignErrorState(ErrorStateView view, Scheduler uiScheduler) {
        this.view = view;
        this.uiScheduler = uiScheduler;
    }

    @Override public Publisher<T> apply(Flowable<T> upstream) {
        HideAtStartShowAtError<T> delegate = new HideAtStartShowAtError<>(
                view.hideErrorState(),
                view.showErrorState(),
                error -> !(error instanceof ContentNotFoundError),
                uiScheduler
        );

        return upstream.compose(delegate);
    }

} public interface ErrorStateView {

    Action showErrorState();

    Action hideErrorState();

} public class LoadingCoordination<T> implements FlowableTransformer<T, T> {

    private LoadingView view;
    private Scheduler uiScheduler;

    public LoadingCoordination(LoadingView view,
                               Scheduler uiScheduler) {
        this.view = view;
        this.uiScheduler = uiScheduler;
    }

    @Override public Publisher<T> apply(Flowable<T> upstream) {

        ShowAtStartHideWhenDone<T> delegate = new ShowAtStartHideWhenDone<>(
                view.showLoading(),
                view.hideLoading(),
                uiScheduler
        );

        return upstream.compose(delegate);
    }

} public interface LoadingView {

    Action showLoading();

    Action hideLoading();

} public interface NetworkingErrorView {

    Action reportNetworkingError();

} public class NetworkingErrorFeedback<T> implements FlowableTransformer<T, T> {

    private NetworkingErrorView view;
    private Scheduler uiScheduler;

    public NetworkingErrorFeedback(NetworkingErrorView view, Scheduler uiScheduler) {
        this.view = view;
        this.uiScheduler = uiScheduler;
    }

    @Override public Publisher<T> apply(Flowable<T> upstream) {
        return upstream.doOnError(this::handleIfNetworkingError);
    }

    private Publisher<T> handleIfNetworkingError(Throwable throwable) {

        if (throwable instanceof NetworkingError) {
            Completable.fromAction(view.reportNetworkingError())
                    .observeOn(uiScheduler)
                    .subscribe();
        }

        return Flowable.error(throwable);
    }

} public class RefreshToogle<T> implements FlowableTransformer<T, T> {

    private final ToogleRefreshView view;
    private Scheduler targetScheduler;

    public RefreshToogle(ToogleRefreshView view, Scheduler targetScheduler) {
        this.view = view;
        this.targetScheduler = targetScheduler;
    }

    @Override public Publisher<T> apply(Flowable<T> upstream) {
        return upstream
                .doOnSubscribe(subscription -> fireAction(view.disableRefresh()))
                .doOnError(this::enableForSpecialErrorCase)
                .doOnComplete(() -> fireAction(view.enableRefresh()));
    }

    private void enableForSpecialErrorCase(Throwable throwable) {
        if (!(throwable instanceof UnexpectedResponseError)) fireAction(view.enableRefresh());
    }

    private void fireAction(Action toPerform) {
        Completable.fromAction(toPerform)
                .subscribeOn(targetScheduler)
                .subscribe();
    }

} public interface ToogleRefreshView {

    Action disableRefresh();

    Action enableRefresh();

}
import br.ufs.demos.rxmvp.playground.dagger.qualifiers.UIScheduler;
import br.ufs.demos.rxmvp.playground.core.behaviours.BehavioursCoordinator;
import br.ufs.demos.rxmvp.playground.core.behaviours.emptystate.AssignEmptyState;
import br.ufs.demos.rxmvp.playground.core.behaviours.emptystate.EmptyStateView;
import br.ufs.demos.rxmvp.playground.core.behaviours.errorstate.AssignErrorState;
import br.ufs.demos.rxmvp.playground.core.behaviours.errorstate.ErrorStateView;
import br.ufs.demos.rxmvp.playground.core.behaviours.loadingcontent.LoadingCoordination;
import br.ufs.demos.rxmvp.playground.core.behaviours.loadingcontent.LoadingView;
import br.ufs.demos.rxmvp.playground.core.behaviours.networking.NetworkingErrorView;
import br.ufs.demos.rxmvp.playground.core.behaviours.networking.NetworkingErrorFeedback;
import br.ufs.demos.rxmvp.playground.core.behaviours.tooglerefresh.RefreshToogle;
import br.ufs.demos.rxmvp.playground.core.behaviours.tooglerefresh.ToogleRefreshView;
import dagger.Module;
import dagger.Provides;
import io.reactivex.Scheduler;
package br.ufs.demos.rxmvp.playground.dagger.modules;


/**
 * Created by bira on 7/5/17.
 */

@Module
public class BehavioursModule {

    @Provides static BehavioursCoordinator coordinator(
            AssignEmptyState assignEmptyState,
            AssignErrorState assignErrorState,