From 008b9f0b6bbbfce4267070bb30c32055c7d7cdbf Mon Sep 17 00:00:00 2001 From: Gavriil Sitnikov Date: Thu, 20 Apr 2017 18:26:49 +0300 Subject: [PATCH] adapter delegate logic finished --- .../components/adapters/AdapterDelegate.java | 224 +++++++++++++++- .../adapters/BindableViewHolder.java | 6 - .../adapters/ObservableCollectionAdapter.java | 250 ++++++++++++------ .../components/navigation/ViewController.java | 6 - .../navigation/activities/BaseActivity.java | 6 - .../utils/BaseLifecycleBindable.java | 9 - .../components/utils/LifecycleBindable.java | 6 - 7 files changed, 383 insertions(+), 124 deletions(-) diff --git a/src/main/java/ru/touchin/roboswag/components/adapters/AdapterDelegate.java b/src/main/java/ru/touchin/roboswag/components/adapters/AdapterDelegate.java index f7bdadd..f3e29fd 100644 --- a/src/main/java/ru/touchin/roboswag/components/adapters/AdapterDelegate.java +++ b/src/main/java/ru/touchin/roboswag/components/adapters/AdapterDelegate.java @@ -6,38 +6,248 @@ import android.view.ViewGroup; import java.util.List; import ru.touchin.roboswag.components.utils.LifecycleBindable; +import ru.touchin.roboswag.components.utils.UiUtils; +import rx.Completable; +import rx.Observable; +import rx.Single; +import rx.Subscription; +import rx.functions.Action0; +import rx.functions.Action1; -public abstract class AdapterDelegate { +/** + * Objects of such class controls creation and binding of specific type of RecyclerView's ViewHolders. + * Default {@link #getItemViewType} is generating on construction of object. + * + * @param Type of {@link BindableViewHolder} of delegate; + * @param Type of items to bind to {@link BindableViewHolder}s. + */ +@SuppressWarnings("PMD.TooManyMethods") +//TooManyMethods: it's ok as it is LifecycleBindable +public abstract class AdapterDelegate implements LifecycleBindable { @NonNull - private final LifecycleBindable lifecycleBindable; + private final LifecycleBindable parentLifecycleBindable; + private final int defaultItemViewType; - public AdapterDelegate(@NonNull final LifecycleBindable lifecycleBindable) { - this.lifecycleBindable = lifecycleBindable; + public AdapterDelegate(@NonNull final LifecycleBindable parentLifecycleBindable) { + this.parentLifecycleBindable = parentLifecycleBindable; + this.defaultItemViewType = UiUtils.OfViews.generateViewId(); } - public abstract int getItemViewType(); + /** + * Returns parent {@link LifecycleBindable} that this delegate created from (e.g. Activity or ViewController). + * + * @return Parent {@link LifecycleBindable}. + */ + @NonNull + public LifecycleBindable getParentLifecycleBindable() { + return parentLifecycleBindable; + } + /** + * Unique ID of AdapterDelegate. + * + * @return Unique ID. + */ + public int getItemViewType() { + return defaultItemViewType; + } + + /** + * Returns if object is processable by this delegate. + * This item will be casted to {@link TItem} and passes to {@link #onBindViewHolder(TViewHolder, TItem, int, int)}. + * + * @param item Item to check; + * @param adapterPosition Position of item in adapter; + * @param itemCollectionPosition Position of item in collection that contains item; + * @return True if item is processable by this delegate. + */ public abstract boolean isForViewType(@NonNull final Object item, final int adapterPosition, final int itemCollectionPosition); + /** + * Returns unique ID of item to support stable ID's logic of RecyclerView's adapter. + * + * @param item Item to check; + * @param adapterPosition Position of item in adapter; + * @param itemCollectionPosition Position of item in collection that contains item; + * @return Unique item ID. + */ public long getItemId(@NonNull final TItem item, final int adapterPosition, final int itemCollectionPosition) { return 0; } + /** + * Creates ViewHolder to bind item to it later. + * + * @param parent Container of ViewHolder's view. + * @return New ViewHolder. + */ @NonNull public abstract TViewHolder onCreateViewHolder(@NonNull final ViewGroup parent); + /** + * Binds item to created by this object ViewHolder. + * + * @param holder ViewHolder to bind item to; + * @param item Item to check; + * @param adapterPosition Position of item in adapter; + * @param itemCollectionPosition Position of item in collection that contains item; + */ public abstract void onBindViewHolder(@NonNull final TViewHolder holder, @NonNull final TItem item, final int adapterPosition, final int itemCollectionPosition); + /** + * Binds item with payloads to created by this object ViewHolder. + * + * @param holder ViewHolder to bind item to; + * @param item Item to check; + * @param payloads Payloads; + * @param adapterPosition Position of item in adapter; + * @param itemCollectionPosition Position of item in collection that contains item; + */ public void onBindViewHolder(@NonNull final TViewHolder holder, @NonNull final TItem item, @NonNull final List payloads, final int adapterPosition, final int itemCollectionPosition) { //do nothing by default } + @SuppressWarnings("CPD-START") + //CPD: it is same as in other implementation based on BaseLifecycleBindable @NonNull - protected LifecycleBindable getLifecycleBindable() { - return lifecycleBindable; + @Override + public Subscription untilStop(@NonNull final Observable observable) { + return parentLifecycleBindable.untilStop(observable); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Observable observable, @NonNull final Action1 onNextAction) { + return parentLifecycleBindable.untilStop(observable, onNextAction); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Observable observable, + @NonNull final Action1 onNextAction, + @NonNull final Action1 onErrorAction) { + return parentLifecycleBindable.untilStop(observable, onNextAction, onErrorAction); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Observable observable, + @NonNull final Action1 onNextAction, + @NonNull final Action1 onErrorAction, + @NonNull final Action0 onCompletedAction) { + return parentLifecycleBindable.untilStop(observable, onNextAction, onErrorAction, onCompletedAction); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Single single) { + return parentLifecycleBindable.untilStop(single); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Single single, @NonNull final Action1 onSuccessAction) { + return parentLifecycleBindable.untilStop(single, onSuccessAction); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Single single, + @NonNull final Action1 onSuccessAction, + @NonNull final Action1 onErrorAction) { + return parentLifecycleBindable.untilStop(single, onSuccessAction, onErrorAction); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Completable completable) { + return parentLifecycleBindable.untilStop(completable); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Completable completable, @NonNull final Action0 onCompletedAction) { + return parentLifecycleBindable.untilStop(completable, onCompletedAction); + } + + @NonNull + @Override + public Subscription untilStop(@NonNull final Completable completable, + @NonNull final Action0 onCompletedAction, + @NonNull final Action1 onErrorAction) { + return parentLifecycleBindable.untilStop(completable, onCompletedAction, onErrorAction); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Observable observable) { + return parentLifecycleBindable.untilDestroy(observable); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Observable observable, @NonNull final Action1 onNextAction) { + return parentLifecycleBindable.untilDestroy(observable, onNextAction); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Observable observable, + @NonNull final Action1 onNextAction, + @NonNull final Action1 onErrorAction) { + return parentLifecycleBindable.untilDestroy(observable, onNextAction, onErrorAction); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Observable observable, + @NonNull final Action1 onNextAction, + @NonNull final Action1 onErrorAction, + @NonNull final Action0 onCompletedAction) { + return parentLifecycleBindable.untilDestroy(observable, onNextAction, onErrorAction, onCompletedAction); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Single single) { + return parentLifecycleBindable.untilDestroy(single); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Single single, @NonNull final Action1 onSuccessAction) { + return parentLifecycleBindable.untilDestroy(single, onSuccessAction); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Single single, + @NonNull final Action1 onSuccessAction, + @NonNull final Action1 onErrorAction) { + return parentLifecycleBindable.untilDestroy(single, onSuccessAction, onErrorAction); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Completable completable) { + return parentLifecycleBindable.untilDestroy(completable); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Completable completable, @NonNull final Action0 onCompletedAction) { + return parentLifecycleBindable.untilDestroy(completable, onCompletedAction); + } + + @NonNull + @Override + public Subscription untilDestroy(@NonNull final Completable completable, + @NonNull final Action0 onCompletedAction, + @NonNull final Action1 onErrorAction) { + return parentLifecycleBindable.untilDestroy(completable, onCompletedAction, onErrorAction); } } 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 2748721..19d48f7 100644 --- a/src/main/java/ru/touchin/roboswag/components/adapters/BindableViewHolder.java +++ b/src/main/java/ru/touchin/roboswag/components/adapters/BindableViewHolder.java @@ -122,12 +122,6 @@ public class BindableViewHolder extends RecyclerView.ViewHolder implements Lifec return ContextCompat.getDrawable(itemView.getContext(), resId); } - @NonNull - @Override - public Subscription bind(@NonNull final Observable observable, @NonNull final Action1 onNextAction) { - return baseLifecycleBindable.bind(observable, onNextAction); - } - @NonNull @Override public Subscription untilStop(@NonNull final Observable observable) { diff --git a/src/main/java/ru/touchin/roboswag/components/adapters/ObservableCollectionAdapter.java b/src/main/java/ru/touchin/roboswag/components/adapters/ObservableCollectionAdapter.java index 43bed1d..8236233 100644 --- a/src/main/java/ru/touchin/roboswag/components/adapters/ObservableCollectionAdapter.java +++ b/src/main/java/ru/touchin/roboswag/components/adapters/ObservableCollectionAdapter.java @@ -30,7 +30,6 @@ import java.util.Collection; import java.util.Collections; import java.util.LinkedList; import java.util.List; -import java.util.concurrent.TimeUnit; import ru.touchin.roboswag.components.utils.LifecycleBindable; import ru.touchin.roboswag.components.utils.UiUtils; @@ -42,7 +41,6 @@ import ru.touchin.roboswag.core.observables.collections.loadable.LoadingMoreList import ru.touchin.roboswag.core.utils.Optional; import ru.touchin.roboswag.core.utils.ShouldNotHappenException; import rx.Observable; -import rx.Subscription; import rx.android.schedulers.AndroidSchedulers; import rx.subjects.BehaviorSubject; @@ -58,30 +56,27 @@ import rx.subjects.BehaviorSubject; * @param Type of items to bind to ViewHolders; * @param Type of ViewHolders to show items. */ +@SuppressWarnings("unchecked") public abstract class ObservableCollectionAdapter extends RecyclerView.Adapter { - //it is needed to avoid massive requests on initial view holders attaching (like if we will add 10 items they all will try to load history) - private static final long DELAY_BEFORE_LOADING_HISTORY = TimeUnit.SECONDS.toMillis(1); - - private static final int PRE_LOADING_COUNT = 10; + private static final int PRE_LOADING_COUNT = 20; @NonNull private final BehaviorSubject>> observableCollectionSubject = BehaviorSubject.create(new Optional<>(null)); @NonNull + private final BehaviorSubject moreAutoLoadingRequested = BehaviorSubject.create(); + @NonNull private final LifecycleBindable lifecycleBindable; @Nullable - private OnItemClickListener onItemClickListener; + private Object onItemClickListener; private int lastUpdatedChangeNumber = -1; - @NonNull - private final Observable historyPreLoadingObservable; - @Nullable - private Subscription historyPreLoadingSubscription; @NonNull private final ObservableList innerCollection = new ObservableList<>(); private boolean anyChangeApplied; + private long itemClickDelayMillis; @NonNull private final List attachedRecyclerViews = new LinkedList<>(); @NonNull @@ -101,14 +96,29 @@ public abstract class ObservableCollectionAdapter { - final ObservableCollection collection = optional.get(); + lifecycleBindable.untilDestroy(createMoreAutoLoadingObservable()); + } + + @NonNull + private Observable createMoreAutoLoadingObservable() { + return observableCollectionSubject + .switchMap(collectionOptional -> { + final ObservableCollection collection = collectionOptional.get(); if (!(collection instanceof LoadingMoreList)) { return Observable.empty(); } - final int size = collection.size(); - return ((LoadingMoreList) collection).loadRange(size, size + PRE_LOADING_COUNT); + return moreAutoLoadingRequested + .distinctUntilChanged() + .switchMap(requested -> { + if (!requested) { + return Observable.empty(); + } + final int size = collection.size(); + return ((LoadingMoreList) collection) + .loadRange(size, size + PRE_LOADING_COUNT) + .onErrorResumeNext(Observable.empty()) + .doOnCompleted(() -> moreAutoLoadingRequested.onNext(false)); + }); }); } @@ -134,7 +144,7 @@ public abstract class ObservableCollectionAdapter> getDelegates() { return Collections.unmodifiableList(delegates); } - @SuppressWarnings("unchecked") + /** + * Adds {@link AdapterDelegate} to adapter. + * + * @param delegate Delegate to add. + */ public void addDelegate(@NonNull final AdapterDelegate delegate) { + for (final AdapterDelegate addedDelegate : delegates) { + if (addedDelegate.getItemViewType() == delegate.getItemViewType()) { + Lc.assertion("AdapterDelegate with viewType=" + delegate.getItemViewType() + " already added"); + return; + } + } delegates.add((AdapterDelegate) delegate); + notifyDataSetChanged(); } - @SuppressWarnings("unchecked") + /** + * Removes {@link AdapterDelegate} from adapter. + * + * @param delegate Delegate to remove. + */ public void removeDelegate(@NonNull final AdapterDelegate delegate) { delegates.remove((AdapterDelegate) delegate); + notifyDataSetChanged(); } @Override - public int getItemViewType(final int adapterPosition) { - final int itemCollectionPosition = adapterPosition - getHeadersCount(); - if (itemCollectionPosition < 0 || itemCollectionPosition >= innerCollection.size()) { - return super.getItemViewType(adapterPosition); + public int getItemViewType(final int positionInAdapter) { + final int positionInCollection = positionInAdapter - getHeadersCount(); + if (positionInCollection < 0 || positionInCollection >= innerCollection.size()) { + return super.getItemViewType(positionInAdapter); } - final TItem item = innerCollection.get(itemCollectionPosition); + final TItem item = innerCollection.get(positionInCollection); for (final AdapterDelegate delegate : delegates) { - if (delegate.isForViewType(item, adapterPosition, itemCollectionPosition)) { + if (delegate.isForViewType(item, positionInAdapter, positionInCollection)) { return delegate.getItemViewType(); } } - return super.getItemViewType(adapterPosition); + return super.getItemViewType(positionInAdapter); } @Override - public long getItemId(final int adapterPosition) { - final int itemCollectionPosition = adapterPosition - getHeadersCount(); - if (itemCollectionPosition < 0 || itemCollectionPosition >= innerCollection.size()) { - return super.getItemId(adapterPosition); + public long getItemId(final int positionInAdapter) { + final int positionInCollection = positionInAdapter - getHeadersCount(); + if (positionInCollection < 0 || positionInCollection >= innerCollection.size()) { + return super.getItemId(positionInAdapter); } - final int itemViewType = getItemViewType(adapterPosition); - final TItem item = innerCollection.get(itemCollectionPosition); + final int itemViewType = getItemViewType(positionInAdapter); + final TItem item = innerCollection.get(positionInCollection); for (final AdapterDelegate delegate : delegates) { if (delegate.getItemViewType() == itemViewType) { - return delegate.getItemId(item, adapterPosition, itemCollectionPosition); + return delegate.getItemId(item, positionInAdapter, positionInCollection); } } - return super.getItemId(adapterPosition); + return super.getItemId(positionInAdapter); } @Override @@ -349,31 +380,30 @@ public abstract class ObservableCollectionAdapter= innerCollection.size()) { + final int positionInCollection = positionInAdapter - getHeadersCount(); + if (positionInCollection < 0 || positionInCollection >= innerCollection.size()) { return; } - updateHistoryLoadingSubscription(adapterPosition); - bindItemViewHolder(holder, null, adapterPosition, itemCollectionPosition); + updateMoreAutoLoadingRequest(positionInCollection); + bindItemViewHolder(holder, null, positionInAdapter, positionInCollection); } @Override - public void onBindViewHolder(@NonNull final BindableViewHolder holder, final int adapterPosition, @NonNull final List payloads) { - super.onBindViewHolder(holder, adapterPosition, payloads); - final int itemCollectionPosition = adapterPosition - getHeadersCount(); - if (itemCollectionPosition < 0 || itemCollectionPosition >= innerCollection.size()) { + public void onBindViewHolder(@NonNull final BindableViewHolder holder, final int positionInAdapter, @NonNull final List payloads) { + super.onBindViewHolder(holder, positionInAdapter, payloads); + final int positionInCollection = positionInAdapter - getHeadersCount(); + if (positionInCollection < 0 || positionInCollection >= innerCollection.size()) { return; } - bindItemViewHolder(holder, payloads, adapterPosition, itemCollectionPosition); + bindItemViewHolder(holder, payloads, positionInAdapter, positionInCollection); } - @SuppressWarnings("unchecked") private void bindItemViewHolder(@NonNull final BindableViewHolder holder, @Nullable final List payloads, - final int adapterPosition, final int itemCollectionPosition) { + final int positionInAdapter, final int positionInCollection) { final TItemViewHolder itemViewHolder; try { itemViewHolder = (TItemViewHolder) holder; @@ -381,69 +411,79 @@ public abstract class ObservableCollectionAdapter onItemClickListener.onItemClicked(item, adapterPosition), getItemClickDelay()); - } + final TItem item = innerCollection.get(positionInCollection); + final int itemViewType = getItemViewType(positionInAdapter); + updateClickListener(holder, item, positionInAdapter, positionInCollection); for (final AdapterDelegate delegate : delegates) { if (itemViewType == delegate.getItemViewType()) { if (payloads == null) { - delegate.onBindViewHolder(itemViewHolder, item, adapterPosition, itemCollectionPosition); + delegate.onBindViewHolder(itemViewHolder, item, positionInAdapter, positionInCollection); } else { - delegate.onBindViewHolder(itemViewHolder, item, payloads, adapterPosition, itemCollectionPosition); + delegate.onBindViewHolder(itemViewHolder, item, payloads, positionInAdapter, positionInCollection); } return; } } if (payloads == null) { - onBindItemToViewHolder(itemViewHolder, adapterPosition, item); + onBindItemToViewHolder(itemViewHolder, positionInAdapter, item); } else { - onBindItemToViewHolder(itemViewHolder, adapterPosition, item, payloads); + onBindItemToViewHolder(itemViewHolder, positionInAdapter, item, payloads); } } - private void updateHistoryLoadingSubscription(final int position) { - if ((historyPreLoadingSubscription != null && !historyPreLoadingSubscription.isUnsubscribed()) - || position - getHeadersCount() > innerCollection.size() - PRE_LOADING_COUNT) { + private void updateClickListener(@NonNull final BindableViewHolder holder, @NonNull final TItem item, + final int positionInAdapter, final int positionInCollection) { + if (onItemClickListener != null && !isOnClickListenerDisabled(item, positionInAdapter, positionInCollection)) { + UiUtils.setOnRippleClickListener(holder.itemView, + () -> { + if (onItemClickListener instanceof OnItemClickListener) { + ((OnItemClickListener) onItemClickListener).onItemClicked(item); + } else if (onItemClickListener instanceof OnItemWithPositionClickListener) { + ((OnItemWithPositionClickListener) onItemClickListener).onItemClicked(item, positionInAdapter, positionInCollection); + } else { + Lc.assertion("Unexpected onItemClickListener type " + onItemClickListener); + } + }, + itemClickDelayMillis); + } + } + + private void updateMoreAutoLoadingRequest(final int positionInCollection) { + if (positionInCollection > innerCollection.size() - PRE_LOADING_COUNT) { return; } - historyPreLoadingSubscription = lifecycleBindable - .untilDestroy(historyPreLoadingObservable - .delaySubscription(DELAY_BEFORE_LOADING_HISTORY, TimeUnit.MILLISECONDS) - .onErrorResumeNext(Observable.empty())); + moreAutoLoadingRequested.onNext(true); } /** * Method to bind item (from {@link #getObservableCollection()}) to item-specific ViewHolder. * It is not calling for headers and footer which counts are returned by {@link #getHeadersCount()} and @link #getFootersCount()}. * - * @param holder ViewHolder to bind item to; - * @param position Position of ViewHolder (NOT item!); - * @param item Item returned by position (WITH HEADER OFFSET!). + * @param holder ViewHolder to bind item to; + * @param positionInAdapter Position of ViewHolder (NOT item!); + * @param item Item returned by position (WITH HEADER OFFSET!). */ - protected abstract void onBindItemToViewHolder(@NonNull TItemViewHolder holder, int position, @NonNull TItem item); + protected abstract void onBindItemToViewHolder(@NonNull TItemViewHolder holder, int positionInAdapter, @NonNull TItem item); /** * Method to bind item (from {@link #getObservableCollection()}) to item-specific ViewHolder with payloads. * It is not calling for headers and footer which counts are returned by {@link #getHeadersCount()} and @link #getFootersCount()}. * - * @param holder ViewHolder to bind item to; - * @param position Position of ViewHolder (NOT item!); - * @param item Item returned by position (WITH HEADER OFFSET!); - * @param payloads Payloads; + * @param holder ViewHolder to bind item to; + * @param positionInAdapter Position of ViewHolder in adapter (NOT item!); + * @param item Item returned by position (WITH HEADER OFFSET!); + * @param payloads Payloads. */ - protected void onBindItemToViewHolder(@NonNull final TItemViewHolder holder, final int position, @NonNull final TItem item, + protected void onBindItemToViewHolder(@NonNull final TItemViewHolder holder, final int positionInAdapter, @NonNull final TItem item, @NonNull final List payloads) { // do nothing by default } @Nullable - public TItem getItem(final int position) { - final int positionInList = position - getHeadersCount(); - return positionInList < 0 || positionInList >= innerCollection.size() ? null : innerCollection.get(positionInList); + public TItem getItem(final int positionInAdapter) { + final int positionInCollection = positionInAdapter - getHeadersCount(); + return positionInCollection < 0 || positionInCollection >= innerCollection.size() ? null : innerCollection.get(positionInCollection); } /** @@ -452,26 +492,51 @@ public abstract class ObservableCollectionAdapter onItemClickListener) { + this.setOnItemClickListener(onItemClickListener, UiUtils.RIPPLE_EFFECT_DELAY); + } + + /** + * Sets item click listener. + * + * @param onItemClickListener Item click listener; + * @param itemClickDelayMillis Delay of calling click listener. + */ + public void setOnItemClickListener(@Nullable final OnItemClickListener onItemClickListener, final long itemClickDelayMillis) { this.onItemClickListener = onItemClickListener; + this.itemClickDelayMillis = itemClickDelayMillis; refreshUpdate(); } /** - * Returns delay of item click. By default returns delay of ripple effect duration. + * Sets item click listener. * - * @return Milliseconds delay of click. + * @param onItemClickListener Item click listener. */ - protected long getItemClickDelay() { - return UiUtils.RIPPLE_EFFECT_DELAY; + public void setOnItemClickListener(@Nullable final OnItemWithPositionClickListener onItemClickListener) { + this.setOnItemClickListener(onItemClickListener, UiUtils.RIPPLE_EFFECT_DELAY); + } + + /** + * Sets item click listener. + * + * @param onItemClickListener Item click listener; + * @param itemClickDelayMillis Delay of calling click listener. + */ + public void setOnItemClickListener(@Nullable final OnItemWithPositionClickListener onItemClickListener, final long itemClickDelayMillis) { + this.onItemClickListener = onItemClickListener; + this.itemClickDelayMillis = itemClickDelayMillis; + refreshUpdate(); } /** * Returns if click listening disabled or not for specific item. * - * @param item Item to check click availability; + * @param item Item to check click availability; + * @param positionInAdapter Position of clicked item in adapter (with headers); + * @param positionInCollection Position of clicked item in inner collection; * @return True if click listener enabled for such item. */ - public boolean isOnClickListenerDisabled(@NonNull final TItem item) { + public boolean isOnClickListenerDisabled(@NonNull final TItem item, final int positionInAdapter, final int positionInCollection) { return false; } @@ -485,10 +550,27 @@ public abstract class ObservableCollectionAdapter Type of item + */ + public interface OnItemWithPositionClickListener { + + /** + * Calls when item have clicked. + * + * @param item Clicked item; + * @param positionInAdapter Position of clicked item in adapter (with headers); + * @param positionInCollection Position of clicked item in inner collection. + */ + void onItemClicked(@NonNull TItem item, final int positionInAdapter, final int positionInCollection); } 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 8d70cde..8377a10 100644 --- a/src/main/java/ru/touchin/roboswag/components/navigation/ViewController.java +++ b/src/main/java/ru/touchin/roboswag/components/navigation/ViewController.java @@ -339,12 +339,6 @@ public class ViewController, @SuppressWarnings("CPD-START") //CPD: it is same as in other implementation based on BaseLifecycleBindable - @NonNull - @Override - public Subscription bind(@NonNull final Observable observable, @NonNull final Action1 onNextAction) { - return baseLifecycleBindable.bind(observable, onNextAction); - } - @NonNull @Override public Subscription untilStop(@NonNull final Observable observable) { diff --git a/src/main/java/ru/touchin/roboswag/components/navigation/activities/BaseActivity.java b/src/main/java/ru/touchin/roboswag/components/navigation/activities/BaseActivity.java index 885e46b..ee07f36 100644 --- a/src/main/java/ru/touchin/roboswag/components/navigation/activities/BaseActivity.java +++ b/src/main/java/ru/touchin/roboswag/components/navigation/activities/BaseActivity.java @@ -256,12 +256,6 @@ public abstract class BaseActivity extends AppCompatActivity @SuppressWarnings("CPD-START") //CPD: it is same as in other implementation based on BaseLifecycleBindable - @NonNull - @Override - public Subscription bind(@NonNull final Observable observable, @NonNull final Action1 onNextAction) { - return baseLifecycleBindable.bind(observable, onNextAction); - } - @NonNull @Override public Subscription untilStop(@NonNull final Observable observable, 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 dae9481..6b23866 100644 --- a/src/main/java/ru/touchin/roboswag/components/utils/BaseLifecycleBindable.java +++ b/src/main/java/ru/touchin/roboswag/components/utils/BaseLifecycleBindable.java @@ -101,15 +101,6 @@ public class BaseLifecycleBindable implements LifecycleBindable { isCreatedSubject.onNext(false); } - @NonNull - @Override - public Subscription bind(@NonNull final Observable observable, @NonNull final Action1 onNextAction) { - 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, getActionThrowableForAssertion(codePoint, UNTIL_STOP_METHOD)); - } - @NonNull @Override public Subscription untilStop(@NonNull final Observable observable) { diff --git a/src/main/java/ru/touchin/roboswag/components/utils/LifecycleBindable.java b/src/main/java/ru/touchin/roboswag/components/utils/LifecycleBindable.java index 95d7b2f..f157356 100644 --- a/src/main/java/ru/touchin/roboswag/components/utils/LifecycleBindable.java +++ b/src/main/java/ru/touchin/roboswag/components/utils/LifecycleBindable.java @@ -35,18 +35,12 @@ import rx.functions.Action1; * Created by Gavriil Sitnikov on 15/04/16. * Interface that should be implemented by lifecycle-based elements ({@link android.app.Activity}, {@link android.support.v4.app.Fragment} etc.) * to not manually manage subscriptions. - * Use {@link #bind(Observable, Action1)} method to subscribe to observable onStart and unsubscribe onStop automatically. * Use {@link #untilStop(Observable)} method to subscribe to observable where you want and unsubscribe onStop. * Use {@link #untilDestroy(Observable)} method to subscribe to observable where you want and unsubscribe onDestroy. */ @SuppressWarnings("PMD.TooManyMethods") public interface LifecycleBindable { - @NonNull - //do not use this method - it's not obvious method - @Deprecated - Subscription bind(@NonNull Observable observable, @NonNull Action1 onNextAction); - /** * Method should be used to guarantee that observable won't be subscribed after onStop. * It is automatically subscribing to the observable.