/*
* Copyright 2013 Hari Krishna Dulipudi
*
* 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 dev.dworks.libs.astickyheader;
import java.util.Arrays;
import java.util.Comparator;
import android.content.Context;
import android.database.DataSetObserver;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import dev.dworks.libs.actionbarplus.widget.FillerView;
import dev.dworks.libs.actionbarplus.widget.HeaderLayout;
import dev.dworks.libs.actionbarplus.widget.PinnedSectionGridView;
import dev.dworks.libs.actionbarplus.widget.PinnedSectionGridView.PinnedSectionGridAdapter;
public class SimpleSectionedGridAdapter extends BaseAdapter implements PinnedSectionGridAdapter{
protected static final int TYPE_FILLER = 0;
protected static final int TYPE_HEADER = 1;
protected static final int TYPE_HEADER_FILLER = 2;
private boolean mValid = true;
private int mSectionResourceId;
private LayoutInflater mLayoutInflater;
private ListAdapter mBaseAdapter;
private SparseArray<Section> mSections = new SparseArray<Section>();
private Context mContext;
// private View mLastHeaderViewSeen;
private View mLastViewSeen;
private int mNumColumns;
private int mWidth;
private int mColumnWidth;
private int mHorizontalSpacing;
private int mStrechMode;
private int requestedColumnWidth;
private int requestedHorizontalSpacing;
private GridView mGridView;
private int mHeaderLayoutResId;
private int mHeaderTextViewResId;
public static class Section {
int firstPosition;
int sectionedPosition;
CharSequence title;
int type = 0;
public Section(int firstPosition, CharSequence title) {
this.firstPosition = firstPosition;
this.title = title;
}
public CharSequence getTitle() {
return title;
}
}
public SimpleSectionedGridAdapter(Context context, BaseAdapter baseAdapter, int sectionResourceId, int headerLayoutResId,
int headerTextViewResId) {
mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mSectionResourceId = sectionResourceId;
mHeaderLayoutResId = headerLayoutResId;
mHeaderTextViewResId = headerTextViewResId;
mBaseAdapter = baseAdapter;
mContext = context;
mBaseAdapter.registerDataSetObserver(new DataSetObserver() {
@Override
public void onChanged() {
mValid = !mBaseAdapter.isEmpty();
notifyDataSetChanged();
}
@Override
public void onInvalidated() {
mValid = false;
notifyDataSetInvalidated();
}
});
}
public void setGridView(GridView gridView){
if(!(gridView instanceof PinnedSectionGridView)){
throw new IllegalArgumentException("Does your grid view extends PinnedSectionGridView?");
}
mGridView = gridView;
mStrechMode = gridView.getStretchMode();
mWidth = gridView.getWidth() - (mGridView.getPaddingLeft() + mGridView.getPaddingRight());
mNumColumns = ((PinnedSectionGridView)gridView).getNumColumns();
requestedColumnWidth = ((PinnedSectionGridView)gridView).getColumnWidth();
requestedHorizontalSpacing = ((PinnedSectionGridView)gridView).getHorizontalSpacing();
}
private int getHeaderSize(){
if(mWidth != mGridView.getWidth()){
mStrechMode = mGridView.getStretchMode();
mWidth = mGridView.getWidth() - (mGridView.getPaddingLeft() + mGridView.getPaddingRight());
mNumColumns = ((PinnedSectionGridView)mGridView).getNumColumns();
requestedColumnWidth = ((PinnedSectionGridView)mGridView).getColumnWidth();
requestedHorizontalSpacing = ((PinnedSectionGridView)mGridView).getHorizontalSpacing();
}
int spaceLeftOver = mWidth - (mNumColumns * requestedColumnWidth) -
((mNumColumns - 1) * requestedHorizontalSpacing);
switch (mStrechMode) {
case GridView.NO_STRETCH: // Nobody stretches
mWidth -= spaceLeftOver;
mColumnWidth = requestedColumnWidth;
mHorizontalSpacing = requestedHorizontalSpacing;
break;
case GridView.STRETCH_COLUMN_WIDTH:
mColumnWidth = requestedColumnWidth + spaceLeftOver / mNumColumns;
mHorizontalSpacing = requestedHorizontalSpacing;
break;
case GridView.STRETCH_SPACING:
mColumnWidth = requestedColumnWidth;
if (mNumColumns > 1) {
mHorizontalSpacing = requestedHorizontalSpacing +
spaceLeftOver / (mNumColumns - 1);
} else {
mHorizontalSpacing = requestedHorizontalSpacing + spaceLeftOver;
}
break;
case GridView.STRETCH_SPACING_UNIFORM:
mColumnWidth = requestedColumnWidth;
mHorizontalSpacing = requestedHorizontalSpacing;
mWidth = mWidth - spaceLeftOver + (2 * mHorizontalSpacing);
break;
}
return mWidth + ((mNumColumns - 1) * (mColumnWidth + mHorizontalSpacing)) ;
}
public void setSections(Section[] sections) {
mSections.clear();
Arrays.sort(sections, new Comparator<Section>() {
@Override
public int compare(Section o, Section o1) {
return (o.firstPosition == o1.firstPosition)
? 0
: ((o.firstPosition < o1.firstPosition) ? -1 : 1);
}
});
int offset = 0; // offset positions for the headers we're adding
for (int i = 0; i < sections.length; i++) {
Section section = sections[i];
Section sectionAdd;
for (int j = 0; j < mNumColumns - 1; j++) {
sectionAdd = new Section(section.firstPosition, section.title);
sectionAdd.type = TYPE_HEADER_FILLER;
sectionAdd.sectionedPosition = sectionAdd.firstPosition + offset;
mSections.append(sectionAdd.sectionedPosition, sectionAdd);
++offset;
}
sectionAdd = new Section(section.firstPosition, section.title);
sectionAdd.type = TYPE_HEADER;
sectionAdd.sectionedPosition = sectionAdd.firstPosition + offset;
mSections.append(sectionAdd.sectionedPosition, sectionAdd);
++offset;
if(i+1 < sections.length){
int nextPos = sections[i+1].firstPosition;
int itemsCount = nextPos - section.firstPosition;
int dummyCount = mNumColumns - (itemsCount % mNumColumns);
if(mNumColumns != dummyCount){
for (int j = 0 ;j < dummyCount; j++) {
sectionAdd = new Section(section.firstPosition, section.title);
sectionAdd.type = TYPE_FILLER;
sectionAdd.sectionedPosition = nextPos + offset;
mSections.append(sectionAdd.sectionedPosition, sectionAdd);
++offset;
}
}
}
}
notifyDataSetChanged();
}
public int positionToSectionedPosition(int position) {
int offset = 0;
for (int i = 0; i < mSections.size(); i++) {
if (mSections.valueAt(i).firstPosition > position) {
break;
}
++offset;
}
return position + offset;
}
public int sectionedPositionToPosition(int sectionedPosition) {
if (isSectionHeaderPosition(sectionedPosition)) {
return ListView.INVALID_POSITION;
}
int offset = 0;
for (int i = 0; i < mSections.size(); i++) {
if (mSections.valueAt(i).sectionedPosition > sectionedPosition) {
break;
}
--offset;
}
return sectionedPosition + offset;
}
public boolean isSectionHeaderPosition(int position) {
return mSections.get(position) != null;
}
@Override
public int getCount() {
return (mValid ? mBaseAdapter.getCount() + mSections.size() : 0);
}
@Override
public Object getItem(int position) {
return isSectionHeaderPosition(position)
? mSections.get(position)
: mBaseAdapter.getItem(sectionedPositionToPosition(position));
}
@Override
public long getItemId(int position) {
return isSectionHeaderPosition(position)
? Integer.MAX_VALUE - mSections.indexOfKey(position)
: mBaseAdapter.getItemId(sectionedPositionToPosition(position));
}
@Override
public int getItemViewType(int position) {
return isSectionHeaderPosition(position)
? getViewTypeCount() - 1
: mBaseAdapter.getItemViewType(position);
}
@Override
public boolean isEnabled(int position) {
//noinspection SimplifiableConditionalExpression
return isSectionHeaderPosition(position)
? false
: mBaseAdapter.isEnabled(sectionedPositionToPosition(position));
}
@Override
public int getViewTypeCount() {
return mBaseAdapter.getViewTypeCount() + 1; // the section headings
}
@Override
public boolean areAllItemsEnabled() {
return mBaseAdapter.areAllItemsEnabled();
}
@Override
public boolean hasStableIds() {
return mBaseAdapter.hasStableIds();
}
@Override
public boolean isEmpty() {
return mBaseAdapter.isEmpty();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (isSectionHeaderPosition(position)) {
HeaderLayout header;
TextView view;
if (null == convertView) {
convertView = mLayoutInflater.inflate(mSectionResourceId, parent, false);
} else {
if (null == convertView.findViewById(mHeaderLayoutResId)) {
convertView = mLayoutInflater.inflate(mSectionResourceId, parent, false);
}
}
switch (mSections.get(position).type) {
case TYPE_HEADER:
header = (HeaderLayout) convertView.findViewById(mHeaderLayoutResId);
view = (TextView) convertView.findViewById(mHeaderTextViewResId);
view.setText(mSections.get(position).title);
header.setHeaderWidth(getHeaderSize());
break;
case TYPE_HEADER_FILLER:
header = (HeaderLayout) convertView.findViewById(mHeaderLayoutResId);
view = (TextView) convertView.findViewById(mHeaderTextViewResId);
view.setText(mSections.get(position).title);
header.setHeaderWidth(0);
break;
default:
convertView = getFillerView(mLastViewSeen);
}
} else {
convertView = mBaseAdapter.getView(sectionedPositionToPosition(position), convertView, parent);
mLastViewSeen = convertView;
}
return convertView;
}
private FillerView getFillerView(final View lastViewSeen) {
final FillerView fillerView = new FillerView(mContext);
fillerView.setMeasureTarget(lastViewSeen);
return fillerView;
}
@Override
public boolean isItemViewTypePinned(int position) {
Section section = mSections.get(position);
return isSectionHeaderPosition(position) && section.type != TYPE_FILLER;
}
@Override
public int getHeaderLayoutResId() {
return mHeaderLayoutResId;
}
public static class ViewHolder {
@SuppressWarnings("unchecked")
public static <T extends View> T get(View view, int id) {
SparseArray<View> viewHolder = (SparseArray<View>) view.getTag();
if (viewHolder == null) {
viewHolder = new SparseArray<View>();
view.setTag(viewHolder);
}
View childView = viewHolder.get(id);
if (childView == null) {
childView = view.findViewById(id);
viewHolder.put(id, childView);
}
return (T) childView;
}
}
}