/*
* Copyright 2015 Hippo Seven
*
* 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 com.hippo.widget;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.hippo.easyrecyclerview.EasyRecyclerView;
import com.hippo.easyrecyclerview.FastScroller;
import com.hippo.easyrecyclerview.HandlerDrawable;
import com.hippo.easyrecyclerview.LayoutManagerUtils;
import com.hippo.ehviewer.R;
import com.hippo.refreshlayout.RefreshLayout;
import com.hippo.util.DrawableManager;
import com.hippo.util.ExceptionUtils;
import com.hippo.view.ViewTransition;
import com.hippo.yorozuya.IntIdGenerator;
import com.hippo.yorozuya.LayoutUtils;
import com.hippo.yorozuya.ResourcesUtils;
import com.hippo.yorozuya.collect.IntList;
import java.util.ArrayList;
import java.util.List;
public class ContentLayout extends FrameLayout {
private ProgressView mProgressView;
private TextView mTipView;
private ViewGroup mContentView;
private RefreshLayout mRefreshLayout;
private EasyRecyclerView mRecyclerView;
private FastScroller mFastScroller;
private ContentHelper mContentHelper;
private int mRecyclerViewOriginTop;
private int mRecyclerViewOriginBottom;
public ContentLayout(Context context) {
super(context);
init(context);
}
public ContentLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ContentLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
LayoutInflater.from(context).inflate(R.layout.widget_content_layout, this);
mProgressView = (ProgressView) findViewById(R.id.progress);
mTipView = (TextView) findViewById(R.id.tip);
mContentView = (ViewGroup) findViewById(R.id.content_view);
mRefreshLayout = (RefreshLayout) mContentView.findViewById(R.id.refresh_layout);
mFastScroller = (FastScroller) mContentView.findViewById(R.id.fast_scroller);
mRecyclerView = (EasyRecyclerView) mRefreshLayout.findViewById(R.id.recycler_view);
mFastScroller.attachToRecyclerView(mRecyclerView);
HandlerDrawable drawable = new HandlerDrawable();
drawable.setColor(ResourcesUtils.getAttrColor(context, R.attr.colorAccent));
mFastScroller.setHandlerDrawable(drawable);
mRefreshLayout.setHeaderColorSchemeResources(
R.color.loading_indicator_red,
R.color.loading_indicator_purple,
R.color.loading_indicator_blue,
R.color.loading_indicator_cyan,
R.color.loading_indicator_green,
R.color.loading_indicator_yellow);
mRefreshLayout.setFooterColorSchemeResources(
R.color.loading_indicator_red,
R.color.loading_indicator_blue,
R.color.loading_indicator_green,
R.color.loading_indicator_orange);
mRecyclerViewOriginTop = mRecyclerView.getPaddingTop();
mRecyclerViewOriginBottom = mRecyclerView.getPaddingBottom();
}
@NonNull
public EasyRecyclerView getRecyclerView() {
return mRecyclerView;
}
public FastScroller getFastScroller() {
return mFastScroller;
}
public RefreshLayout getRefreshLayout() {
return mRefreshLayout;
}
public void setHelper(ContentHelper helper) {
mContentHelper = helper;
helper.init(this);
}
public void showFastScroll() {
if (!mFastScroller.isAttached()) {
mFastScroller.attachToRecyclerView(mRecyclerView);
}
}
public void hideFastScroll() {
mFastScroller.detachedFromRecyclerView();
}
public void setFitPaddingTop(int fitPaddingTop) {
// RecyclerView
mRecyclerView.setPadding(mRecyclerView.getPaddingLeft(), mRecyclerViewOriginTop + fitPaddingTop, mRecyclerView.getPaddingRight(), mRecyclerView.getPaddingBottom());
// RefreshLayout
mRefreshLayout.setProgressViewOffset(false, fitPaddingTop, fitPaddingTop + LayoutUtils.dp2pix(getContext(), 32)); // TODO
}
public void setFitPaddingBottom(int fitPaddingBottom) {
// RecyclerView
mRecyclerView.setPadding(mRecyclerView.getPaddingLeft(),
mRecyclerView.getPaddingTop(), mRecyclerView.getPaddingRight(),
mRecyclerViewOriginBottom + fitPaddingBottom);
}
@Override
protected Parcelable onSaveInstanceState() {
return mContentHelper.saveInstanceState(super.onSaveInstanceState());
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
super.onRestoreInstanceState(mContentHelper.restoreInstanceState(state));
}
public abstract static class ContentHelper<E extends Parcelable> implements ViewTransition.OnShowViewListener {
private static final String TAG = ContentHelper.class.getSimpleName();
private static final String KEY_SUPER = "super";
private static final String KEY_SHOWN_VIEW = "shown_view";
private static final String KEY_TIP = "tip";
private static final String KEY_DATA = "data";
private static final String KEY_NEXT_ID = "next_id";
private static final String KEY_PAGE_DIVIDER = "page_divider";
private static final String KEY_START_PAGE = "start_page";
private static final String KEY_END_PAGE = "end_page";
private static final String KEY_PAGES = "pages";
public static final int TYPE_REFRESH = 0;
public static final int TYPE_PRE_PAGE = 1;
public static final int TYPE_PRE_PAGE_KEEP_POS = 2;
public static final int TYPE_NEXT_PAGE = 3;
public static final int TYPE_NEXT_PAGE_KEEP_POS = 4;
public static final int TYPE_SOMEWHERE = 5;
public static final int TYPE_REFRESH_PAGE = 6;
public static final int REFRESH_TYPE_HEADER = 0;
public static final int REFRESH_TYPE_FOOTER = 1;
public static final int REFRESH_TYPE_PROGRESS_VIEW = 2;
private ProgressView mProgressView;
private TextView mTipView;
private ViewGroup mContentView;
private RefreshLayout mRefreshLayout;
private EasyRecyclerView mRecyclerView;
private ViewTransition mViewTransition;
/**
* Store data
*/
private ArrayList<E> mData = new ArrayList<>();
/**
* Generate task id
*/
private final IntIdGenerator mIdGenerator = new IntIdGenerator();
/**
* Store the page divider index
*
* For example, the data contain page 3, page 4, page 5,
* page 3 size is 7, page 4 size is 8, page 5 size is 9,
* so <code>mPageDivider</code> contain 7, 15, 24.
*/
private IntList mPageDivider = new IntList();
/**
* The first page in <code>mData</code>
*/
private int mStartPage;
/**
* The last page + 1 in <code>mData</code>
*/
private int mEndPage;
/**
* The available page count.
*/
private int mPages;
private int mCurrentTaskId;
private int mCurrentTaskType;
private int mCurrentTaskPage;
private int mNextPageScrollSize;
private String mEmptyString = "No hint";
private final RecyclerView.OnScrollListener mOnScrollListener = new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (!mRefreshLayout.isRefreshing() && mRefreshLayout.isAlmostBottom() && mEndPage < mPages) {
// Get next page
mRefreshLayout.setFooterRefreshing(true);
mOnRefreshListener.onFooterRefresh();
}
}
};
private final RefreshLayout.OnRefreshListener mOnRefreshListener = new RefreshLayout.OnRefreshListener() {
@Override
public void onHeaderRefresh() {
if (mStartPage > 0) {
mCurrentTaskId = mIdGenerator.nextId();
mCurrentTaskType = TYPE_PRE_PAGE_KEEP_POS;
mCurrentTaskPage = mStartPage - 1;
getPageData(mCurrentTaskId, mCurrentTaskType, mCurrentTaskPage);
} else {
doRefresh();
}
}
@Override
public void onFooterRefresh() {
if (mEndPage < mPages) {
// Get next page
mCurrentTaskId = mIdGenerator.nextId();
mCurrentTaskType = TYPE_NEXT_PAGE_KEEP_POS;
mCurrentTaskPage = mEndPage;
getPageData(mCurrentTaskId, mCurrentTaskType, mCurrentTaskPage);
} else if (mEndPage == mPages) {
// Refresh last page
mCurrentTaskId = mIdGenerator.nextId();
mCurrentTaskType = TYPE_REFRESH_PAGE;
mCurrentTaskPage = mEndPage - 1;
getPageData(mCurrentTaskId, mCurrentTaskType, mCurrentTaskPage);
} else {
Log.e(TAG, "Try to footer refresh, but mEndPage = " + mEndPage + ", mPages = " + mPages);
}
}
};
private final LayoutManagerUtils.OnScrollToPositionListener mOnScrollToPositionListener =
new LayoutManagerUtils.OnScrollToPositionListener() {
@Override
public void onScrollToPosition(int position) {
ContentHelper.this.onScrollToPosition(position);
}
};
private void init(ContentLayout contentLayout) {
mNextPageScrollSize = LayoutUtils.dp2pix(contentLayout.getContext(), 48);
mProgressView = contentLayout.mProgressView;
mTipView = contentLayout.mTipView;
mContentView = contentLayout.mContentView;
mRefreshLayout = contentLayout.mRefreshLayout;
mRecyclerView = contentLayout.mRecyclerView;
Drawable drawable = DrawableManager.getDrawable(getContext(), R.drawable.big_weird_face);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
mTipView.setCompoundDrawables(null, drawable, null, null);
mViewTransition = new ViewTransition(mContentView, mProgressView, mTipView);
mViewTransition.setOnShowViewListener(this);
mRecyclerView.addOnScrollListener(mOnScrollListener);
mRefreshLayout.setOnRefreshListener(mOnRefreshListener);
mTipView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
refresh();
}
});
}
/**
* Call {@link #onGetPageData(int, List)} when get data
*
* @param taskId task id
* @param page the page to get
*/
protected abstract void getPageData(int taskId, int type, int page);
protected abstract Context getContext();
protected abstract void notifyDataSetChanged();
protected abstract void notifyItemRangeRemoved(int positionStart, int itemCount);
protected abstract void notifyItemRangeInserted(int positionStart, int itemCount);
protected void onScrollToPosition(int postion) {}
@Override
public void onShowView(View hiddenView, View shownView) {}
public int getShownViewIndex() {
return mViewTransition.getShownViewIndex();
}
public void setRefreshLayoutEnable(boolean enable) {
mRefreshLayout.setEnabled(enable);
}
public void setEnable(boolean enable) {
mRefreshLayout.setEnabled(enable);
}
public void setEmptyString(String str) {
mEmptyString = str;
}
public List<E> getData() {
return mData;
}
/**
* @throws IndexOutOfBoundsException
* if {@code location < 0 || location >= size()}
*/
public E getDataAt(int location) {
return mData.get(location);
}
public int size() {
return mData.size();
}
public boolean isCurrentTask(int taskId) {
return mCurrentTaskId == taskId;
}
public void setPages(int taskId, int pages) {
// TODO what it pages > mEndPage
if (mCurrentTaskId == taskId) {
mPages = pages;
}
}
public int getPages() {
return mPages;
}
public void addAt(int index, E data) {
mData.add(index, data);
for (int i = 0, n = mPageDivider.size(); i < n; i++) {
int divider = mPageDivider.get(i);
if (index < divider) {
mPageDivider.set(i, divider + 1);
}
}
notifyItemRangeInserted(index, 1);
}
public void removeAt(int index) {
mData.remove(index);
for (int i = 0, n = mPageDivider.size(); i < n; i++) {
int divider = mPageDivider.get(i);
if (index < divider) {
mPageDivider.set(i, divider - 1);
}
}
notifyItemRangeRemoved(index, 1);
}
public void onGetPageData(int taskId, List<E> data) {
if (mCurrentTaskId == taskId) {
int dataSize;
switch (mCurrentTaskType) {
case TYPE_REFRESH:
mStartPage = 0;
mEndPage = 1;
mPageDivider.clear();
mPageDivider.add(data.size());
if (data.isEmpty()) {
mData.clear();
notifyDataSetChanged();
if (true || mEndPage >= mPages) { // Not found
// Ui change, show empty string
mRefreshLayout.setHeaderRefreshing(false);
mRefreshLayout.setFooterRefreshing(false);
showEmptyString();
} else {
// Ui change, show progress bar
mRefreshLayout.setHeaderRefreshing(false);
mRefreshLayout.setFooterRefreshing(false);
showProgressBar();
// Get next page
mCurrentTaskId = mIdGenerator.nextId();
mCurrentTaskType = TYPE_NEXT_PAGE_KEEP_POS;
mCurrentTaskPage = mEndPage;
getPageData(mCurrentTaskId, mCurrentTaskType, mCurrentTaskPage);
}
} else {
mData.clear();
mData.addAll(data);
notifyDataSetChanged();
// Ui change, show content
mRefreshLayout.setHeaderRefreshing(false);
mRefreshLayout.setFooterRefreshing(false);
showContent();
// RecyclerView scroll
if (mRecyclerView.isAttachedToWindow()) {
mRecyclerView.stopScroll();
LayoutManagerUtils.scrollToPositionWithOffset(mRecyclerView.getLayoutManager(), 0, 0);
onScrollToPosition(0);
}
}
break;
case TYPE_PRE_PAGE:
case TYPE_PRE_PAGE_KEEP_POS:
dataSize = data.size();
for (int i = 0, n = mPageDivider.size(); i < n; i++) {
mPageDivider.set(i, mPageDivider.get(i) + dataSize);
}
mPageDivider.add(0, dataSize);
mStartPage--;
// assert mStartPage >= 0
if (data.isEmpty()) {
if (true || mStartPage <= 0) { // OK, that's all
if (mData.isEmpty()) {
// Ui change, show empty string
mRefreshLayout.setHeaderRefreshing(false);
mRefreshLayout.setFooterRefreshing(false);
showEmptyString();
} else {
// Ui change, show content
mRefreshLayout.setHeaderRefreshing(false);
mRefreshLayout.setFooterRefreshing(false);
showContent();
if (mCurrentTaskType == TYPE_PRE_PAGE && mRecyclerView.isAttachedToWindow()) {
// RecyclerView scroll, to top
mRecyclerView.stopScroll();
LayoutManagerUtils.scrollToPositionWithOffset(mRecyclerView.getLayoutManager(), 0, 0);
onScrollToPosition(0);
}
}
} else {
// Keep UI
// Get previous
mCurrentTaskId = mIdGenerator.nextId();
// Keep mCurrentTaskType
mCurrentTaskPage = mStartPage - 1;
getPageData(mCurrentTaskId, mCurrentTaskType, mCurrentTaskPage);
}
} else {
mData.addAll(0, data);
notifyItemRangeInserted(0, data.size());
// Ui change, show content
mRefreshLayout.setHeaderRefreshing(false);
mRefreshLayout.setFooterRefreshing(false);
showContent();
if (mRecyclerView.isAttachedToWindow()) {
// RecyclerView scroll
if (mCurrentTaskType == TYPE_PRE_PAGE_KEEP_POS) {
mRecyclerView.stopScroll();
LayoutManagerUtils.scrollToPositionProperly(mRecyclerView.getLayoutManager(), getContext(),
dataSize - 1, mOnScrollToPositionListener);
} else {
mRecyclerView.stopScroll();
LayoutManagerUtils.scrollToPositionWithOffset(mRecyclerView.getLayoutManager(), 0, 0);
onScrollToPosition(0);
}
}
}
break;
case TYPE_NEXT_PAGE:
case TYPE_NEXT_PAGE_KEEP_POS:
dataSize = data.size();
int oldDataSize = mData.size();
mPageDivider.add(oldDataSize + dataSize);
mEndPage++;
if (data.isEmpty()) {
if (true || mEndPage >= mPages) { // OK, that's all
if (mData.isEmpty()) {
// Ui change, show empty string
mRefreshLayout.setHeaderRefreshing(false);
mRefreshLayout.setFooterRefreshing(false);
showEmptyString();
} else {
// Ui change, show content
mRefreshLayout.setHeaderRefreshing(false);
mRefreshLayout.setFooterRefreshing(false);
showContent();
if (mCurrentTaskType == TYPE_NEXT_PAGE && mRecyclerView.isAttachedToWindow()) {
// RecyclerView scroll
mRecyclerView.stopScroll();
LayoutManagerUtils.scrollToPositionWithOffset(mRecyclerView.getLayoutManager(), oldDataSize, 0);
onScrollToPosition(oldDataSize);
}
}
} else {
// Keep UI
// Get next page
mCurrentTaskId = mIdGenerator.nextId();
// Keep mCurrentTaskType
mCurrentTaskPage = mEndPage;
getPageData(mCurrentTaskId, mCurrentTaskType, mCurrentTaskPage);
}
} else {
mData.addAll(data);
notifyItemRangeInserted(oldDataSize, dataSize);
// Ui change, show content
mRefreshLayout.setHeaderRefreshing(false);
mRefreshLayout.setFooterRefreshing(false);
showContent();
if (mRecyclerView.isAttachedToWindow()) {
if (mCurrentTaskType == TYPE_NEXT_PAGE_KEEP_POS) {
mRecyclerView.stopScroll();
mRecyclerView.smoothScrollBy(0, mNextPageScrollSize);
} else {
mRecyclerView.stopScroll();
LayoutManagerUtils.scrollToPositionWithOffset(mRecyclerView.getLayoutManager(), oldDataSize, 0);
onScrollToPosition(oldDataSize);
}
}
}
break;
case TYPE_SOMEWHERE:
mStartPage = mCurrentTaskPage;
mEndPage = mCurrentTaskPage + 1;
mPageDivider.clear();
mPageDivider.add(data.size());
if (data.isEmpty()) {
mData.clear();
notifyDataSetChanged();
if (true || mEndPage >= mPages) { // Not found
// Ui change, show empty string
mRefreshLayout.setHeaderRefreshing(false);
mRefreshLayout.setFooterRefreshing(false);
showEmptyString();
} else {
// Ui change, show progress bar
mRefreshLayout.setHeaderRefreshing(false);
mRefreshLayout.setFooterRefreshing(false);
showProgressBar();
// Get next page
mCurrentTaskId = mIdGenerator.nextId();
mCurrentTaskType = TYPE_NEXT_PAGE_KEEP_POS;
mCurrentTaskPage = mEndPage;
getPageData(mCurrentTaskId, mCurrentTaskType, mCurrentTaskPage);
}
} else {
mData.clear();
mData.addAll(data);
notifyDataSetChanged();
// Ui change, show content
mRefreshLayout.setHeaderRefreshing(false);
mRefreshLayout.setFooterRefreshing(false);
showContent();
if (mRecyclerView.isAttachedToWindow()) {
// RecyclerView scroll
mRecyclerView.stopScroll();
LayoutManagerUtils.scrollToPositionWithOffset(mRecyclerView.getLayoutManager(), 0, 0);
onScrollToPosition(0);
}
}
break;
case TYPE_REFRESH_PAGE:
if (mCurrentTaskPage < mStartPage || mCurrentTaskPage >= mEndPage) {
Log.e(TAG, "TYPE_REFRESH_PAGE, but mCurrentTaskPage = " + mCurrentTaskPage +
", mStartPage = " + mStartPage + ", mEndPage = " + mEndPage);
break;
}
int oldIndexStart = mCurrentTaskPage == mStartPage ? 0 : mPageDivider.get(mCurrentTaskPage - mStartPage - 1);
int oldIndexEnd = mPageDivider.get(mCurrentTaskPage - mStartPage);
mData.subList(oldIndexStart, oldIndexEnd).clear();
int newIndexStart = oldIndexStart;
int newIndexEnd = newIndexStart + data.size();
mData.addAll(oldIndexStart, data);
notifyDataSetChanged();
for (int i = mCurrentTaskPage - mStartPage, n = mPageDivider.size(); i < n; i++) {
mPageDivider.set(i, mPageDivider.get(i) - oldIndexEnd + newIndexEnd);
}
if (mData.isEmpty()) {
// Ui change, show empty string
mRefreshLayout.setHeaderRefreshing(false);
mRefreshLayout.setFooterRefreshing(false);
showEmptyString();
} else {
// Ui change, show content
mRefreshLayout.setHeaderRefreshing(false);
mRefreshLayout.setFooterRefreshing(false);
showContent();
// RecyclerView scroll
if (newIndexEnd > oldIndexEnd && newIndexEnd > 0 && mRecyclerView.isAttachedToWindow()) {
mRecyclerView.stopScroll();
LayoutManagerUtils.scrollToPositionWithOffset(mRecyclerView.getLayoutManager(), newIndexEnd - 1, 0);
onScrollToPosition(newIndexEnd - 1);
}
}
break;
}
}
}
public void onGetException(int taskId, Exception e) {
if (mCurrentTaskId == taskId) {
mRefreshLayout.setHeaderRefreshing(false);
mRefreshLayout.setFooterRefreshing(false);
String readableError;
if (e != null) {
e.printStackTrace();
readableError = ExceptionUtils.getReadableString(e);
} else {
readableError = getContext().getString(R.string.error_unknown);
}
if (mViewTransition.getShownViewIndex() == 0) {
Toast.makeText(getContext(), readableError, Toast.LENGTH_SHORT).show();
} else {
showText(readableError);
}
}
}
public void showContent() {
mViewTransition.showView(0);
}
private boolean isContentShowing() {
return mViewTransition.getShownViewIndex() == 0;
}
public void showProgressBar() {
showProgressBar(true);
}
public void showProgressBar(boolean animation) {
mViewTransition.showView(1, animation);
}
public void showText(CharSequence text) {
mTipView.setText(text);
mViewTransition.showView(2);
}
public void showEmptyString() {
showText(mEmptyString);
}
/**
* Be carefull
*/
public void doGetData(int type, int page, int refreshType) {
switch (refreshType) {
default:
case REFRESH_TYPE_HEADER:
showContent();
mRefreshLayout.setFooterRefreshing(false);
mRefreshLayout.setHeaderRefreshing(true);
break;
case REFRESH_TYPE_FOOTER:
showContent();
mRefreshLayout.setHeaderRefreshing(false);
mRefreshLayout.setFooterRefreshing(true);
break;
case REFRESH_TYPE_PROGRESS_VIEW:
showProgressBar();
mRefreshLayout.setHeaderRefreshing(false);
mRefreshLayout.setFooterRefreshing(false);
break;
}
mCurrentTaskId = mIdGenerator.nextId();
mCurrentTaskType = type;
mCurrentTaskPage = page;
getPageData(mCurrentTaskId, mCurrentTaskType, mCurrentTaskPage);
}
private void doRefresh() {
mCurrentTaskId = mIdGenerator.nextId();
mCurrentTaskType = TYPE_REFRESH;
mCurrentTaskPage = 0;
getPageData(mCurrentTaskId, mCurrentTaskType, mCurrentTaskPage);
}
/**
* Lisk {@link #refresh()}, but no animation when show progress bar
*/
public void firstRefresh() {
showProgressBar(false);
doRefresh();
}
/**
* Show progress bar first, than do refresh
*/
public void refresh() {
showProgressBar();
doRefresh();
}
private void cancelCurrentTask() {
mCurrentTaskId = mIdGenerator.nextId();
mRefreshLayout.setHeaderRefreshing(false);
mRefreshLayout.setFooterRefreshing(false);
}
private int getPageStart(int page) {
if (mStartPage == page) {
return 0;
} else {
return mPageDivider.get(page - mStartPage - 1);
}
}
private int getPageEnd(int page) {
return mPageDivider.get(page - mStartPage);
}
private int getPageForPosition(int position) {
if (position < 0) {
return -1;
}
IntList pageDivider = mPageDivider;
for (int i = 0, n = pageDivider.size(); i < n; i++) {
if (position < pageDivider.get(i)) {
return i + mStartPage;
}
}
return -1;
}
public int getPageForTop() {
return getPageForPosition(LayoutManagerUtils.getFirstVisibleItemPosition(mRecyclerView.getLayoutManager()));
}
public int getPageForBottom() {
return getPageForPosition(LayoutManagerUtils.getLastVisibleItemPosition(mRecyclerView.getLayoutManager()));
}
public boolean canGoTo() {
return isContentShowing();
}
/**
* Check range first!
*
* @param page the target page
* @throws IndexOutOfBoundsException
*/
public void goTo(int page) throws IndexOutOfBoundsException {
if (page < 0 || page >= mPages) {
throw new IndexOutOfBoundsException("Page count is " + mPages + ", page is " + page);
} else if (page >= mStartPage && page < mEndPage) {
cancelCurrentTask();
int position = getPageStart(page);
mRecyclerView.stopScroll();
LayoutManagerUtils.scrollToPositionWithOffset(mRecyclerView.getLayoutManager(), position, 0);
onScrollToPosition(position);
} else if (page == mStartPage - 1) {
mRefreshLayout.setFooterRefreshing(false);
mRefreshLayout.setHeaderRefreshing(true);
mCurrentTaskId = mIdGenerator.nextId();
mCurrentTaskType = TYPE_PRE_PAGE;
mCurrentTaskPage = page;
getPageData(mCurrentTaskId, mCurrentTaskType, mCurrentTaskPage);
} else if (page == mEndPage) {
mRefreshLayout.setHeaderRefreshing(false);
mRefreshLayout.setFooterRefreshing(true);
mCurrentTaskId = mIdGenerator.nextId();
mCurrentTaskType = TYPE_NEXT_PAGE;
mCurrentTaskPage = page;
getPageData(mCurrentTaskId, mCurrentTaskType, mCurrentTaskPage);
} else {
mRefreshLayout.setFooterRefreshing(false);
mRefreshLayout.setHeaderRefreshing(true);
mCurrentTaskId = mIdGenerator.nextId();
mCurrentTaskType = TYPE_SOMEWHERE;
mCurrentTaskPage = page;
getPageData(mCurrentTaskId, mCurrentTaskType, mCurrentTaskPage);
}
}
private Parcelable saveInstanceState(Parcelable superState) {
Bundle bundle = new Bundle();
bundle.putParcelable(KEY_SUPER, superState);
int shownView = mViewTransition.getShownViewIndex();
bundle.putInt(KEY_SHOWN_VIEW, shownView);
bundle.putString(KEY_TIP, mTipView.getText().toString());
// TODO What if data is large
bundle.putParcelableArrayList(KEY_DATA, mData);
bundle.putInt(KEY_NEXT_ID, mIdGenerator.nextId());
bundle.putParcelable(KEY_PAGE_DIVIDER, mPageDivider);
bundle.putInt(KEY_START_PAGE, mStartPage);
bundle.putInt(KEY_END_PAGE, mEndPage);
bundle.putInt(KEY_PAGES, mPages);
return bundle;
}
private Parcelable restoreInstanceState(Parcelable state) {
if (state instanceof Bundle) {
Bundle bundle = (Bundle) state;
mViewTransition.showView(bundle.getInt(KEY_SHOWN_VIEW), false);
mTipView.setText(bundle.getString(KEY_TIP));
mData = bundle.getParcelableArrayList(KEY_DATA);
mIdGenerator.setNextId(bundle.getInt(KEY_NEXT_ID));
mPageDivider = bundle.getParcelable(KEY_PAGE_DIVIDER);
mStartPage = bundle.getInt(KEY_START_PAGE);
mEndPage = bundle.getInt(KEY_END_PAGE);
mPages = bundle.getInt(KEY_PAGES);
return bundle.getParcelable(KEY_SUPER);
} else {
return state;
}
}
}
}