/*
* Copyright 2016 Hannes Dorfmann.
*
* 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 com.hannesdorfmann.mosby3.sample.mvi.view.home;
import android.support.v7.util.DiffUtil;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import com.hannesdorfmann.mosby3.sample.mvi.businesslogic.model.AdditionalItemsLoadable;
import com.hannesdorfmann.mosby3.sample.mvi.businesslogic.model.FeedItem;
import com.hannesdorfmann.mosby3.sample.mvi.businesslogic.model.Product;
import com.hannesdorfmann.mosby3.sample.mvi.businesslogic.model.SectionHeader;
import com.hannesdorfmann.mosby3.sample.mvi.view.ui.viewholder.LoadingViewHolder;
import com.hannesdorfmann.mosby3.sample.mvi.view.ui.viewholder.MoreItemsViewHolder;
import com.hannesdorfmann.mosby3.sample.mvi.view.ui.viewholder.ProductViewHolder;
import com.hannesdorfmann.mosby3.sample.mvi.view.ui.viewholder.SectionHederViewHolder;
import io.reactivex.Observable;
import io.reactivex.subjects.PublishSubject;
import java.util.List;
/**
* @author Hannes Dorfmann
*/
public class HomeAdapter extends RecyclerView.Adapter
implements MoreItemsViewHolder.LoadItemsClickListener {
static final int VIEW_TYPE_PRODUCT = 0;
static final int VIEW_TYPE_LOADING_MORE_NEXT_PAGE = 1;
static final int VIEW_TYPE_SECTION_HEADER = 2;
static final int VIEW_TYPE_MORE_ITEMS_AVAILABLE = 3;
private boolean isLoadingNextPage = false;
private List<FeedItem> items;
private final LayoutInflater layoutInflater;
private final ProductViewHolder.ProductClickedListener productClickedListener;
private PublishSubject<String> loadMoreItemsOfCategoryObservable = PublishSubject.create();
public HomeAdapter(LayoutInflater layoutInflater,
ProductViewHolder.ProductClickedListener productClickedListener) {
this.layoutInflater = layoutInflater;
this.productClickedListener = productClickedListener;
}
public List<FeedItem> getItems() {
return items;
}
/**
* @return true if value has changed since last invocation
*/
public boolean setLoadingNextPage(boolean loadingNextPage) {
boolean hasLoadingMoreChanged = loadingNextPage != isLoadingNextPage;
boolean notifyInserted = loadingNextPage && hasLoadingMoreChanged;
boolean notifyRemoved = !loadingNextPage && hasLoadingMoreChanged;
isLoadingNextPage = loadingNextPage;
if (notifyInserted) {
notifyItemInserted(items.size());
} else if (notifyRemoved) {
notifyItemRemoved(items.size());
}
return hasLoadingMoreChanged;
}
public boolean isLoadingNextPage() {
return isLoadingNextPage;
}
public void setItems(List<FeedItem> newItems) {
List<FeedItem> oldItems = this.items;
this.items = newItems;
if (oldItems == null) {
notifyDataSetChanged();
} else {
// Use Diff utils
DiffUtil.calculateDiff(new DiffUtil.Callback() {
@Override public int getOldListSize() {
return oldItems.size();
}
@Override public int getNewListSize() {
return newItems.size();
}
@Override public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
Object oldItem = oldItems.get(oldItemPosition);
Object newItem = newItems.get(newItemPosition);
if (oldItem instanceof Product
&& newItem instanceof Product
&& ((Product) oldItem).getId() == ((Product) newItem).getId()) {
return true;
}
if (oldItem instanceof SectionHeader
&& newItem instanceof SectionHeader
&& ((SectionHeader) oldItem).getName().equals(((SectionHeader) newItem).getName())) {
return true;
}
if (oldItem instanceof AdditionalItemsLoadable
&& newItem instanceof AdditionalItemsLoadable
&& ((AdditionalItemsLoadable) oldItem).getCategoryName()
.equals(((AdditionalItemsLoadable) newItem).getCategoryName())) {
return true;
}
return false;
}
@Override public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
Object oldItem = oldItems.get(oldItemPosition);
Object newItem = newItems.get(newItemPosition);
return oldItem.equals(newItem);
}
}, true).dispatchUpdatesTo(this);
}
}
@Override public int getItemViewType(int position) {
if (isLoadingNextPage && position == items.size()) {
return VIEW_TYPE_LOADING_MORE_NEXT_PAGE;
}
FeedItem item = items.get(position);
if (item instanceof Product) {
return VIEW_TYPE_PRODUCT;
} else if (item instanceof SectionHeader) {
return VIEW_TYPE_SECTION_HEADER;
} else if (item instanceof AdditionalItemsLoadable) {
return VIEW_TYPE_MORE_ITEMS_AVAILABLE;
}
throw new IllegalArgumentException("Not able to dertermine the view type for item at position "
+ position
+ ". Item is: "
+ item);
}
@Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case VIEW_TYPE_PRODUCT:
return ProductViewHolder.create(layoutInflater, productClickedListener);
case VIEW_TYPE_LOADING_MORE_NEXT_PAGE:
return LoadingViewHolder.create(layoutInflater);
case VIEW_TYPE_MORE_ITEMS_AVAILABLE:
return MoreItemsViewHolder.create(layoutInflater, this);
case VIEW_TYPE_SECTION_HEADER:
return SectionHederViewHolder.create(layoutInflater);
}
throw new IllegalArgumentException("Couldn't create a ViewHolder for viewType = " + viewType);
}
@Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (holder instanceof LoadingViewHolder) {
return;
}
FeedItem item = items.get(position);
if (holder instanceof ProductViewHolder) {
((ProductViewHolder) holder).bind((Product) item);
} else if (holder instanceof SectionHederViewHolder) {
((SectionHederViewHolder) holder).onBind((SectionHeader) item);
} else if (holder instanceof MoreItemsViewHolder) {
((MoreItemsViewHolder) holder).bind((AdditionalItemsLoadable) item);
} else {
throw new IllegalArgumentException("couldn't accept ViewHolder " + holder);
}
}
@Override public int getItemCount() {
return items == null ? 0 : (items.size() + (isLoadingNextPage ? 1 : 0));
}
@Override public void loadItemsForCategory(String category) {
loadMoreItemsOfCategoryObservable.onNext(category);
}
public Observable<String> loadMoreItemsOfCategoryObservable() {
return loadMoreItemsOfCategoryObservable;
}
}