From d11efcbe5046181b819917e63efc9db77b93c362 Mon Sep 17 00:00:00 2001 From: Gavriil Sitnikov Date: Mon, 23 May 2016 22:03:09 +0300 Subject: [PATCH] adapter for observe added --- .../adapters/ObservableCollectionAdapter.java | 164 ++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 src/main/java/ru/touchin/roboswag/components/listing/adapters/ObservableCollectionAdapter.java diff --git a/src/main/java/ru/touchin/roboswag/components/listing/adapters/ObservableCollectionAdapter.java b/src/main/java/ru/touchin/roboswag/components/listing/adapters/ObservableCollectionAdapter.java new file mode 100644 index 0000000..88810b5 --- /dev/null +++ b/src/main/java/ru/touchin/roboswag/components/listing/adapters/ObservableCollectionAdapter.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2015 RoboSwag (Gavriil Sitnikov, Vsevolod Ivanov) + * + * This file is part of RoboSwag library. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package ru.touchin.roboswag.components.listing.adapters; + +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.RecyclerView; +import android.view.ViewGroup; + +import java.util.List; + +import ru.touchin.roboswag.components.R; +import ru.touchin.roboswag.components.utils.UiUtils; +import ru.touchin.roboswag.core.log.Lc; +import ru.touchin.roboswag.core.observables.collections.Change; +import ru.touchin.roboswag.core.observables.collections.ObservableCollection; +import ru.touchin.roboswag.core.observables.collections.ObservableList; +import ru.touchin.roboswag.core.utils.ShouldNotHappenException; +import rx.Subscription; +import rx.android.schedulers.AndroidSchedulers; +import rx.functions.Actions; + +/** + * Created by Gavriil Sitnikov on 20/11/2015. + * TODO: fill description + */ +public abstract class ObservableCollectionAdapter + extends RecyclerView.Adapter { + + private static final int PRE_LOADING_COUNT = 10; + + private static final int LOADED_ITEM_TYPE = R.id.LOADED_ITEM_TYPE; + + @Nullable + private OnItemClickListener onItemClickListener; + @Nullable + private ObservableCollection observableCollection; + @Nullable + private Subscription itemsProviderSubscription; + + protected long getItemClickDelay() { + return UiUtils.RIPPLE_EFFECT_DELAY; + } + + public void setItems(@NonNull final List items) { + setObservableCollection(new ObservableList<>(items)); + } + + @Nullable + public ObservableCollection getObservableCollection() { + return observableCollection; + } + + protected int itemsOffset() { + return 0; + } + + public void setObservableCollection(@Nullable final ObservableCollection observableCollection) { + if (itemsProviderSubscription != null) { + itemsProviderSubscription.unsubscribe(); + itemsProviderSubscription = null; + } + this.observableCollection = observableCollection; + notifyDataSetChanged(); + if (this.observableCollection != null) { + itemsProviderSubscription = this.observableCollection.observeChanges() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(this::onItemsChanged); + } + } + + protected void onItemsChanged(@NonNull final Change change) { + switch (change.getType()) { + case INSERTED: + notifyItemRangeInserted(change.getStart() + itemsOffset(), change.getCount()); + break; + case CHANGED: + notifyItemRangeChanged(change.getStart() + itemsOffset(), change.getCount()); + break; + case REMOVED: + notifyItemRangeRemoved(change.getStart() + itemsOffset(), change.getCount()); + break; + default: + Lc.assertion("Not supported " + change.getType()); + break; + } + } + + public void setOnItemClickListener(@Nullable final OnItemClickListener onItemClickListener) { + this.onItemClickListener = onItemClickListener; + notifyDataSetChanged(); + } + + @Override + public int getItemViewType(final int position) { + return LOADED_ITEM_TYPE; + } + + @Override + public RecyclerView.ViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) { + return onCreateItemViewHolder(parent, viewType); + } + + public abstract TViewHolder onCreateItemViewHolder(final ViewGroup parent, final int viewType); + + @SuppressWarnings("unchecked") + @Override + public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) { + final TItem item = getItem(position); + if (observableCollection == null) { + Lc.assertion(new ShouldNotHappenException("Item at" + position + " should not be null")); + return; + } + onBindItemToViewHolder((TViewHolder) holder, position, item); + observableCollection.loadRange(Math.max(0, position - PRE_LOADING_COUNT), position + PRE_LOADING_COUNT).first() + .subscribe(Actions.empty(), Actions.empty()); + if (onItemClickListener != null && !isOnClickListenerDisabled(item)) { + UiUtils.setOnRippleClickListener(holder.itemView, () -> onItemClickListener.onItemClicked(item, position), getItemClickDelay()); + } + } + + protected abstract void onBindItemToViewHolder(@NonNull final TViewHolder holder, final int position, @NonNull TItem item); + + @NonNull + public TItem getItem(final int position) { + if (observableCollection == null) { + throw new ShouldNotHappenException(); + } + return observableCollection.get(position); + } + + @Override + public int getItemCount() { + return observableCollection != null ? observableCollection.size() : 0; + } + + public boolean isOnClickListenerDisabled(@NonNull final TItem item) { + return false; + } + + public interface OnItemClickListener { + + void onItemClicked(@NonNull TItem item, int position); + + } + +}