package info.guardianproject.securereaderinterface.widgets; import info.guardianproject.securereaderinterface.models.PagedViewContent; import info.guardianproject.securereaderinterface.models.ViewPagerIndicator; import java.util.ArrayList; import java.util.Collections; import android.content.Context; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; public class PagedView extends NestedViewPager { public interface PagedViewListener { PagedViewContent onMovedToPrevious(); PagedViewContent onMovedToNext(); } private PagedViewPagerAdapter mPageAdapter; private PagedViewContent mOriginalContentPrevious; private PagedViewContent mOriginalContentThis; private PagedViewContent mOriginalContentNext; private boolean mContentPreviousReversed; private boolean mContentThisReversed; private boolean mContentNextReversed; private ArrayList<View> mPageViewsThis; private ArrayList<View> mPageViewsPrevious; private ArrayList<View> mPageViewsNext; private ArrayList<View> mPageViewsAll; private PagedViewListener mListener; private ViewPagerIndicator mViewPagerIndicator; public PagedView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { mPageViewsAll = new ArrayList<View>(); mPageAdapter = new PagedViewPagerAdapter(); setAdapter(mPageAdapter); super.setOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageScrollStateChanged(int state) { if (state == ViewPager.SCROLL_STATE_IDLE) { post(new Runnable() { @Override public void run() { adjustCurrentIndex(getCurrentItem()); if (mViewPagerIndicator != null) { if (mContentThisReversed) mViewPagerIndicator.onCurrentChanged(getCurrentItem() - ((mPageViewsNext != null) ? mPageViewsNext.size() : 0)); else mViewPagerIndicator.onCurrentChanged(getCurrentItem() - ((mPageViewsPrevious != null) ? mPageViewsPrevious.size() : 0)); } } }); } } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { } @Override public void onPageSelected(int position) { } }); } public void setListener(PagedViewListener listener) { mListener = listener; } @Override public void setViewPagerIndicator(ViewPagerIndicator viewPagerIndicator) { mViewPagerIndicator = viewPagerIndicator; updateViewPagerIndicator(); } private void updateViewPagerIndicator() { if (mViewPagerIndicator != null) { if (mPageViewsThis != null) mViewPagerIndicator.onTotalChanged(mPageViewsThis.size()); else mViewPagerIndicator.onTotalChanged(0); if (mContentThisReversed) mViewPagerIndicator.onCurrentChanged(getCurrentItem() - ((mPageViewsNext != null) ? mPageViewsNext.size() : 0)); else mViewPagerIndicator.onCurrentChanged(getCurrentItem() - ((mPageViewsPrevious != null) ? mPageViewsPrevious.size() : 0)); } } public PagedViewContent getContentThis() { return mOriginalContentThis; } public void setContentThis(PagedViewContent content) { mOriginalContentThis = content; update(); } public PagedViewContent getContentPrevious() { return mOriginalContentPrevious; } public void setContentPrevious(PagedViewContent content) { mOriginalContentPrevious = content; update(); } public PagedViewContent getContentNext() { return mOriginalContentNext; } public void setContentNext(PagedViewContent content) { mOriginalContentNext = content; update(); } public void recreateAllViews() { int currentPageNumberInThisContent = -1; int pos = mPageAdapter.getItemPosition(mPageViewsThis.get(0)); if (pos != PagerAdapter.POSITION_NONE) { if (getCurrentItem() >= pos) currentPageNumberInThisContent = getCurrentItem() - pos; } // Null them so they will be recreated mPageViewsThis = null; mPageViewsPrevious = null; mPageViewsNext = null; updateViews(currentPageNumberInThisContent); } public void recreateViewsForContent(PagedViewContent content) { int currentPageNumberInThisContent = -1; if (this.mOriginalContentPrevious == content) mPageViewsPrevious = null; else if (this.mOriginalContentNext == content) mPageViewsNext = null; else if (this.mOriginalContentThis == content) { int pos = PagerAdapter.POSITION_NONE; if (mPageViewsThis != null && mPageViewsThis.size() > 0) pos = mPageAdapter.getItemPosition(mPageViewsThis.get(0)); if (pos != PagerAdapter.POSITION_NONE) { if (getCurrentItem() >= pos) currentPageNumberInThisContent = getCurrentItem() - pos; } mPageViewsThis = null; } updateViews(currentPageNumberInThisContent); } private ArrayList<View> createViewsForContent(PagedViewContent content) { if (content == null) return null; int height = this.getHeight(); if (height == 0) return null; ArrayList<View> ret = content.createPages(this); for (View view : ret) { view.setTag(content); } return ret; } private void update() { if (getWidth() == 0 || getHeight() == 0) return; mContentThisReversed = (mOriginalContentThis == null) ? false : mOriginalContentThis.usesReverseSwipe(); mContentPreviousReversed = (mOriginalContentPrevious == null) ? false : mOriginalContentPrevious.usesReverseSwipe(); mContentNextReversed = (mOriginalContentNext == null) ? false : mOriginalContentNext.usesReverseSwipe(); if (mPageViewsPrevious == null) mPageViewsPrevious = createViewsForContent(mOriginalContentPrevious); if (mPageViewsThis == null) mPageViewsThis = createViewsForContent(mOriginalContentThis); if (mPageViewsNext == null) mPageViewsNext = createViewsForContent(mOriginalContentNext); mPageViewsAll.clear(); if (mContentThisReversed) { ArrayList<View> temp; if (mPageViewsNext != null) { temp = new ArrayList<View>(mPageViewsNext); Collections.reverse(temp); mPageViewsAll.addAll(temp); } if (mPageViewsThis != null) { temp = new ArrayList<View>(mPageViewsThis); Collections.reverse(temp); mPageViewsAll.addAll(temp); } if (mPageViewsPrevious != null) { temp = new ArrayList<View>(mPageViewsPrevious); Collections.reverse(temp); mPageViewsAll.addAll(temp); } } else { if (mPageViewsPrevious != null) mPageViewsAll.addAll(mPageViewsPrevious); if (mPageViewsThis != null) mPageViewsAll.addAll(mPageViewsThis); if (mPageViewsNext != null) mPageViewsAll.addAll(mPageViewsNext); } } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); post(new Runnable() { @Override public void run() { // Null them so they will be recreated mPageViewsThis = null; mPageViewsPrevious = null; mPageViewsNext = null; updateViews(0); } }); } public void updateViews(int scrollToThisIndexInThis) { update(); if (this.mPageAdapter != null) mPageAdapter.notifyDataSetChanged(); if (scrollToThisIndexInThis != -1 && mPageViewsThis != null && mPageViewsThis.size() > 0 && mPageAdapter != null) { int pos = mPageAdapter.getItemPosition(mPageViewsThis.get(0)); if (pos != PagerAdapter.POSITION_NONE) { if (scrollToThisIndexInThis >= mPageViewsThis.size()) scrollToThisIndexInThis = mPageViewsThis.size() - 1; if (mContentThisReversed) pos -= scrollToThisIndexInThis; else pos += scrollToThisIndexInThis; setCurrentItem(pos, false); } } updateViewPagerIndicator(); } private int getNumberOfPages() { int count = mPageViewsAll.size(); return count; } private void adjustCurrentIndex(int position) { if (mOriginalContentPrevious != null && mPageViewsAll.get(position).getTag() == mOriginalContentPrevious) { // Moved to previous! // mContentNextReversed = mContentThisReversed; mOriginalContentNext = mOriginalContentThis; mPageViewsNext = mPageViewsThis; mContentThisReversed = mContentPreviousReversed; mOriginalContentThis = mOriginalContentPrevious; mPageViewsThis = mPageViewsPrevious; if (mListener != null) { mOriginalContentPrevious = mListener.onMovedToPrevious(); } else { mOriginalContentPrevious = null; } mPageViewsPrevious = null; updateViews(-1); } else if (mOriginalContentNext != null && mPageViewsAll.get(position).getTag() == mOriginalContentNext) { // Moved to next! // mContentPreviousReversed = mContentThisReversed; mOriginalContentPrevious = mOriginalContentThis; mPageViewsPrevious = mPageViewsThis; mContentThisReversed = mContentNextReversed; mOriginalContentThis = mOriginalContentNext; mPageViewsThis = mPageViewsNext; if (mListener != null) { mOriginalContentNext = mListener.onMovedToNext(); } else { mOriginalContentNext = null; } mPageViewsNext = null; updateViews(-1); } } private class PagedViewPagerAdapter extends PagerAdapter { public PagedViewPagerAdapter() { super(); } @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == (View) arg1; } @Override public Object instantiateItem(ViewGroup container, int position) { View view = PagedView.this.mPageViewsAll.get(position); if (view.getParent() != null) ((ViewGroup) view.getParent()).removeView(view); ((ViewPager) container).addView(view); return view; } @Override public int getItemPosition(Object object) { for (int i = 0; i < mPageViewsAll.size(); i++) { if (mPageViewsAll.get(i).equals(object)) { return i; } } return POSITION_NONE; } @Override public void destroyItem(ViewGroup container, int position, Object object) { ((ViewPager) container).removeView((View) object); } @Override public int getCount() { int count = PagedView.this.getNumberOfPages(); return count; } } }