package com.alorma.github.presenter;
import android.support.annotation.Nullable;
import com.alorma.github.injector.named.IOScheduler;
import com.alorma.github.injector.named.MainScheduler;
import core.datasource.SdkItem;
import core.repository.GenericRepository;
import java.util.concurrent.TimeUnit;
import rx.Observable;
import rx.Scheduler;
import rx.Subscriber;
/**
* Represents base RxJava presenter.
* Just only one Observable could be subscribed to it.
*/
public abstract class BaseRxPresenter<REQUEST, RESPONSE, VIEW extends View<RESPONSE>> extends BasePresenter<VIEW> {
protected final Scheduler mainScheduler;
protected final Scheduler ioScheduler;
private final GenericRepository<REQUEST, RESPONSE> genericRepository;
protected Subscriber<RESPONSE> subscriber;
private Integer page;
public BaseRxPresenter(@MainScheduler Scheduler mainScheduler, @IOScheduler Scheduler ioScheduler,
GenericRepository<REQUEST, RESPONSE> genericRepository) {
this.mainScheduler = mainScheduler;
this.ioScheduler = ioScheduler;
this.genericRepository = genericRepository;
}
/**
* Executes request doesn't assign page to request.
*
* @param request item to execute
* @see #executePaginated(Object)
*/
public void execute(REQUEST request) {
if (!isViewAttached()) return;
SdkItem<REQUEST> sdkItem = new SdkItem<>(request);
subscribe(genericRepository.execute(sdkItem), false);
}
/**
* Executes paginated request, automagically assigns next page if is requested more than one time.
*
* @param request item to execute
* @see #execute(Object)
*/
public void executePaginated(REQUEST request) {
if (!isViewAttached() || page == null || page <= 0) return;
SdkItem<REQUEST> sdkItem = new SdkItem<>(request);
sdkItem.setPage(page);
subscribe(genericRepository.execute(sdkItem), true);
}
/**
* Creates internal subscriber and attaches it to observable argument.
*
* @param observable the object to subscribe
* @param isFromPaginated indicates that request is paginated or not
*/
protected void subscribe(Observable<SdkItem<RESPONSE>> observable, boolean isFromPaginated) {
if (!isViewAttached()) return;
getView().showLoading();
unsubscribe();
subscriber = new Subscriber<RESPONSE>() {
@Override
public void onCompleted() {
BaseRxPresenter.this.onCompleted();
}
@Override
public void onError(Throwable e) {
BaseRxPresenter.this.onError(e);
}
@Override
public void onNext(RESPONSE response) {
BaseRxPresenter.this.onNext(response, isFromPaginated);
}
};
observable.subscribeOn(ioScheduler).observeOn(mainScheduler).timeout(20, TimeUnit.SECONDS).retry(3).map(obs -> {
if (obs.getPage() != null && obs.getPage() > 0) {
this.page = obs.getPage();
} else {
this.page = null;
}
return obs.getK();
}).subscribe(subscriber);
}
/**
* Unsubscribes internal subscriber and set it to null.
*/
protected void unsubscribe() {
if (subscriber != null && !subscriber.isUnsubscribed()) {
subscriber.unsubscribe();
}
subscriber = null;
}
protected void onCompleted() {
if (isViewAttached()) {
getView().hideLoading();
}
unsubscribe();
}
protected void onError(Throwable throwable) {
if (isViewAttached()) {
getView().showError(throwable);
getView().hideLoading();
throwable.printStackTrace();
}
unsubscribe();
}
protected void onNext(RESPONSE response, boolean isFromPaginated) {
if (isViewAttached()) {
getView().onDataReceived(response, isFromPaginated);
}
}
@Override
public void detachView() {
super.detachView();
if (isViewAttached()) {
getView().hideLoading();
}
unsubscribe();
}
@Nullable
public Integer getPage() {
return page;
}
}