package com.bourke.finch;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;
import android.widget.RelativeLayout;
import com.actionbarsherlock.app.SherlockFragment;
import com.actionbarsherlock.view.ActionMode;
import com.actionbarsherlock.view.MenuItem;
import com.bourke.finch.common.FinchTwitterFactory;
import com.bourke.finch.common.TwitterTask;
import com.bourke.finch.common.TwitterTaskCallback;
import com.bourke.finch.common.TwitterTaskParams;
import com.bourke.finch.lazylist.LazyAdapter;
import java.util.ArrayList;
import java.util.List;
import twitter4j.auth.AccessToken;
import twitter4j.Paging;
import twitter4j.ResponseList;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import twitter4j.TwitterResponse;
public abstract class BaseTimelineFragment extends SherlockFragment
implements OnScrollListener {
protected String TAG = "Finch/BaseTimelineFragment";
protected ListView mMainList;
protected LazyAdapter mMainListAdapter;
protected Twitter mTwitter;
protected AccessToken mAccessToken;
protected ActionMode mMode;
protected Context mContext;
protected boolean mLoadingPage = false;
protected int mUnreadCount = 0;
private int mNewestUnreadIndex = 0;
private int mTwitterTaskType;
private MainActivity mActivity;
/* Update the unread display on scrolling every X items */
private static final int UPDATE_UNREAD_COUNT_INTERVAL = 3;
private static final int FETCH_LIMIT = 20;
private List<TwitterResponse> mTimelineGap =
new ArrayList<TwitterResponse>();
public BaseTimelineFragment(int twitterTaskType) {
mTwitterTaskType = twitterTaskType;
switch (mTwitterTaskType) {
case TwitterTask.GET_HOME_TIMELINE:
TAG = "Finch/HomeTimelineFragment";
break;
case TwitterTask.GET_MENTIONS:
TAG = "Finch/ConnectionsTimelineFragment";
break;
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate()");
setHasOptionsMenu(true);
mActivity = (MainActivity)getSherlockActivity();
mContext = mActivity.getApplicationContext();
mTwitter = FinchTwitterFactory.getInstance(mContext).getTwitter();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Log.d(TAG, "onCreateView()");
RelativeLayout layout = (RelativeLayout)inflater
.inflate(R.layout.standard_list_fragment, container, false);
initMainList(layout);
return layout;
}
@Override
public void onScroll(AbsListView view, int firstVisible, int visibleCount,
int totalCount) {
if (totalCount <= 0 || mLoadingPage) {
return;
}
if (firstVisible <= mNewestUnreadIndex) {
mNewestUnreadIndex = firstVisible;
if (mNewestUnreadIndex % UPDATE_UNREAD_COUNT_INTERVAL == 0 ||
mNewestUnreadIndex == 0) {
mUnreadCount = mNewestUnreadIndex;
mActivity.updateUnreadDisplay();
}
}
boolean loadMore = firstVisible + visibleCount >= totalCount;
if (loadMore) {
mLoadingPage = true;
loadNextPage();
}
}
@Override
public void onScrollStateChanged(AbsListView v, int scrollState) {
if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) {
//Log.i("a", "scrolling stopped...");
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_compose:
mActivity.showDialog();
return true;
case R.id.menu_refresh:
refresh();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
protected void refresh() {
Log.d(TAG, "refresh()");
final Paging page = new Paging();
page.setCount(FETCH_LIMIT);
final List<TwitterResponse> currentList = mMainListAdapter
.getResponses();
final int currentPosition = mMainList.getFirstVisiblePosition();
mTimelineGap.clear();
if (currentList != null && !currentList.isEmpty()) {
Log.d(TAG, "current response list size = " + currentList.size());
page.setSinceId(((Status)currentList.get(0)).getId());
final TwitterTaskCallback taskCallback = new TwitterTaskCallback
<TwitterTaskParams, TwitterException>() {
public void onSuccess(TwitterTaskParams payload) {
ResponseList res = (ResponseList)payload.result;
/* If we have made a request with maxId set, we need to
* drop the first response as maxId is inclusive */
if (page.getMaxId() > -1) {
Log.d(TAG, "maxId set, dropping first response");
res.remove(0);
}
if (res.size() > 0) {
Log.d(TAG, "fetched " + res.size() + " responses, " +
"appending to timeline gap list");
mTimelineGap.addAll(res);
page.setMaxId(((Status)mTimelineGap.get(
mTimelineGap.size()-1)).getId());
Log.d(TAG, "Issuing GET with sinceId=" +
page.getSinceId() + ", maxId=" +
page.getMaxId());
// TODO: Add some sort of limit here to prevent getting
// rate limited if there's a *lot* to fetch. Also test
// what happens when we are rate limited
TwitterTaskParams taskParams = new TwitterTaskParams(
mTwitterTaskType, new Object[] {mActivity,
mMainListAdapter, mMainList, page});
new TwitterTask(taskParams, this, mTwitter).execute();
} else {
Log.d(TAG, "fetched " + res.size() + " responses, " +
"prepending timeline gap list to adapter");
mMainListAdapter.prependResponses(mTimelineGap);
mMainListAdapter.notifyDataSetChanged();
int newListSize = mMainListAdapter.getResponses()
.size();
int newScrollPosition = (newListSize -
currentList.size()) + currentPosition;
mMainList.setSelection(newScrollPosition);
/* Update unread count display */
mNewestUnreadIndex = mTimelineGap.size()-1;
mUnreadCount += mTimelineGap.size();
mActivity.updateUnreadDisplay();
}
}
public void onFailure(TwitterException e) {
e.printStackTrace();
}
};
Log.d(TAG, "Issuing GET with sinceId=" +
page.getSinceId() + ", maxId=" +
page.getMaxId());
TwitterTaskParams taskParams = new TwitterTaskParams(
mTwitterTaskType, new Object[] {mActivity,
mMainListAdapter, mMainList, page});
new TwitterTask(taskParams, taskCallback, mTwitter).execute();
} else {
Log.d(TAG, "currentList null or empty");
/* Fetch first N tweets and add to list */
TwitterTaskCallback taskCallback = new TwitterTaskCallback
<TwitterTaskParams, TwitterException>() {
public void onSuccess(TwitterTaskParams payload) {
ResponseList res = (ResponseList)payload.result;
if (res.size() == 0) {
Log.d(TAG, "res.size() == 0, no action");
return;
}
/* Update list */
Log.d(TAG, "fetched " + res.size() + " responses, " +
"appending to adapter");
mMainListAdapter.appendResponses((ResponseList)res);
mMainListAdapter.notifyDataSetChanged();
/* Update unread count display */
mUnreadCount += res.size();
mActivity.updateUnreadDisplay();
}
public void onFailure(TwitterException e) {
e.printStackTrace();
}
};
Log.d(TAG, "Issuing GET with sinceId=" +
page.getSinceId() + ", maxId=" +
page.getMaxId());
TwitterTaskParams taskParams = new TwitterTaskParams(
mTwitterTaskType, new Object[] {mActivity,
mMainListAdapter, mMainList, page});
new TwitterTask(taskParams, taskCallback, mTwitter).execute();
}
}
protected void loadNextPage() {
Log.d(TAG, "loadNextPage");
List<TwitterResponse> currentList = mMainListAdapter.getResponses();
if (currentList.isEmpty()) {
Log.e(TAG, "mMainListAdapter.getResponses() is empty");
return;
}
TwitterTaskCallback taskCallback = new TwitterTaskCallback
<TwitterTaskParams, TwitterException>() {
public void onSuccess(TwitterTaskParams payload) {
ResponseList res =
(ResponseList)payload.result;
if (res.size()-1 == 0) { // -1 as maxId is inclusive
Log.d(TAG, "res.size()-1 == 0, no action");
return;
}
res.remove(0); // Avoid overlap with maxId
mMainListAdapter.appendResponses(res);
mMainListAdapter.notifyDataSetChanged();
mLoadingPage = false;
}
public void onFailure(TwitterException e) {
e.printStackTrace();
}
};
Paging paging = new Paging();
paging.setCount(FETCH_LIMIT);
long maxId = ((Status)currentList.get(currentList.size()-1)).getId();
paging.setMaxId(maxId);
TwitterTaskParams taskParams = new TwitterTaskParams(mTwitterTaskType,
new Object[] {mActivity, mMainListAdapter, mMainList, paging});
new TwitterTask(taskParams, taskCallback, mTwitter).execute();
}
private void initMainList(ViewGroup layout) {
mMainList = (ListView)layout.findViewById(R.id.list);
mMainListAdapter = new LazyAdapter(mActivity);
mMainList.setAdapter(mMainListAdapter);
mMainList.setOnScrollListener(this);
setupActionMode();
}
public int getUnreadCount() {
return mUnreadCount;
}
public abstract void setupActionMode();
}