package fr.ydelouis.selfoss.adapter; import android.content.Context; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.BaseAdapter; import java.util.ArrayList; import java.util.List; import fr.ydelouis.selfoss.view.PagedAdapterViewWrapper; public abstract class PagedAdapter<T> extends BaseAdapter implements View.OnClickListener { private enum State { Idle, Loading, Error, End } private int anticipation = 0; private View loadingView; private View errorView; private View endView; private State state; private List<T> data = new ArrayList<T>(); private PagedAdapterViewWrapper adapterViewWrapper; public PagedAdapter() { } public PagedAdapter(PagedAdapterViewWrapper adapterViewWrapper) { setAdapterViewWrapper(adapterViewWrapper); } public void setAdapterViewWrapper(PagedAdapterViewWrapper adapterViewWrapper) { if(adapterViewWrapper == null) throw new IllegalArgumentException("The PagedAdapterViewWrapper must not be null"); this.adapterViewWrapper = adapterViewWrapper; adapterViewWrapper.setAdapter(this); } @Override public View getView(int position, View view, ViewGroup viewGroup) { if(isNewPageNeeded(position)) loadNextItems(); if(isFooterView(position)) return getFooterView(); return getView(position, view); } private boolean isNewPageNeeded(int position) { if(state != State.Idle) return false; return position >= getCount()-1 - anticipation; } private boolean hasFooterView() { return getFooterView() != null; } private View getFooterView() { if(data.isEmpty() && state != State.Loading) { if(state == State.Error && getEmptyErrorView() != null) return null; if(getEmptyView() != null) return null; } if(state == State.Loading) { return getLoadingView(); } if(state == State.Error) { View view = getErrorView(); view.setOnClickListener(this); return view; } if(state == State.End) return getEndView(); return null; } public void reset() { data.clear(); setState(State.Idle); loadNextItems(); } public void loadNextItems() { setState(State.Loading); } public void loadNewItems() { setState(State.Loading); } public void onItemsLoaded(List<T> newItems, boolean areNewItems) { if(areNewItems && !data.isEmpty()) addNewItems(newItems); else addNextItems(newItems); } private void addNewItems(List<T> newItems) { if(newItems != null) addToStart(newItems); setState(State.Idle); } private void addToStart(List<T> newItems) { int index = 0; for(T t : newItems) { if(!data.contains(t)) { data.add(index, t); index++; } } } private void addNextItems(List<T> nextItems) { if(nextItems == null) setState(State.Error); else if(nextItems.isEmpty()) setState(State.End); else { append(nextItems); setState(State.Idle); } } private void append(List<T> nextItems) { for(T t : nextItems) { if(!data.contains(t)) data.add(t); } } protected void replace(T item) { int index = data.indexOf(item); if (index > -1) { data.set(index, item); notifyDataSetChanged(); } } private void setState(State state) { adapterViewWrapper.removeEmptyView(); if(data.isEmpty() && state != State.Loading) showEmptyView(state); this.state = state; notifyDataSetChanged(); } private void showEmptyView(State state) { if(state == State.Error && adapterViewWrapper.getEmptyErrorView() != null) adapterViewWrapper.showEmptyErrorView(); else adapterViewWrapper.showEmptyView(); } public int getAnticipation() { return anticipation; } public void setAnticipation(int anticipation) { this.anticipation = anticipation; } public void setLoadingView(View loadingView) { this.loadingView = loadingView; } private View getLoadingView() { if(loadingView != null) return loadingView; return adapterViewWrapper.getLoadingView(); } public void setErrorView(View errorView) { this.errorView = errorView; } private View getErrorView() { if(errorView != null) return errorView; return adapterViewWrapper.getErrorView(); } public void setEndView(View endView) { this.endView = endView; } private View getEndView() { if(endView != null) return endView; return adapterViewWrapper.getEndView(); } private View getEmptyErrorView() { return adapterViewWrapper.getEmptyErrorView(); } private View getEmptyView() { return adapterViewWrapper.getEmptyView(); } public Context getContext() { return adapterViewWrapper.getContext(); } private boolean isFooterView(int position) { return position == data.size(); } @Override public void onClick(View view) { if(view.equals(getErrorView())) loadNextItems(); } @Override public int getItemViewType(int position) { if(isFooterView(position)) return AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER; return 0; } @Override public int getViewTypeCount() { return 1; } @Override public int getCount() { int count = data.size(); if(hasFooterView()) count++; return count; } public int getItemCount() { return data.size(); } @Override public T getItem(int i) { if(i < data.size()) return data.get(i); return null; } @Override public long getItemId(int i) { if(i < data.size()) return i; return -1; } @Override public boolean isEnabled(int position) { return !isFooterView(position); } @Override public boolean areAllItemsEnabled() { return false; } public abstract View getView(int position, View view); }