diff --git a/app/build.gradle b/app/build.gradle index 8d0c42c47e..3b36c4c749 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -141,6 +141,9 @@ dependencies { compile "com.pushtorefresh.storio:sqlite-annotations:$STORIO_VERSION" kapt "com.pushtorefresh.storio:sqlite-annotations-processor:$STORIO_VERSION" + // Model View Presenter + compile 'info.android15.nucleus:nucleus:2.0.5' + // Dependency injection compile "com.google.dagger:dagger:$DAGGER_VERSION" kapt "com.google.dagger:dagger-compiler:$DAGGER_VERSION" diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseRxActivity.java b/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseRxActivity.java index ee30033003..ec5a12b5bd 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseRxActivity.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseRxActivity.java @@ -87,9 +87,8 @@ public abstract class BaseRxActivity

extends BaseActivity i } @Override - protected void onDestroy() { - super.onDestroy(); - presenterDelegate.onDropView(); - presenterDelegate.onDestroy(!isChangingConfigurations()); + protected void onPause() { + super.onPause(); + presenterDelegate.onPause(isFinishing()); } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/fragment/BaseRxFragment.java b/app/src/main/java/eu/kanade/tachiyomi/ui/base/fragment/BaseRxFragment.java index e03e6a1cae..84044cdc8c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/fragment/BaseRxFragment.java +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/fragment/BaseRxFragment.java @@ -1,6 +1,7 @@ package eu.kanade.tachiyomi.ui.base.fragment; import android.os.Bundle; +import android.support.v4.app.Fragment; import eu.kanade.tachiyomi.App; import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter; @@ -84,14 +85,13 @@ public abstract class BaseRxFragment

extends BaseFragment i } @Override - public void onDestroyView() { - super.onDestroyView(); - presenterDelegate.onDropView(); + public void onPause() { + super.onPause(); + presenterDelegate.onPause(getActivity().isFinishing() || isRemoving(this)); } - @Override - public void onDestroy() { - super.onDestroy(); - presenterDelegate.onDestroy(!getActivity().isChangingConfigurations()); + private static boolean isRemoving(Fragment fragment) { + Fragment parent = fragment.getParentFragment(); + return fragment.isRemoving() || (parent != null && isRemoving(parent)); } } diff --git a/app/src/main/java/nucleus/factory/PresenterFactory.java b/app/src/main/java/nucleus/factory/PresenterFactory.java deleted file mode 100644 index 22c0d1a3da..0000000000 --- a/app/src/main/java/nucleus/factory/PresenterFactory.java +++ /dev/null @@ -1,7 +0,0 @@ -package nucleus.factory; - -import nucleus.presenter.Presenter; - -public interface PresenterFactory

{ - P createPresenter(); -} diff --git a/app/src/main/java/nucleus/factory/PresenterStorage.java b/app/src/main/java/nucleus/factory/PresenterStorage.java deleted file mode 100644 index 8c36926786..0000000000 --- a/app/src/main/java/nucleus/factory/PresenterStorage.java +++ /dev/null @@ -1,64 +0,0 @@ -package nucleus.factory; - -import java.util.HashMap; - -import nucleus.presenter.Presenter; - -/** - * This is the singleton where all presenters are stored. - */ -public enum PresenterStorage { - - INSTANCE; - - private HashMap idToPresenter = new HashMap<>(); - private HashMap presenterToId = new HashMap<>(); - - /** - * Adds a presenter to the storage - * - * @param presenter a presenter to add - */ - public void add(final Presenter presenter) { - String id = presenter.getClass().getSimpleName() + "/" + System.nanoTime() + "/" + (int)(Math.random() * Integer.MAX_VALUE); - idToPresenter.put(id, presenter); - presenterToId.put(presenter, id); - presenter.addOnDestroyListener(new Presenter.OnDestroyListener() { - @Override - public void onDestroy() { - idToPresenter.remove(presenterToId.remove(presenter)); - } - }); - } - - /** - * Returns a presenter by id or null if such presenter does not exist. - * - * @param id id of a presenter that has been received by calling {@link #getId(Presenter)} - * @param

a type of presenter - * @return a presenter or null - */ - public

P getPresenter(String id) { - //noinspection unchecked - return (P)idToPresenter.get(id); - } - - /** - * Returns id of a given presenter. - * - * @param presenter a presenter to get id for. - * @return if of the presenter. - */ - public String getId(Presenter presenter) { - return presenterToId.get(presenter); - } - - /** - * Removes all presenters from the storage. - * Use this method for testing purposes only. - */ - public void clear() { - idToPresenter.clear(); - presenterToId.clear(); - } -} diff --git a/app/src/main/java/nucleus/factory/ReflectionPresenterFactory.java b/app/src/main/java/nucleus/factory/ReflectionPresenterFactory.java deleted file mode 100644 index b84d4fd0c2..0000000000 --- a/app/src/main/java/nucleus/factory/ReflectionPresenterFactory.java +++ /dev/null @@ -1,45 +0,0 @@ -package nucleus.factory; - -import android.support.annotation.Nullable; - -import nucleus.presenter.Presenter; - -/** - * This class represents a {@link PresenterFactory} that creates a presenter using {@link Class#newInstance()} method. - * - * @param

the type of the presenter. - */ -public class ReflectionPresenterFactory

implements PresenterFactory

{ - - private Class

presenterClass; - - /** - * This method returns a {@link ReflectionPresenterFactory} instance if a given view class has - * a {@link RequiresPresenter} annotation, or null otherwise. - * - * @param viewClass a class of the view - * @param

a type of the presenter - * @return a {@link ReflectionPresenterFactory} instance that is supposed to create a presenter from {@link RequiresPresenter} annotation. - */ - @Nullable - public static

ReflectionPresenterFactory

fromViewClass(Class viewClass) { - RequiresPresenter annotation = viewClass.getAnnotation(RequiresPresenter.class); - //noinspection unchecked - Class

presenterClass = annotation == null ? null : (Class

)annotation.value(); - return presenterClass == null ? null : new ReflectionPresenterFactory<>(presenterClass); - } - - public ReflectionPresenterFactory(Class

presenterClass) { - this.presenterClass = presenterClass; - } - - @Override - public P createPresenter() { - try { - return presenterClass.newInstance(); - } - catch (Exception e) { - throw new RuntimeException(e); - } - } -} diff --git a/app/src/main/java/nucleus/factory/RequiresPresenter.java b/app/src/main/java/nucleus/factory/RequiresPresenter.java deleted file mode 100644 index 081b477019..0000000000 --- a/app/src/main/java/nucleus/factory/RequiresPresenter.java +++ /dev/null @@ -1,13 +0,0 @@ -package nucleus.factory; - -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -import nucleus.presenter.Presenter; - -@Inherited -@Retention(RetentionPolicy.RUNTIME) -public @interface RequiresPresenter { - Class value(); -} diff --git a/app/src/main/java/nucleus/presenter/Presenter.java b/app/src/main/java/nucleus/presenter/Presenter.java deleted file mode 100644 index 0c986dfb06..0000000000 --- a/app/src/main/java/nucleus/presenter/Presenter.java +++ /dev/null @@ -1,164 +0,0 @@ -package nucleus.presenter; - -import android.app.Activity; -import android.app.Fragment; -import android.content.Intent; -import android.os.Bundle; -import android.support.annotation.Nullable; - -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * This is a base class for all presenters. Subclasses can override - * {@link #onCreate}, {@link #onDestroy}, {@link #onSave}, - * {@link #onTakeView}, {@link #onDropView}. - *

- * {@link Presenter.OnDestroyListener} can also be used by external classes - * to be notified about the need of freeing resources. - * - * @param a type of view to return with {@link #getView()}. - */ -public class Presenter { - - @Nullable private View view; - private CopyOnWriteArrayList onDestroyListeners = new CopyOnWriteArrayList<>(); - - /** - * This method is called after presenter construction. - * - * This method is intended for overriding. - * - * @param savedState If the presenter is being re-instantiated after a process restart then this Bundle - * contains the data it supplied in {@link #onSave}. - */ - protected void onCreate(@Nullable Bundle savedState) { - } - - /** - * This method is being called when a user leaves view. - * - * This method is intended for overriding. - */ - protected void onDestroy() { - } - - /** - * A returned state is the state that will be passed to {@link #onCreate} for a new presenter instance after a process restart. - * - * This method is intended for overriding. - * - * @param state a non-null bundle which should be used to put presenter's state into. - */ - protected void onSave(Bundle state) { - } - - /** - * This method is being called when a view gets attached to it. - * Normally this happens during {@link Activity#onResume()}, {@link android.app.Fragment#onResume()} - * and {@link android.view.View#onAttachedToWindow()}. - * - * This method is intended for overriding. - * - * @param view a view that should be taken - */ - protected void onTakeView(View view) { - } - - /** - * This method is being called when a view gets detached from the presenter. - * Normally this happens during {@link Activity#onPause()} ()}, {@link Fragment#onPause()} ()} - * and {@link android.view.View#onDetachedFromWindow()}. - * - * This method is intended for overriding. - */ - protected void onDropView() { - } - - /** - * A callback to be invoked when a presenter is about to be destroyed. - */ - public interface OnDestroyListener { - /** - * Called before {@link Presenter#onDestroy()}. - */ - void onDestroy(); - } - - /** - * Adds a listener observing {@link #onDestroy}. - * - * @param listener a listener to add. - */ - public void addOnDestroyListener(OnDestroyListener listener) { - onDestroyListeners.add(listener); - } - - /** - * Removed a listener observing {@link #onDestroy}. - * - * @param listener a listener to remove. - */ - public void removeOnDestroyListener(OnDestroyListener listener) { - onDestroyListeners.remove(listener); - } - - /** - * Returns a current view attached to the presenter or null. - * - * View is normally available between - * {@link Activity#onResume()} and {@link Activity#onPause()}, - * {@link Fragment#onResume()} and {@link Fragment#onPause()}, - * {@link android.view.View#onAttachedToWindow()} and {@link android.view.View#onDetachedFromWindow()}. - * - * Calls outside of these ranges will return null. - * Notice here that {@link Activity#onActivityResult(int, int, Intent)} is called *before* {@link Activity#onResume()} - * so you can't use this method as a callback. - * - * @return a current attached view. - */ - @Nullable - public View getView() { - return view; - } - - /** - * Initializes the presenter. - */ - public void create(Bundle bundle) { - onCreate(bundle); - } - - /** - * Destroys the presenter, calling all {@link Presenter.OnDestroyListener} callbacks. - */ - public void destroy() { - for (OnDestroyListener listener : onDestroyListeners) - listener.onDestroy(); - onDestroy(); - } - - /** - * Saves the presenter. - */ - public void save(Bundle state) { - onSave(state); - } - - /** - * Attaches a view to the presenter. - * - * @param view a view to attach. - */ - public void takeView(View view) { - this.view = view; - onTakeView(view); - } - - /** - * Detaches the presenter from a view. - */ - public void dropView() { - onDropView(); - this.view = null; - } -} diff --git a/app/src/main/java/nucleus/presenter/RxPresenter.java b/app/src/main/java/nucleus/presenter/RxPresenter.java deleted file mode 100644 index c614dec09b..0000000000 --- a/app/src/main/java/nucleus/presenter/RxPresenter.java +++ /dev/null @@ -1,342 +0,0 @@ -package nucleus.presenter; - -import android.os.Bundle; -import android.support.annotation.CallSuper; -import android.support.annotation.Nullable; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -import nucleus.presenter.delivery.DeliverFirst; -import nucleus.presenter.delivery.DeliverLatestCache; -import nucleus.presenter.delivery.DeliverReplay; -import nucleus.presenter.delivery.Delivery; -import rx.Observable; -import rx.Subscription; -import rx.functions.Action1; -import rx.functions.Action2; -import rx.functions.Func0; -import rx.internal.util.SubscriptionList; -import rx.subjects.BehaviorSubject; - -/** - * This is an extension of {@link Presenter} which provides RxJava functionality. - * - * @param a type of view. - */ -public class RxPresenter extends Presenter { - - private static final String REQUESTED_KEY = RxPresenter.class.getName() + "#requested"; - - private final BehaviorSubject views = BehaviorSubject.create(); - private final SubscriptionList subscriptions = new SubscriptionList(); - - private final HashMap> restartables = new HashMap<>(); - private final HashMap restartableSubscriptions = new HashMap<>(); - private final ArrayList requested = new ArrayList<>(); - - /** - * Returns an {@link rx.Observable} that emits the current attached view or null. - * See {@link BehaviorSubject} for more information. - * - * @return an observable that emits the current attached view or null. - */ - public Observable view() { - return views; - } - - /** - * Registers a subscription to automatically unsubscribe it during onDestroy. - * See {@link SubscriptionList#add(Subscription) for details.} - * - * @param subscription a subscription to add. - */ - public void add(Subscription subscription) { - subscriptions.add(subscription); - } - - /** - * Removes and unsubscribes a subscription that has been registered with {@link #add} previously. - * See {@link SubscriptionList#remove(Subscription)} for details. - * - * @param subscription a subscription to remove. - */ - public void remove(Subscription subscription) { - subscriptions.remove(subscription); - } - - /** - * A restartable is any RxJava observable that can be started (subscribed) and - * should be automatically restarted (re-subscribed) after a process restart if - * it was still subscribed at the moment of saving presenter's state. - * - * Registers a factory. Re-subscribes the restartable after the process restart. - * - * @param restartableId id of the restartable - * @param factory factory of the restartable - */ - public void restartable(int restartableId, Func0 factory) { - restartables.put(restartableId, factory); - if (requested.contains(restartableId)) - start(restartableId); - } - - /** - * Starts the given restartable. - * - * @param restartableId id of the restartable - */ - public void start(int restartableId) { - stop(restartableId); - requested.add(restartableId); - restartableSubscriptions.put(restartableId, restartables.get(restartableId).call()); - } - - /** - * Unsubscribes a restartable - * - * @param restartableId id of a restartable. - */ - public void stop(int restartableId) { - requested.remove((Integer) restartableId); - Subscription subscription = restartableSubscriptions.get(restartableId); - if (subscription != null) - subscription.unsubscribe(); - } - - /** - * Checks if a restartable is unsubscribed. - * - * @param restartableId id of the restartable. - * @return true if the subscription is null or unsubscribed, false otherwise. - */ - public boolean isUnsubscribed(int restartableId) { - Subscription subscription = restartableSubscriptions.get(restartableId); - return subscription == null || subscription.isUnsubscribed(); - } - - /** - * This is a shortcut that can be used instead of combining together - * {@link #restartable(int, Func0)}, - * {@link #deliverFirst()}, - * {@link #split(Action2, Action2)}. - * - * @param restartableId an id of the restartable. - * @param observableFactory a factory that should return an Observable when the restartable should run. - * @param onNext a callback that will be called when received data should be delivered to view. - * @param onError a callback that will be called if the source observable emits onError. - * @param the type of the observable. - */ - public void restartableFirst(int restartableId, final Func0> observableFactory, - final Action2 onNext, @Nullable final Action2 onError) { - - restartable(restartableId, new Func0() { - @Override - public Subscription call() { - return observableFactory.call() - .compose(RxPresenter.this.deliverFirst()) - .subscribe(split(onNext, onError)); - } - }); - } - - /** - * This is a shortcut for calling {@link #restartableFirst(int, Func0, Action2, Action2)} with the last parameter = null. - */ - public void restartableFirst(int restartableId, final Func0> observableFactory, final Action2 onNext) { - restartableFirst(restartableId, observableFactory, onNext, null); - } - - /** - * This is a shortcut that can be used instead of combining together - * {@link #restartable(int, Func0)}, - * {@link #deliverLatestCache()}, - * {@link #split(Action2, Action2)}. - * - * @param restartableId an id of the restartable. - * @param observableFactory a factory that should return an Observable when the restartable should run. - * @param onNext a callback that will be called when received data should be delivered to view. - * @param onError a callback that will be called if the source observable emits onError. - * @param the type of the observable. - */ - public void restartableLatestCache(int restartableId, final Func0> observableFactory, - final Action2 onNext, @Nullable final Action2 onError) { - - restartable(restartableId, new Func0() { - @Override - public Subscription call() { - return observableFactory.call() - .compose(RxPresenter.this.deliverLatestCache()) - .subscribe(split(onNext, onError)); - } - }); - } - - /** - * This is a shortcut for calling {@link #restartableLatestCache(int, Func0, Action2, Action2)} with the last parameter = null. - */ - public void restartableLatestCache(int restartableId, final Func0> observableFactory, final Action2 onNext) { - restartableLatestCache(restartableId, observableFactory, onNext, null); - } - - /** - * This is a shortcut that can be used instead of combining together - * {@link #restartable(int, Func0)}, - * {@link #deliverReplay()}, - * {@link #split(Action2, Action2)}. - * - * @param restartableId an id of the restartable. - * @param observableFactory a factory that should return an Observable when the restartable should run. - * @param onNext a callback that will be called when received data should be delivered to view. - * @param onError a callback that will be called if the source observable emits onError. - * @param the type of the observable. - */ - public void restartableReplay(int restartableId, final Func0> observableFactory, - final Action2 onNext, @Nullable final Action2 onError) { - - restartable(restartableId, new Func0() { - @Override - public Subscription call() { - return observableFactory.call() - .compose(RxPresenter.this.deliverReplay()) - .subscribe(split(onNext, onError)); - } - }); - } - - /** - * This is a shortcut for calling {@link #restartableReplay(int, Func0, Action2, Action2)} with the last parameter = null. - */ - public void restartableReplay(int restartableId, final Func0> observableFactory, final Action2 onNext) { - restartableReplay(restartableId, observableFactory, onNext, null); - } - - /** - * Returns an {@link rx.Observable.Transformer} that couples views with data that has been emitted by - * the source {@link rx.Observable}. - * - * {@link #deliverLatestCache} keeps the latest onNext value and emits it each time a new view gets attached. - * If a new onNext value appears while a view is attached, it will be delivered immediately. - * - * @param the type of source observable emissions - */ - public DeliverLatestCache deliverLatestCache() { - return new DeliverLatestCache<>(views); - } - - /** - * Returns an {@link rx.Observable.Transformer} that couples views with data that has been emitted by - * the source {@link rx.Observable}. - * - * {@link #deliverFirst} delivers only the first onNext value that has been emitted by the source observable. - * - * @param the type of source observable emissions - */ - public DeliverFirst deliverFirst() { - return new DeliverFirst<>(views); - } - - /** - * Returns an {@link rx.Observable.Transformer} that couples views with data that has been emitted by - * the source {@link rx.Observable}. - * - * {@link #deliverReplay} keeps all onNext values and emits them each time a new view gets attached. - * If a new onNext value appears while a view is attached, it will be delivered immediately. - * - * @param the type of source observable emissions - */ - public DeliverReplay deliverReplay() { - return new DeliverReplay<>(views); - } - - /** - * Returns a method that can be used for manual restartable chain build. It returns an Action1 that splits - * a received {@link Delivery} into two {@link Action2} onNext and onError calls. - * - * @param onNext a method that will be called if the delivery contains an emitted onNext value. - * @param onError a method that will be called if the delivery contains an onError throwable. - * @param a type on onNext value. - * @return an Action1 that splits a received {@link Delivery} into two {@link Action2} onNext and onError calls. - */ - public Action1> split(final Action2 onNext, @Nullable final Action2 onError) { - return new Action1>() { - @Override - public void call(Delivery delivery) { - delivery.split(onNext, onError); - } - }; - } - - /** - * This is a shortcut for calling {@link #split(Action2, Action2)} when the second parameter is null. - */ - public Action1> split(Action2 onNext) { - return split(onNext, null); - } - - /** - * {@inheritDoc} - */ - @CallSuper - @Override - protected void onCreate(Bundle savedState) { - if (savedState != null) - requested.addAll(savedState.getIntegerArrayList(REQUESTED_KEY)); - } - - /** - * {@inheritDoc} - */ - @CallSuper - @Override - protected void onDestroy() { - views.onCompleted(); - subscriptions.unsubscribe(); - for (Map.Entry entry : restartableSubscriptions.entrySet()) - entry.getValue().unsubscribe(); - } - - /** - * {@inheritDoc} - */ - @CallSuper - @Override - protected void onSave(Bundle state) { - for (int i = requested.size() - 1; i >= 0; i--) { - int restartableId = requested.get(i); - Subscription subscription = restartableSubscriptions.get(restartableId); - if (subscription != null && subscription.isUnsubscribed()) - requested.remove(i); - } - state.putIntegerArrayList(REQUESTED_KEY, requested); - } - - /** - * {@inheritDoc} - */ - @CallSuper - @Override - protected void onTakeView(View view) { - views.onNext(view); - } - - /** - * {@inheritDoc} - */ - @CallSuper - @Override - protected void onDropView() { - views.onNext(null); - } - - /** - * Please, use restartableXX and deliverXX methods for pushing data from RxPresenter into View. - */ - @Deprecated - @Nullable - @Override - public View getView() { - return super.getView(); - } -} diff --git a/app/src/main/java/nucleus/presenter/delivery/DeliverFirst.java b/app/src/main/java/nucleus/presenter/delivery/DeliverFirst.java deleted file mode 100644 index bac7fc1dc5..0000000000 --- a/app/src/main/java/nucleus/presenter/delivery/DeliverFirst.java +++ /dev/null @@ -1,38 +0,0 @@ -package nucleus.presenter.delivery; - -import rx.Notification; -import rx.Observable; -import rx.functions.Func1; - -public class DeliverFirst implements Observable.Transformer> { - - private final Observable view; - - public DeliverFirst(Observable view) { - this.view = view; - } - - @Override - public Observable> call(Observable observable) { - return observable.materialize() - .take(1) - .switchMap(new Func1, Observable>>() { - @Override - public Observable> call(final Notification notification) { - return view.map(new Func1>() { - @Override - public Delivery call(View view) { - return view == null ? null : new Delivery<>(view, notification); - } - }); - } - }) - .filter(new Func1, Boolean>() { - @Override - public Boolean call(Delivery delivery) { - return delivery != null; - } - }) - .take(1); - } -} diff --git a/app/src/main/java/nucleus/presenter/delivery/DeliverLatestCache.java b/app/src/main/java/nucleus/presenter/delivery/DeliverLatestCache.java deleted file mode 100644 index dfecd8db30..0000000000 --- a/app/src/main/java/nucleus/presenter/delivery/DeliverLatestCache.java +++ /dev/null @@ -1,42 +0,0 @@ -package nucleus.presenter.delivery; - -import rx.Notification; -import rx.Observable; -import rx.functions.Func1; -import rx.functions.Func2; - -public class DeliverLatestCache implements Observable.Transformer> { - - private final Observable view; - - public DeliverLatestCache(Observable view) { - this.view = view; - } - - @Override - public Observable> call(Observable observable) { - return Observable - .combineLatest( - view, - observable - .materialize() - .filter(new Func1, Boolean>() { - @Override - public Boolean call(Notification notification) { - return !notification.isOnCompleted(); - } - }), - new Func2, Delivery>() { - @Override - public Delivery call(View view, Notification notification) { - return view == null ? null : new Delivery<>(view, notification); - } - }) - .filter(new Func1, Boolean>() { - @Override - public Boolean call(Delivery delivery) { - return delivery != null; - } - }); - } -} diff --git a/app/src/main/java/nucleus/presenter/delivery/DeliverReplay.java b/app/src/main/java/nucleus/presenter/delivery/DeliverReplay.java deleted file mode 100644 index 18d2c0f383..0000000000 --- a/app/src/main/java/nucleus/presenter/delivery/DeliverReplay.java +++ /dev/null @@ -1,50 +0,0 @@ -package nucleus.presenter.delivery; - -import rx.Notification; -import rx.Observable; -import rx.Subscription; -import rx.functions.Action0; -import rx.functions.Func1; -import rx.subjects.ReplaySubject; - -public class DeliverReplay implements Observable.Transformer> { - - private final Observable view; - - public DeliverReplay(Observable view) { - this.view = view; - } - - @Override - public Observable> call(Observable observable) { - final ReplaySubject> subject = ReplaySubject.create(); - final Subscription subscription = observable - .materialize() - .filter(new Func1, Boolean>() { - @Override - public Boolean call(Notification notification) { - return !notification.isOnCompleted(); - } - }) - .subscribe(subject); - return view - .switchMap(new Func1>>() { - @Override - public Observable> call(final View view) { - return view == null ? Observable.>never() : subject - .map(new Func1, Delivery>() { - @Override - public Delivery call(Notification notification) { - return new Delivery<>(view, notification); - } - }); - } - }) - .doOnUnsubscribe(new Action0() { - @Override - public void call() { - subscription.unsubscribe(); - } - }); - } -} diff --git a/app/src/main/java/nucleus/presenter/delivery/Delivery.java b/app/src/main/java/nucleus/presenter/delivery/Delivery.java deleted file mode 100644 index 270e1231c3..0000000000 --- a/app/src/main/java/nucleus/presenter/delivery/Delivery.java +++ /dev/null @@ -1,56 +0,0 @@ -package nucleus.presenter.delivery; - -import android.support.annotation.Nullable; - -import rx.Notification; -import rx.functions.Action2; - -/** - * A class that represents a couple of View and Data. - * - * @param - * @param - */ -public final class Delivery { - - private final View view; - private final Notification notification; - - public Delivery(View view, Notification notification) { - this.view = view; - this.notification = notification; - } - - public void split(Action2 onNext, @Nullable Action2 onError) { - if (notification.getKind() == Notification.Kind.OnNext) - onNext.call(view, notification.getValue()); - else if (onError != null && notification.getKind() == Notification.Kind.OnError) - onError.call(view, notification.getThrowable()); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Delivery delivery = (Delivery)o; - - if (view != null ? !view.equals(delivery.view) : delivery.view != null) return false; - return !(notification != null ? !notification.equals(delivery.notification) : delivery.notification != null); - } - - @Override - public int hashCode() { - int result = view != null ? view.hashCode() : 0; - result = 31 * result + (notification != null ? notification.hashCode() : 0); - return result; - } - - @Override - public String toString() { - return "Delivery{" + - "view=" + view + - ", notification=" + notification + - '}'; - } -} diff --git a/app/src/main/java/nucleus/view/NucleusActivity.java b/app/src/main/java/nucleus/view/NucleusActivity.java deleted file mode 100644 index 5f7d897427..0000000000 --- a/app/src/main/java/nucleus/view/NucleusActivity.java +++ /dev/null @@ -1,79 +0,0 @@ -package nucleus.view; - -import android.app.Activity; -import android.os.Bundle; -import android.support.annotation.NonNull; - -import nucleus.factory.PresenterFactory; -import nucleus.factory.ReflectionPresenterFactory; -import nucleus.presenter.Presenter; - -/** - * This class is an example of how an activity could controls it's presenter. - * You can inherit from this class or copy/paste this class's code to - * create your own view implementation. - * - * @param

a type of presenter to return with {@link #getPresenter}. - */ -public abstract class NucleusActivity

extends Activity implements ViewWithPresenter

{ - - private static final String PRESENTER_STATE_KEY = "presenter_state"; - - private PresenterLifecycleDelegate

presenterDelegate = - new PresenterLifecycleDelegate<>(ReflectionPresenterFactory.

fromViewClass(getClass())); - - /** - * Returns a current presenter factory. - */ - public PresenterFactory

getPresenterFactory() { - return presenterDelegate.getPresenterFactory(); - } - - /** - * Sets a presenter factory. - * Call this method before onCreate/onFinishInflate to override default {@link ReflectionPresenterFactory} presenter factory. - * Use this method for presenter dependency injection. - */ - @Override - public void setPresenterFactory(PresenterFactory

presenterFactory) { - presenterDelegate.setPresenterFactory(presenterFactory); - } - - /** - * Returns a current attached presenter. - * This method is guaranteed to return a non-null value between - * onResume/onPause and onAttachedToWindow/onDetachedFromWindow calls - * if the presenter factory returns a non-null value. - * - * @return a currently attached presenter or null. - */ - public P getPresenter() { - return presenterDelegate.getPresenter(); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (savedInstanceState != null) - presenterDelegate.onRestoreInstanceState(savedInstanceState.getBundle(PRESENTER_STATE_KEY)); - } - - @Override - protected void onSaveInstanceState(@NonNull Bundle outState) { - super.onSaveInstanceState(outState); - outState.putBundle(PRESENTER_STATE_KEY, presenterDelegate.onSaveInstanceState()); - } - - @Override - protected void onResume() { - super.onResume(); - presenterDelegate.onResume(this); - } - - @Override - protected void onDestroy() { - super.onDestroy(); - presenterDelegate.onDropView(); - presenterDelegate.onDestroy(!isChangingConfigurations()); - } -} diff --git a/app/src/main/java/nucleus/view/NucleusFragment.java b/app/src/main/java/nucleus/view/NucleusFragment.java deleted file mode 100644 index 9979a2a8d1..0000000000 --- a/app/src/main/java/nucleus/view/NucleusFragment.java +++ /dev/null @@ -1,82 +0,0 @@ -package nucleus.view; - -import android.app.Fragment; -import android.os.Bundle; - -import nucleus.factory.PresenterFactory; -import nucleus.factory.ReflectionPresenterFactory; -import nucleus.presenter.Presenter; - -/** - * This view is an example of how a view should control it's presenter. - * You can inherit from this class or copy/paste this class's code to - * create your own view implementation. - * - * @param

a type of presenter to return with {@link #getPresenter}. - */ -public abstract class NucleusFragment

extends Fragment implements ViewWithPresenter

{ - - private static final String PRESENTER_STATE_KEY = "presenter_state"; - private PresenterLifecycleDelegate

presenterDelegate = - new PresenterLifecycleDelegate<>(ReflectionPresenterFactory.

fromViewClass(getClass())); - - /** - * Returns a current presenter factory. - */ - public PresenterFactory

getPresenterFactory() { - return presenterDelegate.getPresenterFactory(); - } - - /** - * Sets a presenter factory. - * Call this method before onCreate/onFinishInflate to override default {@link ReflectionPresenterFactory} presenter factory. - * Use this method for presenter dependency injection. - */ - @Override - public void setPresenterFactory(PresenterFactory

presenterFactory) { - presenterDelegate.setPresenterFactory(presenterFactory); - } - - /** - * Returns a current attached presenter. - * This method is guaranteed to return a non-null value between - * onResume/onPause and onAttachedToWindow/onDetachedFromWindow calls - * if the presenter factory returns a non-null value. - * - * @return a currently attached presenter or null. - */ - public P getPresenter() { - return presenterDelegate.getPresenter(); - } - - @Override - public void onCreate(Bundle bundle) { - super.onCreate(bundle); - if (bundle != null) - presenterDelegate.onRestoreInstanceState(bundle.getBundle(PRESENTER_STATE_KEY)); - } - - @Override - public void onSaveInstanceState(Bundle bundle) { - super.onSaveInstanceState(bundle); - bundle.putBundle(PRESENTER_STATE_KEY, presenterDelegate.onSaveInstanceState()); - } - - @Override - public void onResume() { - super.onResume(); - presenterDelegate.onResume(this); - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - presenterDelegate.onDropView(); - } - - @Override - public void onDestroy() { - super.onDestroy(); - presenterDelegate.onDestroy(!getActivity().isChangingConfigurations()); - } -} diff --git a/app/src/main/java/nucleus/view/NucleusLayout.java b/app/src/main/java/nucleus/view/NucleusLayout.java deleted file mode 100644 index 8e9c57f528..0000000000 --- a/app/src/main/java/nucleus/view/NucleusLayout.java +++ /dev/null @@ -1,113 +0,0 @@ -package nucleus.view; - -import android.app.Activity; -import android.content.Context; -import android.content.ContextWrapper; -import android.os.Bundle; -import android.os.Parcelable; -import android.util.AttributeSet; -import android.widget.FrameLayout; - -import nucleus.factory.PresenterFactory; -import nucleus.factory.ReflectionPresenterFactory; -import nucleus.presenter.Presenter; - -/** - * This view is an example of how a view should control it's presenter. - * You can inherit from this class or copy/paste this class's code to - * create your own view implementation. - * - * @param

a type of presenter to return with {@link #getPresenter}. - */ -public class NucleusLayout

extends FrameLayout implements ViewWithPresenter

{ - - private static final String PARENT_STATE_KEY = "parent_state"; - private static final String PRESENTER_STATE_KEY = "presenter_state"; - - private PresenterLifecycleDelegate

presenterDelegate = - new PresenterLifecycleDelegate<>(ReflectionPresenterFactory.

fromViewClass(getClass())); - - public NucleusLayout(Context context) { - super(context); - } - - public NucleusLayout(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public NucleusLayout(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - /** - * Returns a current presenter factory. - */ - public PresenterFactory

getPresenterFactory() { - return presenterDelegate.getPresenterFactory(); - } - - /** - * Sets a presenter factory. - * Call this method before onCreate/onFinishInflate to override default {@link ReflectionPresenterFactory} presenter factory. - * Use this method for presenter dependency injection. - */ - @Override - public void setPresenterFactory(PresenterFactory

presenterFactory) { - presenterDelegate.setPresenterFactory(presenterFactory); - } - - /** - * Returns a current attached presenter. - * This method is guaranteed to return a non-null value between - * onResume/onPause and onAttachedToWindow/onDetachedFromWindow calls - * if the presenter factory returns a non-null value. - * - * @return a currently attached presenter or null. - */ - public P getPresenter() { - return presenterDelegate.getPresenter(); - } - - /** - * Returns the unwrapped activity of the view or throws an exception. - * - * @return an unwrapped activity - */ - public Activity getActivity() { - Context context = getContext(); - while (!(context instanceof Activity) && context instanceof ContextWrapper) - context = ((ContextWrapper) context).getBaseContext(); - if (!(context instanceof Activity)) - throw new IllegalStateException("Expected an activity context, got " + context.getClass().getSimpleName()); - return (Activity) context; - } - - @Override - protected Parcelable onSaveInstanceState() { - Bundle bundle = new Bundle(); - bundle.putBundle(PRESENTER_STATE_KEY, presenterDelegate.onSaveInstanceState()); - bundle.putParcelable(PARENT_STATE_KEY, super.onSaveInstanceState()); - return bundle; - } - - @Override - protected void onRestoreInstanceState(Parcelable state) { - Bundle bundle = (Bundle) state; - super.onRestoreInstanceState(bundle.getParcelable(PARENT_STATE_KEY)); - presenterDelegate.onRestoreInstanceState(bundle.getBundle(PRESENTER_STATE_KEY)); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - if (!isInEditMode()) - presenterDelegate.onResume(this); - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - presenterDelegate.onDropView(); - presenterDelegate.onDestroy(!getActivity().isChangingConfigurations()); - } -} diff --git a/app/src/main/java/nucleus/view/ParcelFn.java b/app/src/main/java/nucleus/view/ParcelFn.java deleted file mode 100644 index 5b4fedca78..0000000000 --- a/app/src/main/java/nucleus/view/ParcelFn.java +++ /dev/null @@ -1,25 +0,0 @@ -package nucleus.view; - -import android.os.Parcel; - -class ParcelFn { - - private static final ClassLoader CLASS_LOADER = ParcelFn.class.getClassLoader(); - - static T unmarshall(byte[] array) { - Parcel parcel = Parcel.obtain(); - parcel.unmarshall(array, 0, array.length); - parcel.setDataPosition(0); - Object value = parcel.readValue(CLASS_LOADER); - parcel.recycle(); - return (T)value; - } - - static byte[] marshall(Object o) { - Parcel parcel = Parcel.obtain(); - parcel.writeValue(o); - byte[] result = parcel.marshall(); - parcel.recycle(); - return result; - } -} \ No newline at end of file diff --git a/app/src/main/java/nucleus/view/PresenterLifecycleDelegate.java b/app/src/main/java/nucleus/view/PresenterLifecycleDelegate.java deleted file mode 100644 index 655040a207..0000000000 --- a/app/src/main/java/nucleus/view/PresenterLifecycleDelegate.java +++ /dev/null @@ -1,127 +0,0 @@ -package nucleus.view; - -import android.os.Bundle; -import android.os.Parcelable; -import android.support.annotation.Nullable; - -import nucleus.factory.PresenterFactory; -import nucleus.factory.PresenterStorage; -import nucleus.presenter.Presenter; - -/** - * This class adopts a View lifecycle to the Presenter`s lifecycle. - * - * @param

a type of the presenter. - */ -public final class PresenterLifecycleDelegate

{ - - private static final String PRESENTER_KEY = "presenter"; - private static final String PRESENTER_ID_KEY = "presenter_id"; - - @Nullable private PresenterFactory

presenterFactory; - @Nullable private P presenter; - @Nullable private Bundle bundle; - - private boolean presenterHasView; - - public PresenterLifecycleDelegate(@Nullable PresenterFactory

presenterFactory) { - this.presenterFactory = presenterFactory; - } - - /** - * {@link ViewWithPresenter#getPresenterFactory()} - */ - @Nullable - public PresenterFactory

getPresenterFactory() { - return presenterFactory; - } - - /** - * {@link ViewWithPresenter#setPresenterFactory(PresenterFactory)} - */ - public void setPresenterFactory(@Nullable PresenterFactory

presenterFactory) { - if (presenter != null) - throw new IllegalArgumentException("setPresenterFactory() should be called before onResume()"); - this.presenterFactory = presenterFactory; - } - - /** - * {@link ViewWithPresenter#getPresenter()} - */ - public P getPresenter() { - if (presenterFactory != null) { - if (presenter == null && bundle != null) - presenter = PresenterStorage.INSTANCE.getPresenter(bundle.getString(PRESENTER_ID_KEY)); - - if (presenter == null) { - presenter = presenterFactory.createPresenter(); - PresenterStorage.INSTANCE.add(presenter); - presenter.create(bundle == null ? null : bundle.getBundle(PRESENTER_KEY)); - } - bundle = null; - } - return presenter; - } - - /** - * {@link android.app.Activity#onSaveInstanceState(Bundle)}, {@link android.app.Fragment#onSaveInstanceState(Bundle)}, {@link android.view.View#onSaveInstanceState()}. - */ - public Bundle onSaveInstanceState() { - Bundle bundle = new Bundle(); - getPresenter(); - if (presenter != null) { - Bundle presenterBundle = new Bundle(); - presenter.save(presenterBundle); - bundle.putBundle(PRESENTER_KEY, presenterBundle); - bundle.putString(PRESENTER_ID_KEY, PresenterStorage.INSTANCE.getId(presenter)); - } - return bundle; - } - - /** - * {@link android.app.Activity#onCreate(Bundle)}, {@link android.app.Fragment#onCreate(Bundle)}, {@link android.view.View#onRestoreInstanceState(Parcelable)}. - */ - public void onRestoreInstanceState(Bundle presenterState) { - if (presenter != null) - throw new IllegalArgumentException("onRestoreInstanceState() should be called before onResume()"); - this.bundle = ParcelFn.unmarshall(ParcelFn.marshall(presenterState)); - } - - /** - * {@link android.app.Activity#onResume()}, - * {@link android.app.Fragment#onResume()}, - * {@link android.view.View#onAttachedToWindow()} - */ - public void onResume(Object view) { - getPresenter(); - if (presenter != null && !presenterHasView) { - //noinspection unchecked - presenter.takeView(view); - presenterHasView = true; - } - } - - /** - * {@link android.app.Activity#onDestroy()}, - * {@link android.app.Fragment#onDestroyView()}, - * {@link android.view.View#onDetachedFromWindow()} - */ - public void onDropView() { - if (presenter != null && presenterHasView) { - presenter.dropView(); - presenterHasView = false; - } - } - - /** - * {@link android.app.Activity#onDestroy()}, - * {@link android.app.Fragment#onDestroy()}, - * {@link android.view.View#onDetachedFromWindow()} - */ - public void onDestroy(boolean isFinal) { - if (presenter != null && isFinal) { - presenter.destroy(); - presenter = null; - } - } -} diff --git a/app/src/main/java/nucleus/view/ViewWithPresenter.java b/app/src/main/java/nucleus/view/ViewWithPresenter.java deleted file mode 100644 index 979065a5a4..0000000000 --- a/app/src/main/java/nucleus/view/ViewWithPresenter.java +++ /dev/null @@ -1,30 +0,0 @@ -package nucleus.view; - -import nucleus.factory.PresenterFactory; -import nucleus.factory.ReflectionPresenterFactory; -import nucleus.presenter.Presenter; - -public interface ViewWithPresenter

{ - - /** - * Returns a current presenter factory. - */ - PresenterFactory

getPresenterFactory(); - - /** - * Sets a presenter factory. - * Call this method before onCreate/onFinishInflate to override default {@link ReflectionPresenterFactory} presenter factory. - * Use this method for presenter dependency injection. - */ - void setPresenterFactory(PresenterFactory

presenterFactory); - - /** - * Returns a current attached presenter. - * This method is guaranteed to return a non-null value between - * onResume/onPause and onAttachedToWindow/onDetachedFromWindow calls - * if the presenter factory returns a non-null value. - * - * @return a currently attached presenter or null. - */ - P getPresenter(); -}