package com.battlelancer.seriesguide.adapters; import android.content.Context; import android.support.v4.util.LongSparseArray; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.TextView; import com.battlelancer.seriesguide.R; import com.battlelancer.seriesguide.adapters.model.HeaderData; import com.battlelancer.seriesguide.util.TimeTools; import com.battlelancer.seriesguide.util.Utils; import com.tonicartos.widget.stickygridheaders.StickyGridHeadersBaseAdapter; import com.uwetrottmann.trakt5.entities.HistoryEntry; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; /** * A sectioned {@link HistoryEntry} adapter, grouping watched items by day. */ public abstract class SectionedHistoryAdapter extends ArrayAdapter<HistoryEntry> implements StickyGridHeadersBaseAdapter { protected final LayoutInflater mInflater; private List<HeaderData> mHeaders; private Calendar mCalendar; private final int mResIdDrawableWatched; private final int mResIdDrawableCheckin; public SectionedHistoryAdapter(Context context) { super(context, 0); mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); mCalendar = Calendar.getInstance(); mResIdDrawableWatched = Utils.resolveAttributeToResourceId(getContext().getTheme(), R.attr.drawableWatch); mResIdDrawableCheckin = Utils.resolveAttributeToResourceId(getContext().getTheme(), R.attr.drawableCheckin); } public void setData(List<HistoryEntry> data) { clear(); if (data != null) { addAll(data); } } public int getResIdDrawableWatched() { return mResIdDrawableWatched; } public int getResIdDrawableCheckin() { return mResIdDrawableCheckin; } @Override public int getCountForHeader(int position) { if (mHeaders != null) { return mHeaders.get(position).getCount(); } return 0; } @Override public int getNumHeaders() { if (mHeaders != null) { return mHeaders.size(); } return 0; } @Override public View getHeaderView(int position, View convertView, ViewGroup parent) { // get header position for item position position = mHeaders.get(position).getRefPosition(); HistoryEntry item = getItem(position); if (item == null) { return null; } HeaderViewHolder holder; if (convertView == null) { convertView = mInflater.inflate(R.layout.item_grid_header, parent, false); holder = new HeaderViewHolder(); holder.day = (TextView) convertView.findViewById(R.id.textViewGridHeader); convertView.setTag(holder); } else { holder = (HeaderViewHolder) convertView.getTag(); } long headerTime = getHeaderTime(item); // display headers like "Mon in 3 days", also "today" when applicable holder.day.setText( TimeTools.formatToLocalDayAndRelativeTime(getContext(), new Date(headerTime))); return convertView; } @Override public void notifyDataSetChanged() { // re-create headers before letting notifyDataSetChanged reach the AdapterView mHeaders = generateHeaderList(); super.notifyDataSetChanged(); } @Override public void notifyDataSetInvalidated() { // remove headers before letting notifyDataSetChanged reach the AdapterView mHeaders = null; super.notifyDataSetInvalidated(); } protected List<HeaderData> generateHeaderList() { int count = getCount(); if (count == 0) { return null; } LongSparseArray<HeaderData> mapping = new LongSparseArray<>(); List<HeaderData> headers = new ArrayList<>(); for (int position = 0; position < count; position++) { long headerId = getHeaderId(position); HeaderData headerData = mapping.get(headerId); if (headerData == null) { headerData = new HeaderData(position); headers.add(headerData); } headerData.incrementCount(); mapping.put(headerId, headerData); } return headers; } /** * Maps all actions of the same day in the device time zone to the same id (which equals the * time in ms close to midnight of that day). */ private long getHeaderId(int position) { HistoryEntry item = getItem(position); if (item != null) { return getHeaderTime(item); } return 0; } /** * Extracts the action timestamp and "rounds" it down to shortly after midnight in the current * device time zone. */ private long getHeaderTime(HistoryEntry item) { mCalendar.setTimeInMillis(item.watched_at.getMillis()); // mCalendar.set(Calendar.HOUR_OF_DAY, 0); mCalendar.set(Calendar.MINUTE, 0); mCalendar.set(Calendar.SECOND, 0); mCalendar.set(Calendar.MILLISECOND, 1); return mCalendar.getTimeInMillis(); } static class HeaderViewHolder { public TextView day; } }