package cheng.app.cnbeta;
import java.lang.ref.WeakReference;
import cheng.app.cnbeta.data.CBContract.HmColumns;
import cheng.app.cnbeta.data.CBContract.NewsColumns;
import cheng.app.cnbeta.lib.EndlessAdapter;
import cheng.app.cnbeta.util.Configs;
import cheng.app.cnbeta.util.HttpUtil;
import cheng.app.cnbeta.util.DataUtil;
import cheng.app.cnbeta.util.Utils;
import uk.co.senab.actionbarpulltorefresh.extras.actionbarcompat.PullToRefreshLayout;
import uk.co.senab.actionbarpulltorefresh.library.ActionBarPullToRefresh;
import uk.co.senab.actionbarpulltorefresh.library.listeners.OnRefreshListener;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ListView;
/**
* A list fragment representing a list of Pages. This fragment
* also supports tablet devices by allowing list items to be given an
* 'activated' state upon selection. This helps indicate which item is
* currently being viewed in a {@link PageDetailFragment}.
* <p>
* Activities containing this fragment MUST implement the {@link Callbacks}
* interface.
*/
public class PageListFragment extends ListFragment implements
LoaderManager.LoaderCallbacks<Cursor>, OnRefreshListener {
private static final String TAG = "PageListFragment";
private static final String STATE_LAST_ITEM_ID = "last_item_id";
/**
* The fragment's current callback object, which is notified of list item
* clicks.
*/
private Callbacks mCallbacks = sDummyCallbacks;
/**
* The current activated item position. Only used on tablets.
*/
public static final int PAGE_NEWS = 0;
public static final int PAGE_HM = 1;
//private int mActivatedPosition = ListView.INVALID_POSITION;
private boolean mIsReCreated = false;
private boolean mIsLoading = false;
public static final String ARG_PAGE = "page";
public static final String ARG_LAST_ID = "last_id";
AutoLoadAdapter mAdapter;
private PullToRefreshLayout mPullToRefreshLayout;
private Menu mOptionsMenu;
private int mPageId;
private long mLastItemId = -1;
/**
* A callback interface that all activities containing this fragment must
* implement. This mechanism allows activities to be notified of item
* selections.
*/
public interface Callbacks {
/**
* Callback for when an item has been selected.
*/
public void onItemSelected(int pageId, long id);
}
/**
* A dummy implementation of the {@link Callbacks} interface that does
* nothing. Used only when this fragment is not attached to an activity.
*/
private static Callbacks sDummyCallbacks = new Callbacks() {
@Override
public void onItemSelected(int pageId, long id) {
}
};
/**
* Mandatory empty constructor for the fragment manager to instantiate the
* fragment (e.g. upon screen orientation changes).
*/
public PageListFragment() {
}
public int getPageId() {
return mPageId;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mIsReCreated = savedInstanceState != null;
setHasOptionsMenu(true);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (getArguments().containsKey(ARG_PAGE)) {
mPageId = getArguments().getInt(ARG_PAGE, PAGE_NEWS);
}
// Restore the previously serialized activated item position.
if (savedInstanceState != null) {
if(savedInstanceState.containsKey(STATE_LAST_ITEM_ID)) {
mLastItemId = savedInstanceState.getLong(STATE_LAST_ITEM_ID);
}
}
mAdapter = new AutoLoadAdapter(getActivity(), new PageListAdapter(getActivity(), mPageId));
mAdapter.setRunInBackground(false);
setListAdapter(mAdapter);
// Start out with a progress indicator.
setListShown(false);
if (mIsReCreated) {
mIsLoading = true;
Bundle args = new Bundle();
args.putLong(ARG_LAST_ID, mLastItemId);
getLoaderManager().restartLoader(mPageId, args, this);
} else {
refresh(-1);
}
}
@Override
public void onResume() {
super.onResume();
mAdapter.setFontSize();
}
void refresh(long lastId) {
if (!mIsLoading) {
Log.d(TAG, "[" + mPageId + "]start refresh from net, lastId=" + lastId);
new PageListAsyncTask(this).execute(lastId);
} else {
Log.e(TAG, "[" + mPageId + "]already in loading!");
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d(TAG, "onCreateView of " + this);
View v = super.onCreateView(inflater, container, savedInstanceState);
View layout = (FrameLayout) inflater.inflate(R.layout.list_container, null);
FrameLayout root = (FrameLayout) layout.findViewById(R.id.main_frame);
root.addView(v);
return layout;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mPullToRefreshLayout = (PullToRefreshLayout) view.findViewById(R.id.ptr_layout);
ActionBarPullToRefresh.from(getActivity())
// Mark All Children as pullable
.allChildrenArePullable()
// Set the OnRefreshListener
.listener(this)
// Finally commit the setup to our PullToRefreshLayout
.setup(mPullToRefreshLayout);
ListView lv = getListView();
lv.setDrawSelectorOnTop(true);
lv.setDivider(view.getResources().getDrawable(android.R.color.transparent));
lv.setDividerHeight(view.getResources().getDimensionPixelSize(R.dimen.multipane_padding));
Log.d(TAG, "onViewCreated of " + this);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
//inflater.inflate(R.menu.main_refresh_action, menu);
mOptionsMenu = menu;
triggerRefresh(mIsLoading);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_refresh:
refresh(-1L);
return true;
}
return false;
}
private void triggerRefresh(boolean refreshing) {
if (mOptionsMenu == null) {
return;
}
final MenuItem refreshItem = mOptionsMenu.findItem(R.id.action_refresh);
if (refreshItem != null) {
if (refreshing) {
refreshItem.setActionView(R.layout.actionbar_indeterminate_progress);
} else {
refreshItem.setActionView(null);
}
}
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Activities containing this fragment must implement its callbacks.
if (!(activity instanceof Callbacks)) {
throw new IllegalStateException("Activity must implement fragment's callbacks.");
}
mCallbacks = (Callbacks) activity;
}
@Override
public void onDetach() {
super.onDetach();
// Reset the active callbacks interface to the dummy implementation.
mCallbacks = sDummyCallbacks;
}
@Override
public void onRefreshStarted(View view) {
refresh(-1L);
}
@Override
public void onListItemClick(ListView listView, View view, int position, long id) {
Cursor c = (Cursor) mAdapter.getItem(position);
long itemId = -1;
if (mPageId == PAGE_HM) {
itemId = c.getLong(c.getColumnIndex(HmColumns.HMID));
} else {
itemId = c.getLong(c.getColumnIndex(NewsColumns.ARTICLE_ID));
}
mCallbacks.onItemSelected(mPageId, itemId);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putLong(STATE_LAST_ITEM_ID, mLastItemId);
}
@Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
long lastId = -1;
if (arg1 != null) {
if (arg1.containsKey(ARG_LAST_ID))
lastId = arg1.getLong(ARG_LAST_ID);
}
Log.d(TAG, "[" + arg0 + "]onCreateLoader, lastId=" + lastId);
PageListLoader cl = new PageListLoader(getActivity(), arg0, lastId);
cl.setUpdateThrottle(2000); // update at most every 2 seconds.
return cl;
}
@Override
public void onLoadFinished(Loader<Cursor> arg0, Cursor arg1) {
mAdapter.changeData(arg1);
if (arg1 != null && arg1.moveToLast()) {
if (mPageId == PAGE_HM)
mLastItemId = arg1.getLong(arg1.getColumnIndex(HmColumns.HMID));
else
mLastItemId = arg1.getLong(arg1.getColumnIndex(NewsColumns.ARTICLE_ID));
Log.d(TAG, "[" + mPageId + "]onLoadFinished, mLastItemId=" + mLastItemId);
}
// The list should now be shown.
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
mIsLoading = false;
triggerRefresh(false);
mPullToRefreshLayout.setRefreshComplete();
}
@Override
public void onLoaderReset(Loader<Cursor> arg0) {
mAdapter.changeData(null);
}
private static class PageListAsyncTask extends AsyncTask<Long, Void, Long> {
private WeakReference<PageListFragment> mFragment;
private ContentResolver mCr;
private long mLastId;//this is the last item of the list
@Override
protected void onPreExecute() {
final PageListFragment fragment = mFragment.get();
if (fragment != null) {
fragment.mIsLoading = true;
fragment.triggerRefresh(true);
}
}
public PageListAsyncTask(PageListFragment fragment) {
mFragment = new WeakReference<PageListFragment>(fragment);
mCr = fragment.getActivity().getContentResolver();
}
@Override
protected Long doInBackground(Long... params) {
final PageListFragment fragment = mFragment.get();
mLastId = params[0];
if (fragment != null) {
int pageId = fragment.getPageId();
if (pageId == PAGE_HM) {
return loadHM(mLastId);
} else {
return loadNewsList(mLastId);
}
} else {
return -1L;
}
}
private long loadNewsList(long lastId) {
String url = Configs.NEWSLIST_URL + Configs.LIMIT;
if (lastId > 0) {
url += (Configs.NEWSLIST_PAGE + lastId);
}
String html = HttpUtil.getInstance().httpGet(url);
return DataUtil.parseAndSaveNewsList(html, mCr);
}
private long loadHM(long lastId) {
String url = Configs.HMCOMMENT_URL + Configs.LIMIT;
if (lastId > 0) {
url += (Configs.HMCOMMENT_PAGE + lastId);
}
String html = HttpUtil.getInstance().httpGet(url);
return DataUtil.parseAndSaveHotComments(html, mCr);
}
@Override
protected void onPostExecute(Long result) {
final PageListFragment fragment = mFragment.get();
if (fragment != null && fragment.isResumed()) {
Log.d(TAG, "[" + fragment.getPageId() + "]onPostExecute, last saved id is " + result);
// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
Bundle args = new Bundle();
args.putLong(ARG_LAST_ID, result);
fragment.getLoaderManager().restartLoader(fragment.mPageId, args, fragment);
}
}
}
class AutoLoadAdapter extends EndlessAdapter {
Context mContext;
PageListAdapter mAdapter;
public AutoLoadAdapter(Context c, PageListAdapter wrapped) {
super(wrapped);
mContext = c;
mAdapter = wrapped;
}
@Override
protected View getPendingView(ViewGroup parent) {
LayoutInflater inflater = LayoutInflater.from(mContext);
View v = inflater.inflate(R.layout.list_loading_layout, null);
return v;
}
@Override
protected boolean cacheInBackground() throws Exception {
Log.i(TAG, "start cacheInBackground");
refresh(mLastItemId);
return true;
}
@Override
protected void appendCachedData() {
// TODO Auto-generated method stub
}
public void changeData(Cursor c) {
mAdapter.swapCursor(c);
onDataReady();
}
public void setFontSize() {
String textSize = Utils.getSharedPreferences(getActivity(), Utils.PREFERENCE_FONT_SIZE,
Utils.PREFERENCE_FONT_SIZE_DEFAULT);
mAdapter.setFontSize(Integer.parseInt(textSize));
}
@Override
public Object getItem(int position) {
return mAdapter.getItem(position);
}
}
}