package com.ecollege.android.adapter; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; import org.apache.commons.lang.NotImplementedException; import android.app.Activity; import android.content.Context; import android.database.DataSetObserver; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; import com.ecollege.android.R; import com.ecollege.android.adapter.UberItem.UberItemType; public class UberAdapter<T> extends BaseAdapter { protected Context context; private boolean isLoading = false; private boolean canLoadMore = true; private boolean hasHeader; private boolean hasFooter; private long lastUpdatedAt = -1; private List<T> dataItems; private List<UberItem<T>> uberItems; private UberItem<T> loadMoreItem = new UberItem<T>(UberItemType.LOAD_MORE_ITEM); private UberItem<T> loadingItem = new UberItem<T>(UberItemType.LOADING_ITEM); private UberItem<T> noDataItem = new UberItem<T>(UberItemType.NO_DATA_ITEM); private UberItem<T> lastUpdatedItem = new UberItem<T>(UberItemType.LAST_UPDATED_ITEM); private int specialItemViewType = 0; private int dataItemViewType = 1; private int headerItemViewType = 2; private int footerItemViewType = 3; private int lastUpdatedViewType = 4; private int viewTypeCount = 5; //+1 if hasHeader, +1 if hasFooter private SimpleDateFormat lastUpdatedDateFormat; private String lastUpdatedWrapperFormat; public UberAdapter(Context context, boolean hasHeader, boolean hasFooter, boolean canLoadMore) { this.canLoadMore = canLoadMore; this.context = context; this.hasHeader = hasHeader; this.hasFooter = hasFooter; } // set to 0 for "Never", anything greater for an actual date // if not called it won't show public void setLastUpdatedAt(long lastUpdatedAt) { assert lastUpdatedAt >= 0; if (this.lastUpdatedAt == -1) { this.lastUpdatedDateFormat = new SimpleDateFormat(context.getString(R.string.last_updated_date_format)); this.lastUpdatedWrapperFormat = context.getString(R.string.last_updated_s); } this.lastUpdatedAt = lastUpdatedAt; this.notifyDataSetChanged(); } public void beginLoading() { this.isLoading = true; this.notifyDataSetChanged(); } public void hasError() { this.isLoading = false; this.dataItems = null; this.uberItems = null; this.notifyDataSetChanged(); } public void updateItems(List<T> dataItems) { updateItems(dataItems,canLoadMore); } public void updateItems(T[] dataItems) { updateItems(Arrays.asList(dataItems)); } public void updateItems(T[] dataItems, boolean canLoadMore) { updateItems(Arrays.asList(dataItems),canLoadMore); } public void updateItems(List<T> dataItems, boolean canLoadMore) { assert dataItems != null; this.isLoading = false; this.canLoadMore = canLoadMore; this.dataItems = dataItems; calculateGrouping(); this.notifyDataSetChanged(); } protected Object groupIdFunction(T item) { //override in subclass throw new RuntimeException("groupIdFunction required for " + this.getClass().getSimpleName()); } protected void calculateGrouping() { assert dataItems != null; uberItems = new ArrayList<UberItem<T>>(); Object lastGroupId = null; Object currentGroupId = null; for (int i=0;i<dataItems.size();i++) { if (hasHeader || hasFooter) { currentGroupId = groupIdFunction(dataItems.get(i)); if (lastGroupId == null && hasHeader) { uberItems.add(new UberItem<T>(UberItemType.HEADER,currentGroupId)); } else if (currentGroupId != null && !currentGroupId.equals(lastGroupId)) { if (hasFooter) { uberItems.add(new UberItem<T>(UberItemType.FOOTER,currentGroupId)); } if (hasHeader) { uberItems.add(new UberItem<T>(UberItemType.HEADER,currentGroupId)); } } uberItems.add(new UberItem<T>(dataItems.get(i),i)); lastGroupId = currentGroupId; } else { uberItems.add(new UberItem<T>(dataItems.get(i),i)); } } if (hasFooter && currentGroupId != null) { uberItems.add(new UberItem<T>(UberItemType.FOOTER,currentGroupId)); } } public int getCount() { if (isLoading) { return 1; } else { if (dataItems == null) { return 0; //show nothing while waiting to begin loading } else { if (dataItems.size() == 0) { return 1; // item that says no items } else { int count = uberItems.size(); if (lastUpdatedAt >= 0) count++; if (canLoadMore) count++; return count; } } } } public List<T> getDataItems() { return null; } public UberItem<T> getItem(int position) { if (isLoading) { return loadingItem; } else { if (dataItems == null) { return null; //empty list } else { if (dataItems.size() == 0) { return noDataItem; // item that says no items } else { if (lastUpdatedAt >= 0 && position == 0) { return lastUpdatedItem; } else if (canLoadMore && position == (getCount() - 1)) { return loadMoreItem; } else { int dataItemPosition = lastUpdatedAt >= 0 ? position - 1 : position; return uberItems.get(dataItemPosition); } } } } } public long getItemId(int position) { return position; } public int getItemViewType(int position) { UberItem<T> item = getItem(position); if (item.getItemType() == UberItemType.LOAD_MORE_ITEM) return specialItemViewType; if (item.getItemType() == UberItemType.LOADING_ITEM) return specialItemViewType; if (item.getItemType() == UberItemType.NO_DATA_ITEM) return specialItemViewType; if (item.getItemType() == UberItemType.HEADER) return headerItemViewType; if (item.getItemType() == UberItemType.FOOTER) return footerItemViewType; if (item.getItemType() == UberItemType.LAST_UPDATED_ITEM) return lastUpdatedViewType; return dataItemViewType; } public View getLoadMoreView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = ((Activity)context).getLayoutInflater().inflate(R.layout.load_more_item, null); } return convertView; } public View getLoadingView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = ((Activity)context).getLayoutInflater().inflate(R.layout.loading_item, null); } return convertView; } private static class SpecialItemViewHolder { ImageView iconImage; ProgressBar loadingIndicator; TextView titleText; } private static class HeaderViewHolder { TextView headerLabelText; } protected View getSpecialView(int position, View convertView, ViewGroup parent, UberItem<T> item) { SpecialItemViewHolder holder; if (convertView == null) { convertView = ((Activity)context).getLayoutInflater().inflate(R.layout.special_item, null); holder = new SpecialItemViewHolder(); holder.iconImage = (ImageView) convertView.findViewById(R.id.icon_image); holder.loadingIndicator = (ProgressBar) convertView.findViewById(R.id.loading_indicator); holder.titleText = (TextView) convertView.findViewById(R.id.title_text); convertView.setTag(holder); } else { holder = (SpecialItemViewHolder) convertView.getTag(); } if (item.getItemType() == UberItemType.NO_DATA_ITEM) { holder.iconImage.setVisibility(View.VISIBLE); holder.loadingIndicator.setVisibility(View.INVISIBLE); holder.iconImage.setImageResource(R.drawable.ic_no_responses); holder.titleText.setText(R.string.li_no_items); } else if (item.getItemType() == UberItemType.LOAD_MORE_ITEM) { holder.iconImage.setVisibility(View.INVISIBLE); holder.loadingIndicator.setVisibility(View.INVISIBLE); holder.titleText.setText(R.string.li_load_more); } else if (item.getItemType() == UberItemType.LOADING_ITEM) { holder.iconImage.setVisibility(View.INVISIBLE); holder.loadingIndicator.setVisibility(View.VISIBLE); holder.titleText.setText(R.string.li_loading); } else { throw new RuntimeException("getSpecialView doesn't support item type " + item.getItemType().toString()); } return convertView; } //optionally override in subclass protected View getHeaderView(int position, View convertView, ViewGroup parent, Object groupId) { HeaderViewHolder holder; if (convertView == null) { convertView = ((Activity)context).getLayoutInflater().inflate(R.layout.list_header_item, null); holder = new HeaderViewHolder(); holder.headerLabelText = (TextView) convertView.findViewById(R.id.header_label_text); convertView.setTag(holder); } else { holder = (HeaderViewHolder) convertView.getTag(); } holder.headerLabelText.setText(groupId.toString()); return convertView; } private static class LastUpdatedViewHolder { TextView lastUpdatedText; } protected View getLastUpdatedView(View convertView, ViewGroup parent, UberItem<T> item, long lastUpdatedAt) { LastUpdatedViewHolder holder; if (convertView == null) { convertView = ((Activity)context).getLayoutInflater().inflate(R.layout.last_updated_view, null); holder = new LastUpdatedViewHolder(); holder.lastUpdatedText = (TextView) convertView.findViewById(R.id.last_updated_text); convertView.setTag(holder); } else { holder = (LastUpdatedViewHolder) convertView.getTag(); } String dateText; if (lastUpdatedAt > 0) { dateText = lastUpdatedDateFormat.format(new Date(lastUpdatedAt)); } else { dateText = context.getString(R.string.never); } holder.lastUpdatedText.setText(String.format(lastUpdatedWrapperFormat, dateText)); return convertView; } //must override in subclass if hasFooter protected View getFooterView(int position, View convertView, ViewGroup parent, Object groupId) { throw new NotImplementedException(); } //must override in subclass protected View getDataItemView(View convertView, ViewGroup parent, UberItem<T> item) { throw new NotImplementedException(); } public View getView(int position, View convertView, ViewGroup parent) { UberItem<T> item = getItem(position); if (item.getItemType() == UberItemType.HEADER) { return getHeaderView(position, convertView, parent, item.getGroupId()); } else if (item.getItemType() == UberItemType.FOOTER) { return getFooterView(position, convertView, parent, item.getGroupId()); } else if (item.getItemType() == UberItemType.LOAD_MORE_ITEM) { return getSpecialView(position, convertView, parent, item); } else if (item.getItemType() == UberItemType.LOADING_ITEM) { return getSpecialView(position, convertView, parent, item); } else if (item.getItemType() == UberItemType.NO_DATA_ITEM) { return getSpecialView(position, convertView, parent, item); } else if (item.getItemType() == UberItemType.LAST_UPDATED_ITEM) { return getLastUpdatedView(convertView, parent, item, lastUpdatedAt); } else { return getDataItemView(convertView, parent, item); } } public int getViewTypeCount() { return viewTypeCount; } public void registerDataSetObserver(DataSetObserver observer) { super.registerDataSetObserver(observer); } public void unregisterDataSetObserver(DataSetObserver observer) { super.unregisterDataSetObserver(observer); } public boolean hasStableIds() { return false; } public boolean isEmpty() { return getItem(0) != null; } public boolean areAllItemsEnabled() { return false; } public boolean isEnabled(int position) { UberItem<T> item = getItem(position); if (item == null) return false; if (item == loadMoreItem) return true; if (item.getItemType() == UberItemType.DATA_ITEM) return true; return false; } }