diff --git a/src/main/java/ru/touchin/roboswag/components/adapters/BindableViewHolder.java b/src/main/java/ru/touchin/roboswag/components/adapters/BindableViewHolder.java index 227d23d..37c2e28 100644 --- a/src/main/java/ru/touchin/roboswag/components/adapters/BindableViewHolder.java +++ b/src/main/java/ru/touchin/roboswag/components/adapters/BindableViewHolder.java @@ -33,7 +33,9 @@ import android.view.View; import ru.touchin.roboswag.components.utils.LifecycleBindable; import ru.touchin.roboswag.core.utils.ShouldNotHappenException; +import rx.Completable; import rx.Observable; +import rx.Single; import rx.Subscription; import rx.functions.Action0; import rx.functions.Action1; @@ -154,6 +156,46 @@ public class BindableViewHolder extends RecyclerView.ViewHolder implements Lifec return baseLifecycleBindable.untilStop(observable, onNextAction, onErrorAction, onCompletedAction); } + @NonNull + @Override + public Subscription untilStop(@NonNull final Single single) { + return baseLifecycleBindable.untilStop(single); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Single single, @NonNull final Action1 onSuccessAction) { + return baseLifecycleBindable.untilStop(single, onSuccessAction); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Single single, + @NonNull final Action1 onSuccessAction, + @NonNull final Action1 onErrorAction) { + return baseLifecycleBindable.untilStop(single, onSuccessAction, onErrorAction); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Completable completable) { + return baseLifecycleBindable.untilStop(completable); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Completable completable, @NonNull final Action0 onCompletedAction) { + return baseLifecycleBindable.untilStop(completable, onCompletedAction); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Completable completable, + @NonNull final Action0 onCompletedAction, + @NonNull final Action1 onErrorAction) { + return baseLifecycleBindable.untilStop(completable, onCompletedAction, onErrorAction); + } + @NonNull @Override public Subscription untilDestroy(@NonNull final Observable observable) { @@ -183,4 +225,44 @@ public class BindableViewHolder extends RecyclerView.ViewHolder implements Lifec return baseLifecycleBindable.untilDestroy(observable, onNextAction, onErrorAction, onCompletedAction); } + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Single single) { + return baseLifecycleBindable.untilDestroy(single); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Single single, @NonNull final Action1 onSuccessAction) { + return baseLifecycleBindable.untilDestroy(single, onSuccessAction); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Single single, + @NonNull final Action1 onSuccessAction, + @NonNull final Action1 onErrorAction) { + return baseLifecycleBindable.untilDestroy(single, onSuccessAction, onErrorAction); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Completable completable) { + return baseLifecycleBindable.untilDestroy(completable); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Completable completable, @NonNull final Action0 onCompletedAction) { + return baseLifecycleBindable.untilDestroy(completable, onCompletedAction); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Completable completable, + @NonNull final Action0 onCompletedAction, + @NonNull final Action1 onErrorAction) { + return baseLifecycleBindable.untilDestroy(completable, onCompletedAction, onErrorAction); + } + } diff --git a/src/main/java/ru/touchin/roboswag/components/navigation/ViewController.java b/src/main/java/ru/touchin/roboswag/components/navigation/ViewController.java index a1d92a7..5d932cb 100644 --- a/src/main/java/ru/touchin/roboswag/components/navigation/ViewController.java +++ b/src/main/java/ru/touchin/roboswag/components/navigation/ViewController.java @@ -44,7 +44,9 @@ import ru.touchin.roboswag.components.utils.LifecycleBindable; import ru.touchin.roboswag.components.utils.UiUtils; import ru.touchin.roboswag.core.log.Lc; import ru.touchin.roboswag.core.utils.ShouldNotHappenException; +import rx.Completable; import rx.Observable; +import rx.Single; import rx.Subscription; import rx.functions.Action0; import rx.functions.Action1; @@ -372,6 +374,46 @@ public class ViewController, return baseLifecycleBindable.untilStop(observable, onNextAction, onErrorAction, onCompletedAction); } + @NonNull + @Override + public Subscription untilStop(@NonNull final Single single) { + return baseLifecycleBindable.untilStop(single); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Single single, @NonNull final Action1 onSuccessAction) { + return baseLifecycleBindable.untilStop(single, onSuccessAction); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Single single, + @NonNull final Action1 onSuccessAction, + @NonNull final Action1 onErrorAction) { + return baseLifecycleBindable.untilStop(single, onSuccessAction, onErrorAction); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Completable completable) { + return baseLifecycleBindable.untilStop(completable); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Completable completable, @NonNull final Action0 onCompletedAction) { + return baseLifecycleBindable.untilStop(completable, onCompletedAction); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Completable completable, + @NonNull final Action0 onCompletedAction, + @NonNull final Action1 onErrorAction) { + return baseLifecycleBindable.untilStop(completable, onCompletedAction, onErrorAction); + } + @NonNull @Override public Subscription untilDestroy(@NonNull final Observable observable) { @@ -401,6 +443,46 @@ public class ViewController, return baseLifecycleBindable.untilDestroy(observable, onNextAction, onErrorAction, onCompletedAction); } + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Single single) { + return baseLifecycleBindable.untilDestroy(single); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Single single, @NonNull final Action1 onSuccessAction) { + return baseLifecycleBindable.untilDestroy(single, onSuccessAction); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Single single, + @NonNull final Action1 onSuccessAction, + @NonNull final Action1 onErrorAction) { + return baseLifecycleBindable.untilDestroy(single, onSuccessAction, onErrorAction); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Completable completable) { + return baseLifecycleBindable.untilDestroy(completable); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Completable completable, @NonNull final Action0 onCompletedAction) { + return baseLifecycleBindable.untilDestroy(completable, onCompletedAction); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Completable completable, + @NonNull final Action0 onCompletedAction, + @NonNull final Action1 onErrorAction) { + return baseLifecycleBindable.untilDestroy(completable, onCompletedAction, onErrorAction); + } + @SuppressWarnings("CPD-END") //CPD: it is same as in other implementation based on BaseLifecycleBindable /** diff --git a/src/main/java/ru/touchin/roboswag/components/utils/BaseLifecycleBindable.java b/src/main/java/ru/touchin/roboswag/components/utils/BaseLifecycleBindable.java index 59106de..124a508 100644 --- a/src/main/java/ru/touchin/roboswag/components/utils/BaseLifecycleBindable.java +++ b/src/main/java/ru/touchin/roboswag/components/utils/BaseLifecycleBindable.java @@ -23,7 +23,9 @@ import android.support.annotation.NonNull; import ru.touchin.roboswag.core.log.Lc; import ru.touchin.roboswag.core.utils.ShouldNotHappenException; +import rx.Completable; import rx.Observable; +import rx.Single; import rx.Subscription; import rx.android.schedulers.AndroidSchedulers; import rx.exceptions.OnErrorThrowable; @@ -38,6 +40,9 @@ import rx.subjects.BehaviorSubject; */ public class BaseLifecycleBindable implements LifecycleBindable { + private static final String UNTIL_DESTROY_METHOD = "untilDestroy"; + private static final String UNTIL_STOP_METHOD = "untilStop"; + @NonNull private final BehaviorSubject isCreatedSubject = BehaviorSubject.create(); @NonNull @@ -77,26 +82,21 @@ public class BaseLifecycleBindable implements LifecycleBindable { final String codePoint = Lc.getCodePoint(this, 2); return isStartedSubject.switchMap(started -> started ? observable.observeOn(AndroidSchedulers.mainThread()) : Observable.never()) .takeUntil(isCreatedSubject.filter(created -> !created)) - .subscribe(onNextAction, - throwable -> Lc.assertion(new ShouldNotHappenException("Unexpected error on untilStop at " + codePoint, throwable))); + .subscribe(onNextAction, getActionThrowableForAssertion(codePoint, UNTIL_STOP_METHOD)); } @NonNull @Override public Subscription untilStop(@NonNull final Observable observable) { final String codePoint = Lc.getCodePoint(this, 2); - return untilStop(observable, Actions.empty(), - throwable -> Lc.assertion(new ShouldNotHappenException("Unexpected error on untilStop at " + codePoint, throwable)), - Actions.empty()); + return untilStop(observable, Actions.empty(), getActionThrowableForAssertion(codePoint, UNTIL_STOP_METHOD), Actions.empty()); } @NonNull @Override public Subscription untilStop(@NonNull final Observable observable, @NonNull final Action1 onNextAction) { final String codePoint = Lc.getCodePoint(this, 2); - return untilStop(observable, onNextAction, - throwable -> Lc.assertion(new ShouldNotHappenException("Unexpected error on untilStop at " + codePoint, throwable)), - Actions.empty()); + return untilStop(observable, onNextAction, getActionThrowableForAssertion(codePoint, UNTIL_STOP_METHOD), Actions.empty()); } @NonNull @@ -116,13 +116,56 @@ public class BaseLifecycleBindable implements LifecycleBindable { return until(observable, isStartedSubject.map(started -> !started), onNextAction, onErrorAction, onCompletedAction); } + @NonNull + @Override + public Subscription untilStop(@NonNull final Single single) { + final String codePoint = Lc.getCodePoint(this, 2); + return untilStop(single, Actions.empty(), getActionThrowableForAssertion(codePoint, UNTIL_STOP_METHOD)); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Single single, @NonNull final Action1 onSuccessAction) { + final String codePoint = Lc.getCodePoint(this, 2); + return untilStop(single, onSuccessAction, getActionThrowableForAssertion(codePoint, UNTIL_STOP_METHOD)); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Single single, + @NonNull final Action1 onSuccessAction, + @NonNull final Action1 onErrorAction) { + return until(single, isStartedSubject.map(started -> !started), onSuccessAction, onErrorAction); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Completable completable) { + final String codePoint = Lc.getCodePoint(this, 2); + return untilStop(completable, Actions.empty(), getActionThrowableForAssertion(codePoint, UNTIL_STOP_METHOD)); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Completable completable, + @NonNull final Action0 onCompletedAction) { + final String codePoint = Lc.getCodePoint(this, 2); + return untilStop(completable, onCompletedAction, getActionThrowableForAssertion(codePoint, UNTIL_STOP_METHOD)); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Completable completable, + @NonNull final Action0 onCompletedAction, + @NonNull final Action1 onErrorAction) { + return until(completable, isStartedSubject.map(started -> !started), onCompletedAction, onErrorAction); + } + @NonNull @Override public Subscription untilDestroy(@NonNull final Observable observable) { final String codePoint = Lc.getCodePoint(this, 2); - return untilDestroy(observable, Actions.empty(), - throwable -> Lc.assertion(new ShouldNotHappenException("Unexpected error on untilDestroy at " + codePoint, throwable)), - Actions.empty()); + return untilDestroy(observable, Actions.empty(), getActionThrowableForAssertion(codePoint, UNTIL_DESTROY_METHOD), Actions.empty()); } @NonNull @@ -130,9 +173,7 @@ public class BaseLifecycleBindable implements LifecycleBindable { public Subscription untilDestroy(@NonNull final Observable observable, @NonNull final Action1 onNextAction) { final String codePoint = Lc.getCodePoint(this, 2); - return untilDestroy(observable, onNextAction, - throwable -> Lc.assertion(new ShouldNotHappenException("Unexpected error on untilDestroy at " + codePoint, throwable)), - Actions.empty()); + return untilDestroy(observable, onNextAction, getActionThrowableForAssertion(codePoint, UNTIL_DESTROY_METHOD), Actions.empty()); } @NonNull @@ -152,6 +193,51 @@ public class BaseLifecycleBindable implements LifecycleBindable { return until(observable, isCreatedSubject.map(created -> !created), onNextAction, onErrorAction, onCompletedAction); } + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Single single) { + final String codePoint = Lc.getCodePoint(this, 2); + return untilDestroy(single, Actions.empty(), getActionThrowableForAssertion(codePoint, UNTIL_DESTROY_METHOD)); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Single single, @NonNull final Action1 onSuccessAction) { + final String codePoint = Lc.getCodePoint(this, 2); + return untilDestroy(single, onSuccessAction, getActionThrowableForAssertion(codePoint, UNTIL_DESTROY_METHOD)); + } + + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Single single, + @NonNull final Action1 onSuccessAction, + @NonNull final Action1 onErrorAction) { + return until(single, isCreatedSubject.map(created -> !created), onSuccessAction, onErrorAction); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Completable completable) { + final String codePoint = Lc.getCodePoint(this, 2); + return untilDestroy(completable, Actions.empty(), getActionThrowableForAssertion(codePoint, UNTIL_DESTROY_METHOD)); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Completable completable, @NonNull final Action0 onCompletedAction) { + final String codePoint = Lc.getCodePoint(this, 2); + return untilDestroy(completable, onCompletedAction, getActionThrowableForAssertion(codePoint, UNTIL_DESTROY_METHOD)); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Completable completable, + @NonNull final Action0 onCompletedAction, + @NonNull final Action1 onErrorAction) { + return until(completable, isCreatedSubject.map(created -> !created), onCompletedAction, onErrorAction); + } + @NonNull private Subscription until(@NonNull final Observable observable, @NonNull final Observable conditionSubject, @@ -178,4 +264,60 @@ public class BaseLifecycleBindable implements LifecycleBindable { }); } -} + @NonNull + private Subscription until(@NonNull final Single single, + @NonNull final Observable conditionSubject, + @NonNull final Action1 onSuccessAction, + @NonNull final Action1 onErrorAction) { + final Single actualSingle; + if (onSuccessAction == Actions.empty() && onErrorAction == (Action1) Actions.empty()) { + actualSingle = single; + } else { + actualSingle = single.observeOn(AndroidSchedulers.mainThread()); + } + return isCreatedSubject.first() + .flatMap(created -> created ? actualSingle.toObservable() : Observable.empty()) + .takeUntil(conditionSubject.filter(condition -> condition)) + .toSingle() + .subscribe(onSuccessAction, throwable -> { + final boolean isRxError = throwable instanceof OnErrorThrowable; + if ((!isRxError && throwable instanceof RuntimeException) + || (isRxError && throwable.getCause() instanceof RuntimeException)) { + Lc.assertion(throwable); + } + onErrorAction.call(throwable); + }); + } + + + @NonNull + private Subscription until(@NonNull final Completable completable, + @NonNull final Observable conditionSubject, + @NonNull final Action0 onCompletedAction, + @NonNull final Action1 onErrorAction) { + final Completable actualCompletable; + if (onCompletedAction == Actions.empty() && onErrorAction == (Action1) Actions.empty()) { + actualCompletable = completable; + } else { + actualCompletable = completable.observeOn(AndroidSchedulers.mainThread()); + } + return isCreatedSubject.first() + .flatMap(created -> created ? actualCompletable.toObservable() : Observable.empty()) + .takeUntil(conditionSubject.filter(condition -> condition)) + .toCompletable() + .subscribe(throwable -> { + final boolean isRxError = throwable instanceof OnErrorThrowable; + if ((!isRxError && throwable instanceof RuntimeException) + || (isRxError && throwable.getCause() instanceof RuntimeException)) { + Lc.assertion(throwable); + } + onErrorAction.call(throwable); + }, onCompletedAction); + } + + @NonNull + private Action1 getActionThrowableForAssertion(@NonNull final String codePoint, @NonNull final String method) { + return throwable -> Lc.assertion(new ShouldNotHappenException("Unexpected error on " + method + " at " + codePoint, throwable)); + } + +} \ No newline at end of file