Add infinite scroll for feed item list and social feed item list.

This commit is contained in:
RyanBateman 2012-08-10 11:59:02 -04:00
parent 64166b6dfe
commit 72a50217e5
12 changed files with 169 additions and 53 deletions

View file

@ -46,10 +46,18 @@ public class FeedItemsList extends ItemsList {
@Override @Override
public void triggerRefresh() { public void triggerRefresh() {
triggerRefresh(0);
}
@Override
public void triggerRefresh(int page) {
setSupportProgressBarIndeterminateVisibility(true); setSupportProgressBarIndeterminateVisibility(true);
final Intent intent = new Intent(Intent.ACTION_SYNC, null, this, SyncService.class); final Intent intent = new Intent(Intent.ACTION_SYNC, null, this, SyncService.class);
intent.putExtra(SyncService.EXTRA_STATUS_RECEIVER, syncFragment.receiver); intent.putExtra(SyncService.EXTRA_STATUS_RECEIVER, syncFragment.receiver);
intent.putExtra(SyncService.SYNCSERVICE_TASK, SyncService.EXTRA_TASK_FEED_UPDATE); intent.putExtra(SyncService.SYNCSERVICE_TASK, SyncService.EXTRA_TASK_FEED_UPDATE);
if (page > 1) {
intent.putExtra(SyncService.EXTRA_TASK_PAGE_NUMBER, Integer.toString(page));
}
intent.putExtra(SyncService.EXTRA_TASK_FEED_ID, feedId); intent.putExtra(SyncService.EXTRA_TASK_FEED_ID, feedId);
startService(intent); startService(intent);
} }

View file

@ -24,7 +24,7 @@ public class FeedReading extends Reading {
super.onCreate(savedInstanceBundle); super.onCreate(savedInstanceBundle);
feedId = getIntent().getStringExtra(Reading.EXTRA_FEED); feedId = getIntent().getStringExtra(Reading.EXTRA_FEED);
Uri storiesURI = FeedProvider.STORIES_URI.buildUpon().appendPath(feedId).build(); Uri storiesURI = FeedProvider.FEED_STORIES_URI.buildUpon().appendPath(feedId).build();
stories = contentResolver.query(storiesURI, null, FeedProvider.getSelectionFromState(currentState), null, null); stories = contentResolver.query(storiesURI, null, FeedProvider.getSelectionFromState(currentState), null, null);

View file

@ -54,6 +54,7 @@ public abstract class ItemsList extends SherlockFragmentActivity implements Sync
} }
public abstract void triggerRefresh(); public abstract void triggerRefresh();
public abstract void triggerRefresh(int page);
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {

View file

@ -44,14 +44,22 @@ public class SocialFeedItemsList extends ItemsList {
triggerRefresh(); triggerRefresh();
} }
} }
@Override @Override
public void triggerRefresh() { public void triggerRefresh() {
triggerRefresh(0);
}
@Override
public void triggerRefresh(int page) {
setSupportProgressBarIndeterminateVisibility(true); setSupportProgressBarIndeterminateVisibility(true);
final Intent intent = new Intent(Intent.ACTION_SYNC, null, this, SyncService.class); final Intent intent = new Intent(Intent.ACTION_SYNC, null, this, SyncService.class);
intent.putExtra(SyncService.EXTRA_STATUS_RECEIVER, syncFragment.receiver); intent.putExtra(SyncService.EXTRA_STATUS_RECEIVER, syncFragment.receiver);
intent.putExtra(SyncService.SYNCSERVICE_TASK, SyncService.EXTRA_TASK_SOCIALFEED_UPDATE); intent.putExtra(SyncService.SYNCSERVICE_TASK, SyncService.EXTRA_TASK_SOCIALFEED_UPDATE);
intent.putExtra(SyncService.EXTRA_TASK_SOCIALFEED_ID, userId); intent.putExtra(SyncService.EXTRA_TASK_SOCIALFEED_ID, userId);
if (page > 1) {
intent.putExtra(SyncService.EXTRA_TASK_PAGE_NUMBER, Integer.toString(page));
}
intent.putExtra(SyncService.EXTRA_TASK_SOCIALFEED_USERNAME, username); intent.putExtra(SyncService.EXTRA_TASK_SOCIALFEED_USERNAME, username);
startService(intent); startService(intent);
} }

View file

@ -24,7 +24,7 @@ public class SocialFeedReading extends Reading {
String userId = getIntent().getStringExtra(Reading.EXTRA_USERID); String userId = getIntent().getStringExtra(Reading.EXTRA_USERID);
Uri storiesURI = FeedProvider.SOCIAL_FEEDS_URI.buildUpon().appendPath(userId).build(); Uri storiesURI = FeedProvider.SOCIALFEED_STORIES_URI.buildUpon().appendPath(userId).build();
stories = contentResolver.query(storiesURI, null, FeedProvider.getSelectionFromState(currentState), null, null); stories = contentResolver.query(storiesURI, null, FeedProvider.getSelectionFromState(currentState), null, null);
setTitle(getIntent().getStringExtra(EXTRA_USERNAME)); setTitle(getIntent().getStringExtra(EXTRA_USERNAME));
setupPager(stories); setupPager(stories);

View file

@ -24,7 +24,8 @@ public class FeedProvider extends ContentProvider {
public static final Uri FEEDS_URI = Uri.parse("content://" + AUTHORITY + "/" + VERSION + "/feeds/"); public static final Uri FEEDS_URI = Uri.parse("content://" + AUTHORITY + "/" + VERSION + "/feeds/");
public static final Uri MODIFY_COUNT_URI = Uri.parse("content://" + AUTHORITY + "/" + VERSION + "/feedcount/"); public static final Uri MODIFY_COUNT_URI = Uri.parse("content://" + AUTHORITY + "/" + VERSION + "/feedcount/");
public static final Uri MODIFY_SOCIALCOUNT_URI = Uri.parse("content://" + AUTHORITY + "/" + VERSION + "/socialfeedcount/"); public static final Uri MODIFY_SOCIALCOUNT_URI = Uri.parse("content://" + AUTHORITY + "/" + VERSION + "/socialfeedcount/");
public static final Uri STORIES_URI = Uri.parse("content://" + AUTHORITY + "/" + VERSION + "/stories/"); public static final Uri FEED_STORIES_URI = Uri.parse("content://" + AUTHORITY + "/" + VERSION + "/stories/feed/");
public static final Uri SOCIALFEED_STORIES_URI = Uri.parse("content://" + AUTHORITY + "/" + VERSION + "/stories/socialfeed/");
public static final Uri STORY_URI = Uri.parse("content://" + AUTHORITY + "/" + VERSION + "/story/"); public static final Uri STORY_URI = Uri.parse("content://" + AUTHORITY + "/" + VERSION + "/story/");
public static final Uri COMMENTS_URI = Uri.parse("content://" + AUTHORITY + "/" + VERSION + "/comments/"); public static final Uri COMMENTS_URI = Uri.parse("content://" + AUTHORITY + "/" + VERSION + "/comments/");
public static final Uri FEED_FOLDER_MAP_URI = Uri.parse("content://" + AUTHORITY + "/" + VERSION + "/feedfoldermap/"); public static final Uri FEED_FOLDER_MAP_URI = Uri.parse("content://" + AUTHORITY + "/" + VERSION + "/feedfoldermap/");
@ -37,27 +38,30 @@ public class FeedProvider extends ContentProvider {
private static final int INDIVIDUAL_FOLDER = 4; private static final int INDIVIDUAL_FOLDER = 4;
private static final int FEED_FOLDER_MAP = 5; private static final int FEED_FOLDER_MAP = 5;
private static final int SPECIFIC_FEED_FOLDER_MAP = 6; private static final int SPECIFIC_FEED_FOLDER_MAP = 6;
private static final int INDIVIDUAL_SOCIALFEED = 7; private static final int SOCIALFEED_STORIES = 7;
private static final int INDIVIDUAL_FEED = 8; private static final int INDIVIDUAL_FEED = 8;
private static final int STORY_COMMENTS = 9; private static final int STORY_COMMENTS = 9;
private static final int INDIVIDUAL_STORY = 10; private static final int INDIVIDUAL_STORY = 10;
private static final int DECREMENT_FEED_COUNT = 11; private static final int DECREMENT_FEED_COUNT = 11;
private static final int OFFLINE_UPDATES = 12; private static final int OFFLINE_UPDATES = 12;
private static final int DECREMENT_SOCIALFEED_COUNT = 13; private static final int DECREMENT_SOCIALFEED_COUNT = 13;
private static final int INDIVIDUAL_SOCIAL_FEED = 14;
private BlurDatabase databaseHelper; private BlurDatabase databaseHelper;
private static UriMatcher uriMatcher; private static UriMatcher uriMatcher;
static { static {
// TODO: Tidy this url-structure. It's not forward-facing but it's kind of a mess.
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AUTHORITY, VERSION + "/feeds/", ALL_FEEDS); uriMatcher.addURI(AUTHORITY, VERSION + "/feeds/", ALL_FEEDS);
uriMatcher.addURI(AUTHORITY, VERSION + "/social_feeds/", ALL_SOCIAL_FEEDS); uriMatcher.addURI(AUTHORITY, VERSION + "/social_feeds/", ALL_SOCIAL_FEEDS);
uriMatcher.addURI(AUTHORITY, VERSION + "/social_feeds/#/", INDIVIDUAL_SOCIALFEED); uriMatcher.addURI(AUTHORITY, VERSION + "/social_feeds/#/", INDIVIDUAL_SOCIAL_FEED);
uriMatcher.addURI(AUTHORITY, VERSION + "/feeds/*/", INDIVIDUAL_FEED); uriMatcher.addURI(AUTHORITY, VERSION + "/feeds/*/", INDIVIDUAL_FEED);
uriMatcher.addURI(AUTHORITY, VERSION + "/feedcount/", DECREMENT_FEED_COUNT); uriMatcher.addURI(AUTHORITY, VERSION + "/feedcount/", DECREMENT_FEED_COUNT);
uriMatcher.addURI(AUTHORITY, VERSION + "/socialfeedcount/", DECREMENT_SOCIALFEED_COUNT); uriMatcher.addURI(AUTHORITY, VERSION + "/socialfeedcount/", DECREMENT_SOCIALFEED_COUNT);
uriMatcher.addURI(AUTHORITY, VERSION + "/feed/*/", INDIVIDUAL_FEED); uriMatcher.addURI(AUTHORITY, VERSION + "/feed/*/", INDIVIDUAL_FEED);
uriMatcher.addURI(AUTHORITY, VERSION + "/stories/#/", FEED_STORIES); uriMatcher.addURI(AUTHORITY, VERSION + "/stories/socialfeed/#/", SOCIALFEED_STORIES);
uriMatcher.addURI(AUTHORITY, VERSION + "/stories/feed/#/", FEED_STORIES);
uriMatcher.addURI(AUTHORITY, VERSION + "/story/*/", INDIVIDUAL_STORY); uriMatcher.addURI(AUTHORITY, VERSION + "/story/*/", INDIVIDUAL_STORY);
uriMatcher.addURI(AUTHORITY, VERSION + "/comments/", STORY_COMMENTS); uriMatcher.addURI(AUTHORITY, VERSION + "/comments/", STORY_COMMENTS);
uriMatcher.addURI(AUTHORITY, VERSION + "/feedfoldermap/", FEED_FOLDER_MAP); uriMatcher.addURI(AUTHORITY, VERSION + "/feedfoldermap/", FEED_FOLDER_MAP);
@ -126,7 +130,7 @@ public class FeedProvider extends ContentProvider {
break; break;
// Inserting a story for a social feed // Inserting a story for a social feed
case INDIVIDUAL_SOCIALFEED: case SOCIALFEED_STORIES:
db.beginTransaction(); db.beginTransaction();
final ContentValues socialMapValues = new ContentValues(); final ContentValues socialMapValues = new ContentValues();
socialMapValues.put(DatabaseConstants.SOCIALFEED_STORY_USER_ID, uri.getLastPathSegment()); socialMapValues.put(DatabaseConstants.SOCIALFEED_STORY_USER_ID, uri.getLastPathSegment());
@ -265,8 +269,10 @@ public class FeedProvider extends ContentProvider {
case OFFLINE_UPDATES: case OFFLINE_UPDATES:
return db.query(DatabaseConstants.UPDATE_TABLE, null, null, null, null, null, null); return db.query(DatabaseConstants.UPDATE_TABLE, null, null, null, null, null, null);
case ALL_SOCIAL_FEEDS: case ALL_SOCIAL_FEEDS:
return db.query(DatabaseConstants.SOCIALFEED_TABLE, null, selection, null, null, null, null); return db.query(DatabaseConstants.SOCIALFEED_TABLE, null, selection, null, null, null, null);
case INDIVIDUAL_SOCIALFEED: case INDIVIDUAL_SOCIAL_FEED:
return db.query(DatabaseConstants.SOCIALFEED_TABLE, null, DatabaseConstants.SOCIAL_FEED_ID + " = ?", new String[] { uri.getLastPathSegment() }, null, null, null);
case SOCIALFEED_STORIES:
String[] userArgument = new String[] { uri.getLastPathSegment() }; String[] userArgument = new String[] { uri.getLastPathSegment() };
String userQuery = "SELECT " + TextUtils.join(",", DatabaseConstants.STORY_COLUMNS) + ", " + DatabaseConstants.FEED_TITLE + ", " + String userQuery = "SELECT " + TextUtils.join(",", DatabaseConstants.STORY_COLUMNS) + ", " + DatabaseConstants.FEED_TITLE + ", " +
@ -299,7 +305,7 @@ public class FeedProvider extends ContentProvider {
switch (uriMatcher.match(uri)) { switch (uriMatcher.match(uri)) {
case INDIVIDUAL_FEED: case INDIVIDUAL_FEED:
return db.update(DatabaseConstants.FEED_TABLE, values, DatabaseConstants.FEED_ID + " = ?", new String[] { uri.getLastPathSegment() }); return db.update(DatabaseConstants.FEED_TABLE, values, DatabaseConstants.FEED_ID + " = ?", new String[] { uri.getLastPathSegment() });
case INDIVIDUAL_SOCIALFEED: case SOCIALFEED_STORIES:
return db.update(DatabaseConstants.SOCIALFEED_TABLE, values, DatabaseConstants.FEED_ID + " = ?", new String[] { uri.getLastPathSegment() }); return db.update(DatabaseConstants.SOCIALFEED_TABLE, values, DatabaseConstants.FEED_ID + " = ?", new String[] { uri.getLastPathSegment() });
case INDIVIDUAL_STORY: case INDIVIDUAL_STORY:
return db.update(DatabaseConstants.STORY_TABLE, values, DatabaseConstants.STORY_ID + " = ?", new String[] { uri.getLastPathSegment() }); return db.update(DatabaseConstants.STORY_TABLE, values, DatabaseConstants.STORY_ID + " = ?", new String[] { uri.getLastPathSegment() });

View file

@ -36,7 +36,8 @@ public class SocialFeed {
return values; return values;
} }
public SocialFeed fromCursor(final Cursor cursor) { public static SocialFeed fromCursor(final Cursor cursor) {
cursor.moveToFirst();
SocialFeed socialFeed = new SocialFeed(); SocialFeed socialFeed = new SocialFeed();
socialFeed.userId = cursor.getString(cursor.getColumnIndex(DatabaseConstants.SOCIAL_FEED_ID)); socialFeed.userId = cursor.getString(cursor.getColumnIndex(DatabaseConstants.SOCIAL_FEED_ID));
socialFeed.username = cursor.getString(cursor.getColumnIndex(DatabaseConstants.SOCIAL_FEED_USERNAME)); socialFeed.username = cursor.getString(cursor.getColumnIndex(DatabaseConstants.SOCIAL_FEED_USERNAME));

View file

@ -14,6 +14,8 @@ import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView; import android.widget.ListView;
@ -24,10 +26,12 @@ import com.newsblur.activity.ItemsList;
import com.newsblur.activity.Reading; import com.newsblur.activity.Reading;
import com.newsblur.database.DatabaseConstants; import com.newsblur.database.DatabaseConstants;
import com.newsblur.database.FeedProvider; import com.newsblur.database.FeedProvider;
import com.newsblur.domain.Feed;
import com.newsblur.util.AppConstants;
import com.newsblur.view.ItemViewBinder; import com.newsblur.view.ItemViewBinder;
public class FeedItemListFragment extends ItemListFragment implements LoaderManager.LoaderCallbacks<Cursor>, OnItemClickListener { public class FeedItemListFragment extends ItemListFragment implements LoaderManager.LoaderCallbacks<Cursor>, OnItemClickListener, OnScrollListener {
private static final String TAG = "itemListFragment"; private static final String TAG = "itemListFragment";
public static final String FRAGMENT_TAG = "itemListFragment"; public static final String FRAGMENT_TAG = "itemListFragment";
private ContentResolver contentResolver; private ContentResolver contentResolver;
@ -35,56 +39,64 @@ public class FeedItemListFragment extends ItemListFragment implements LoaderMana
private SimpleCursorAdapter adapter; private SimpleCursorAdapter adapter;
private Uri storiesUri; private Uri storiesUri;
private int currentState; private int currentState;
private int currentPage = 1;
private boolean requestedPage = false;
public static int ITEMLIST_LOADER = 0x01; public static int ITEMLIST_LOADER = 0x01;
private int READING_RETURNED = 0x02; private int READING_RETURNED = 0x02;
private Feed feed;
public FeedItemListFragment(final String feedId, final int currentState) { public FeedItemListFragment(final String feedId, final int currentState) {
this.feedId = feedId; this.feedId = feedId;
this.currentState = currentState; this.currentState = currentState;
} }
public FeedItemListFragment() { public FeedItemListFragment() {
} }
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
} }
public static FeedItemListFragment newInstance(final String feedId, int currentState) { public static FeedItemListFragment newInstance(final String feedId, int currentState) {
return new FeedItemListFragment(feedId, currentState); return new FeedItemListFragment(feedId, currentState);
} }
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_itemlist, null); View v = inflater.inflate(R.layout.fragment_itemlist, null);
ListView itemList = (ListView) v.findViewById(R.id.itemlistfragment_list); ListView itemList = (ListView) v.findViewById(R.id.itemlistfragment_list);
contentResolver = getActivity().getContentResolver(); contentResolver = getActivity().getContentResolver();
storiesUri = FeedProvider.STORIES_URI.buildUpon().appendPath(feedId).build(); storiesUri = FeedProvider.FEED_STORIES_URI.buildUpon().appendPath(feedId).build();
Cursor cursor = contentResolver.query(storiesUri, null, FeedProvider.getSelectionFromState(currentState), null, DatabaseConstants.STORY_DATE + " DESC"); Uri feedUri = FeedProvider.FEEDS_URI.buildUpon().appendPath(feedId).build();
Cursor cursor = contentResolver.query(storiesUri, null, FeedProvider.getSelectionFromState(currentState), null, DatabaseConstants.STORY_DATE + " DESC");
feed = Feed.fromCursor(contentResolver.query(feedUri, null, null, null, null));
String[] groupFrom = new String[] { DatabaseConstants.STORY_TITLE, DatabaseConstants.STORY_AUTHORS, DatabaseConstants.STORY_READ, DatabaseConstants.STORY_SHORTDATE, DatabaseConstants.STORY_INTELLIGENCE_AUTHORS }; String[] groupFrom = new String[] { DatabaseConstants.STORY_TITLE, DatabaseConstants.STORY_AUTHORS, DatabaseConstants.STORY_READ, DatabaseConstants.STORY_SHORTDATE, DatabaseConstants.STORY_INTELLIGENCE_AUTHORS };
int[] groupTo = new int[] { R.id.row_item_title, R.id.row_item_author, R.id.row_item_title, R.id.row_item_date, R.id.row_item_sidebar }; int[] groupTo = new int[] { R.id.row_item_title, R.id.row_item_author, R.id.row_item_title, R.id.row_item_date, R.id.row_item_sidebar };
getLoaderManager().initLoader(ITEMLIST_LOADER , null, this); getLoaderManager().initLoader(ITEMLIST_LOADER , null, this);
adapter = new SimpleCursorAdapter(getActivity(), R.layout.row_item, cursor, groupFrom, groupTo, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); adapter = new SimpleCursorAdapter(getActivity(), R.layout.row_item, cursor, groupFrom, groupTo, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
itemList.setOnScrollListener(this);
adapter.setViewBinder(new ItemViewBinder()); adapter.setViewBinder(new ItemViewBinder());
itemList.setAdapter(adapter); itemList.setAdapter(adapter);
itemList.setOnItemClickListener(this); itemList.setOnItemClickListener(this);
return v; return v;
} }
@Override @Override
public Loader<Cursor> onCreateLoader(int loaderId, Bundle bundle) { public Loader<Cursor> onCreateLoader(int loaderId, Bundle bundle) {
Uri uri = FeedProvider.STORIES_URI.buildUpon().appendPath(feedId).build(); Uri uri = FeedProvider.FEED_STORIES_URI.buildUpon().appendPath(feedId).build();
CursorLoader cursorLoader = new CursorLoader(getActivity(), uri, null, FeedProvider.getSelectionFromState(currentState), null, DatabaseConstants.STORY_DATE + " DESC"); CursorLoader cursorLoader = new CursorLoader(getActivity(), uri, null, FeedProvider.getSelectionFromState(currentState), null, DatabaseConstants.STORY_DATE + " DESC");
return cursorLoader; return cursorLoader;
} }
@Override @Override
@ -93,9 +105,10 @@ public class FeedItemListFragment extends ItemListFragment implements LoaderMana
adapter.swapCursor(cursor); adapter.swapCursor(cursor);
} }
} }
public void hasUpdated() { public void hasUpdated() {
getLoaderManager().restartLoader(ITEMLIST_LOADER , null, this); getLoaderManager().restartLoader(ITEMLIST_LOADER , null, this);
requestedPage = false;
} }
@Override @Override
@ -120,6 +133,37 @@ public class FeedItemListFragment extends ItemListFragment implements LoaderMana
adapter.swapCursor(cursor); adapter.swapCursor(cursor);
} }
@Override
public void onScroll(AbsListView view, int firstVisible, int visibleCount, int totalCount) {
if (firstVisible + visibleCount == totalCount) {
boolean loadMore = false;
switch (currentState) {
case AppConstants.STATE_ALL:
loadMore = feed.positiveCount + feed.neutralCount + feed.negativeCount > totalCount;
break;
case AppConstants.STATE_BEST:
loadMore = feed.positiveCount > totalCount;
break;
case AppConstants.STATE_SOME:
loadMore = feed.positiveCount + feed.neutralCount > totalCount;
break;
}
if (loadMore && !requestedPage) {
currentPage += 1;
requestedPage = true;
((ItemsList) getActivity()).triggerRefresh(currentPage);
} else {
Log.d(TAG, "No need");
}
}
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) { }
} }

View file

@ -14,21 +14,24 @@ import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView; import android.widget.ListView;
import com.newsblur.R; import com.newsblur.R;
import com.newsblur.activity.ItemsList; import com.newsblur.activity.ItemsList;
import com.newsblur.activity.NewsBlurApplication;
import com.newsblur.activity.Reading; import com.newsblur.activity.Reading;
import com.newsblur.activity.SocialFeedReading; import com.newsblur.activity.SocialFeedReading;
import com.newsblur.database.DatabaseConstants; import com.newsblur.database.DatabaseConstants;
import com.newsblur.database.FeedProvider; import com.newsblur.database.FeedProvider;
import com.newsblur.database.SocialFeedItemsAdapter; import com.newsblur.database.SocialFeedItemsAdapter;
import com.newsblur.domain.SocialFeed;
import com.newsblur.util.AppConstants;
import com.newsblur.view.SocialItemViewBinder; import com.newsblur.view.SocialItemViewBinder;
public class SocialFeedItemListFragment extends ItemListFragment implements LoaderManager.LoaderCallbacks<Cursor>, OnItemClickListener { public class SocialFeedItemListFragment extends ItemListFragment implements LoaderManager.LoaderCallbacks<Cursor>, OnItemClickListener, OnScrollListener {
private static final String TAG = "socialfeedListFragment"; private static final String TAG = "socialfeedListFragment";
public static final String FRAGMENT_TAG = "socialfeedListFragment"; public static final String FRAGMENT_TAG = "socialfeedListFragment";
@ -36,9 +39,13 @@ public class SocialFeedItemListFragment extends ItemListFragment implements Load
private String userId, username; private String userId, username;
private SimpleCursorAdapter adapter; private SimpleCursorAdapter adapter;
private Uri storiesUri; private Uri storiesUri;
private int currentState; private SocialFeed socialFeed;
private int currentState, currentPage = 1;
private boolean requestedPage;
public static int ITEMLIST_LOADER = 0x01; public static int ITEMLIST_LOADER = 0x01;
private int READING_RETURNED = 0x02; private int READING_RETURNED = 0x02;
private Uri socialFeedUri;
public SocialFeedItemListFragment(final String userId, final String username, final int currentState) { public SocialFeedItemListFragment(final String userId, final String username, final int currentState) {
this.userId = userId; this.userId = userId;
@ -53,19 +60,12 @@ public class SocialFeedItemListFragment extends ItemListFragment implements Load
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
}
public static SocialFeedItemListFragment newInstance(final String userId, final String username, final int currentState) {
return new SocialFeedItemListFragment(userId, username, currentState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_itemlist, null);
ListView itemList = (ListView) v.findViewById(R.id.itemlistfragment_list);
contentResolver = getActivity().getContentResolver(); contentResolver = getActivity().getContentResolver();
storiesUri = FeedProvider.SOCIAL_FEEDS_URI.buildUpon().appendPath(userId).build(); storiesUri = FeedProvider.SOCIALFEED_STORIES_URI.buildUpon().appendPath(userId).build();
socialFeedUri = FeedProvider.SOCIAL_FEEDS_URI.buildUpon().appendPath(userId).build();
socialFeed = SocialFeed.fromCursor(contentResolver.query(socialFeedUri, null, null, null, null));
Cursor cursor = contentResolver.query(storiesUri, null, FeedProvider.getSelectionFromState(currentState), null, DatabaseConstants.STORY_DATE + " DESC"); Cursor cursor = contentResolver.query(storiesUri, null, FeedProvider.getSelectionFromState(currentState), null, DatabaseConstants.STORY_DATE + " DESC");
String[] groupFrom = new String[] { DatabaseConstants.FEED_FAVICON_URL, DatabaseConstants.FEED_TITLE, DatabaseConstants.STORY_TITLE, DatabaseConstants.STORY_READ, DatabaseConstants.STORY_SHORTDATE, DatabaseConstants.STORY_INTELLIGENCE_AUTHORS}; String[] groupFrom = new String[] { DatabaseConstants.FEED_FAVICON_URL, DatabaseConstants.FEED_TITLE, DatabaseConstants.STORY_TITLE, DatabaseConstants.STORY_READ, DatabaseConstants.STORY_SHORTDATE, DatabaseConstants.STORY_INTELLIGENCE_AUTHORS};
@ -76,6 +76,17 @@ public class SocialFeedItemListFragment extends ItemListFragment implements Load
adapter = new SocialFeedItemsAdapter(getActivity(), R.layout.row_socialitem, cursor, groupFrom, groupTo, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); adapter = new SocialFeedItemsAdapter(getActivity(), R.layout.row_socialitem, cursor, groupFrom, groupTo, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
adapter.setViewBinder(new SocialItemViewBinder(getActivity())); adapter.setViewBinder(new SocialItemViewBinder(getActivity()));
}
public static SocialFeedItemListFragment newInstance(final String userId, final String username, final int currentState) {
return new SocialFeedItemListFragment(userId, username, currentState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_itemlist, null);
ListView itemList = (ListView) v.findViewById(R.id.itemlistfragment_list);
itemList.setOnScrollListener(this);
itemList.setAdapter(adapter); itemList.setAdapter(adapter);
itemList.setOnItemClickListener(this); itemList.setOnItemClickListener(this);
@ -84,7 +95,7 @@ public class SocialFeedItemListFragment extends ItemListFragment implements Load
@Override @Override
public Loader<Cursor> onCreateLoader(int loaderId, Bundle bundle) { public Loader<Cursor> onCreateLoader(int loaderId, Bundle bundle) {
Uri uri = FeedProvider.SOCIAL_FEEDS_URI.buildUpon().appendPath(userId).build(); Uri uri = FeedProvider.SOCIALFEED_STORIES_URI.buildUpon().appendPath(userId).build();
CursorLoader cursorLoader = new CursorLoader(getActivity(), uri, null, FeedProvider.getSelectionFromState(currentState), null, DatabaseConstants.STORY_DATE + " DESC"); CursorLoader cursorLoader = new CursorLoader(getActivity(), uri, null, FeedProvider.getSelectionFromState(currentState), null, DatabaseConstants.STORY_DATE + " DESC");
return cursorLoader; return cursorLoader;
} }
@ -98,6 +109,7 @@ public class SocialFeedItemListFragment extends ItemListFragment implements Load
public void hasUpdated() { public void hasUpdated() {
getLoaderManager().restartLoader(ITEMLIST_LOADER , null, this); getLoaderManager().restartLoader(ITEMLIST_LOADER , null, this);
requestedPage = false;
} }
@Override @Override
@ -105,6 +117,34 @@ public class SocialFeedItemListFragment extends ItemListFragment implements Load
Log.d(TAG, "Loader reset"); Log.d(TAG, "Loader reset");
adapter.notifyDataSetInvalidated(); adapter.notifyDataSetInvalidated();
} }
@Override
public void onScroll(AbsListView view, int firstVisible, int visibleCount, int totalCount) {
if (firstVisible + visibleCount == totalCount) {
boolean loadMore = false;
switch (currentState) {
case AppConstants.STATE_ALL:
loadMore = socialFeed.positiveCount + socialFeed.neutralCount + socialFeed.negativeCount > totalCount;
break;
case AppConstants.STATE_BEST:
loadMore = socialFeed.positiveCount > totalCount;
break;
case AppConstants.STATE_SOME:
loadMore = socialFeed.positiveCount + socialFeed.neutralCount > totalCount;
break;
}
if (loadMore && !requestedPage) {
currentPage += 1;
requestedPage = true;
((ItemsList) getActivity()).triggerRefresh(currentPage);
} else {
Log.d(TAG, "No need");
}
}
}
@Override @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
@ -123,4 +163,7 @@ public class SocialFeedItemListFragment extends ItemListFragment implements Load
adapter.swapCursor(cursor); adapter.swapCursor(cursor);
} }
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) { }
} }

View file

@ -30,6 +30,7 @@ public class APIConstants {
public static final String PARAMETER_SHARE_COMMENT = "comments"; public static final String PARAMETER_SHARE_COMMENT = "comments";
public static final String PARAMETER_SHARE_SOURCEID = "source_user_id"; public static final String PARAMETER_SHARE_SOURCEID = "source_user_id";
public static final String PARAMETER_MARKSOCIAL_JSON = "users_feeds_stories"; public static final String PARAMETER_MARKSOCIAL_JSON = "users_feeds_stories";
public static final String PARAMETER_PAGE_NUMBER = "page";
public static final String NEWSBLUR_URL = "http://www.newsblur.com"; public static final String NEWSBLUR_URL = "http://www.newsblur.com";

View file

@ -133,15 +133,18 @@ public class APIManager {
} }
} }
public StoriesResponse getStoriesForFeed(String feedId) { public StoriesResponse getStoriesForFeed(String feedId, String pageNumber) {
final APIClient client = new APIClient(context); final APIClient client = new APIClient(context);
final ContentValues values = new ContentValues(); final ContentValues values = new ContentValues();
values.put(APIConstants.PARAMETER_FEEDS, feedId); values.put(APIConstants.PARAMETER_FEEDS, feedId);
if (!TextUtils.isEmpty(pageNumber)) {
values.put(APIConstants.PARAMETER_PAGE_NUMBER, "" + pageNumber);
}
Uri feedUri = Uri.parse(APIConstants.URL_FEED_STORIES).buildUpon().appendPath(feedId).build(); Uri feedUri = Uri.parse(APIConstants.URL_FEED_STORIES).buildUpon().appendPath(feedId).build();
final APIResponse response = client.get(feedUri.toString(), values); final APIResponse response = client.get(feedUri.toString(), values);
StoriesResponse storiesResponse = gson.fromJson(response.responseString, StoriesResponse.class); StoriesResponse storiesResponse = gson.fromJson(response.responseString, StoriesResponse.class);
if (response.responseCode == HttpStatus.SC_OK && !response.hasRedirected) { if (response.responseCode == HttpStatus.SC_OK && !response.hasRedirected) {
Uri storyUri = FeedProvider.STORIES_URI.buildUpon().appendPath(feedId).build(); Uri storyUri = FeedProvider.FEED_STORIES_URI.buildUpon().appendPath(feedId).build();
for (Story story : storiesResponse.stories) { for (Story story : storiesResponse.stories) {
contentResolver.insert(storyUri, story.getValues()); contentResolver.insert(storyUri, story.getValues());
for (Comment comment : story.comments) { for (Comment comment : story.comments) {
@ -160,18 +163,20 @@ public class APIManager {
} }
} }
public SocialFeedResponse getStoriesForSocialFeed(String userId, String username) { public SocialFeedResponse getStoriesForSocialFeed(String userId, String username, String pageNumber) {
final APIClient client = new APIClient(context); final APIClient client = new APIClient(context);
final ContentValues values = new ContentValues(); final ContentValues values = new ContentValues();
values.put(APIConstants.PARAMETER_USER_ID, userId); values.put(APIConstants.PARAMETER_USER_ID, userId);
values.put(APIConstants.PARAMETER_USERNAME, username); values.put(APIConstants.PARAMETER_USERNAME, username);
if (!TextUtils.isEmpty(pageNumber)) {
values.put(APIConstants.PARAMETER_PAGE_NUMBER, "" + pageNumber);
}
Uri feedUri = Uri.parse(APIConstants.URL_SOCIALFEED_STORIES).buildUpon().appendPath(userId).appendPath(username).build(); Uri feedUri = Uri.parse(APIConstants.URL_SOCIALFEED_STORIES).buildUpon().appendPath(userId).appendPath(username).build();
final APIResponse response = client.get(feedUri.toString(), values); final APIResponse response = client.get(feedUri.toString(), values);
SocialFeedResponse socialFeedResponse = gson.fromJson(response.responseString, SocialFeedResponse.class); SocialFeedResponse socialFeedResponse = gson.fromJson(response.responseString, SocialFeedResponse.class);
if (response.responseCode == HttpStatus.SC_OK && !response.hasRedirected) { if (response.responseCode == HttpStatus.SC_OK && !response.hasRedirected) {
for (Story story : socialFeedResponse.stories) { for (Story story : socialFeedResponse.stories) {
Uri storyUri = FeedProvider.STORIES_URI.buildUpon().appendPath(story.feedId).build(); Uri storyUri = FeedProvider.FEED_STORIES_URI.buildUpon().appendPath(story.feedId).build();
contentResolver.insert(storyUri, story.getValues()); contentResolver.insert(storyUri, story.getValues());
for (Comment comment : story.comments) { for (Comment comment : story.comments) {
@ -184,9 +189,8 @@ public class APIManager {
contentResolver.insert(FeedProvider.COMMENTS_URI, comment.getValues()); contentResolver.insert(FeedProvider.COMMENTS_URI, comment.getValues());
} }
Uri storySocialUri = FeedProvider.SOCIAL_FEEDS_URI.buildUpon().appendPath(userId).build(); Uri storySocialUri = FeedProvider.SOCIALFEED_STORIES_URI.buildUpon().appendPath(userId).build();
contentResolver.insert(storySocialUri, story.getValues()); contentResolver.insert(storySocialUri, story.getValues());
} }
for (Feed feed : socialFeedResponse.feeds) { for (Feed feed : socialFeedResponse.feeds) {

View file

@ -33,7 +33,7 @@ public class SyncService extends IntentService {
public static final String EXTRA_TASK_SOCIALFEED_ID = "userId"; public static final String EXTRA_TASK_SOCIALFEED_ID = "userId";
public static final String EXTRA_TASK_SOCIALFEED_USERNAME = "username"; public static final String EXTRA_TASK_SOCIALFEED_USERNAME = "username";
public static final String EXTRA_TASK_MARK_SOCIAL_JSON = "socialJson"; public static final String EXTRA_TASK_MARK_SOCIAL_JSON = "socialJson";
public static final String EXTRA_TASK_PAGE_NUMBER = "page";
public final static int STATUS_RUNNING = 0x02; public final static int STATUS_RUNNING = 0x02;
public final static int STATUS_FINISHED = 0x03; public final static int STATUS_FINISHED = 0x03;
@ -117,7 +117,7 @@ public class SyncService extends IntentService {
break; break;
case EXTRA_TASK_FEED_UPDATE: case EXTRA_TASK_FEED_UPDATE:
if (!TextUtils.isEmpty(intent.getStringExtra(EXTRA_TASK_FEED_ID))) { if (!TextUtils.isEmpty(intent.getStringExtra(EXTRA_TASK_FEED_ID))) {
apiManager.getStoriesForFeed(intent.getStringExtra(EXTRA_TASK_FEED_ID)); apiManager.getStoriesForFeed(intent.getStringExtra(EXTRA_TASK_FEED_ID), intent.getStringExtra(EXTRA_TASK_PAGE_NUMBER));
} else { } else {
Log.e(TAG, "No feed to refresh included in SyncRequest"); Log.e(TAG, "No feed to refresh included in SyncRequest");
receiver.send(STATUS_ERROR, Bundle.EMPTY); receiver.send(STATUS_ERROR, Bundle.EMPTY);
@ -125,7 +125,7 @@ public class SyncService extends IntentService {
break; break;
case EXTRA_TASK_SOCIALFEED_UPDATE: case EXTRA_TASK_SOCIALFEED_UPDATE:
if (!TextUtils.isEmpty(intent.getStringExtra(EXTRA_TASK_SOCIALFEED_ID)) && !TextUtils.isEmpty(intent.getStringExtra(EXTRA_TASK_SOCIALFEED_USERNAME))) { if (!TextUtils.isEmpty(intent.getStringExtra(EXTRA_TASK_SOCIALFEED_ID)) && !TextUtils.isEmpty(intent.getStringExtra(EXTRA_TASK_SOCIALFEED_USERNAME))) {
apiManager.getStoriesForSocialFeed(intent.getStringExtra(EXTRA_TASK_SOCIALFEED_ID), intent.getStringExtra(EXTRA_TASK_SOCIALFEED_USERNAME)); apiManager.getStoriesForSocialFeed(intent.getStringExtra(EXTRA_TASK_SOCIALFEED_ID), intent.getStringExtra(EXTRA_TASK_SOCIALFEED_USERNAME), intent.getStringExtra(EXTRA_TASK_PAGE_NUMBER));
} else { } else {
Log.e(TAG, "Missing parameters forsocialfeed SyncRequest"); Log.e(TAG, "Missing parameters forsocialfeed SyncRequest");
receiver.send(STATUS_ERROR, Bundle.EMPTY); receiver.send(STATUS_ERROR, Bundle.EMPTY);