/*
* Copyright 2015 Fabio Collini.
*
* 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 it.cosenonjaviste.mv2m.recycler;
import android.databinding.ObservableList;
import android.support.v7.widget.RecyclerView;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
public class BindableAdapter<T> extends RecyclerView.Adapter<BindableViewHolder<T>> {
private final ObservableList.OnListChangedCallback<ObservableList<T>> onListChangedCallback;
private ObservableList<? extends T> items;
private List<ViewHolderFactory<? extends T>> viewHolderFactories = new ArrayList<>();
private ViewHolderFactory<T> defaultViewHolderFactory;
private List<ViewTypeSelector> viewTypeSelectors = new ArrayList<>();
private BindListener<T> onBindListener;
public BindableAdapter(ObservableList<? extends T> items) {
this(items, null);
}
public BindableAdapter(ObservableList<? extends T> items, ViewHolderFactory<T> defaultViewHolderFactory) {
this.items = items;
this.defaultViewHolderFactory = defaultViewHolderFactory;
//saved in a field to maintain a reference and avoid garbage collection
onListChangedCallback = new AdapterOnListChangedCallback<>(this);
items.addOnListChangedCallback((ObservableList.OnListChangedCallback) new WeakOnListChangedCallback<>(onListChangedCallback));
if (!items.isEmpty()) {
notifyDataSetChanged();
}
}
public void addViewType(ViewHolderFactory<? extends T> viewHolderFactory, ViewTypeSelector selector) {
viewHolderFactories.add(viewHolderFactory);
viewTypeSelectors.add(selector);
}
public <I extends T> void addViewType(ViewHolderFactory<I> viewHolderFactory, final Class<I> itemClass) {
viewHolderFactories.add(viewHolderFactory);
viewTypeSelectors.add(new ClassViewTypeSelector<>(itemClass));
}
@Override public int getItemViewType(int position) {
int i = 0;
for (ViewTypeSelector selector : viewTypeSelectors) {
if (selector.isOfViewType(position)) {
return i;
}
i++;
}
if (defaultViewHolderFactory == null) {
throw new RuntimeException("No factory found and no default factory available for item in position " + position);
}
return -1;
}
@Override public BindableViewHolder<T> onCreateViewHolder(ViewGroup viewGroup, int viewType) {
ViewHolderFactory<? extends T> factory;
if (viewType != -1) {
factory = viewHolderFactories.get(viewType);
} else {
factory = defaultViewHolderFactory;
}
return (BindableViewHolder) factory.create(viewGroup);
}
@Override public void onBindViewHolder(BindableViewHolder<T> viewHolder, int position) {
viewHolder.bind(items.get(position));
if (onBindListener != null) {
onBindListener.call(viewHolder, position);
}
}
@Override public int getItemCount() {
return items.size();
}
public void setOnBindListener(BindListener<T> onBindListener) {
this.onBindListener = onBindListener;
}
public interface ViewHolderFactory<T> {
BindableViewHolder<T> create(ViewGroup viewGroup);
}
public interface ViewTypeSelector {
boolean isOfViewType(int position);
}
public interface BindListener<T> {
void call(BindableViewHolder<T> viewHolder, Integer position);
}
private class ClassViewTypeSelector<I> implements ViewTypeSelector {
private final Class<I> itemClass;
public ClassViewTypeSelector(Class<I> itemClass) {
this.itemClass = itemClass;
}
@Override public boolean isOfViewType(int position) {
T item = items.get(position);
return item != null && item.getClass().isAssignableFrom(itemClass);
}
}
}