mirror of
https://github.com/samuelclay/NewsBlur.git
synced 2025-09-18 21:50:56 +00:00
Unified story fetching.
This commit is contained in:
parent
dcc6d89dd3
commit
2ffef06fab
6 changed files with 107 additions and 245 deletions
|
@ -13,12 +13,11 @@ import com.google.gson.Gson;
|
|||
import com.google.gson.GsonBuilder;
|
||||
|
||||
/**
|
||||
* This utility class is simply a Map<String,String> that serializes to JSON.
|
||||
* A String-to-String multimap that serializes to JSON or HTTP request params.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ValueMultimap implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 3102965432185825759L;
|
||||
|
||||
private Map<String, List<String>> multimap;
|
||||
private String TAG = "ValueMultimap";
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import java.net.URLEncoder;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
|
@ -49,6 +50,7 @@ import com.newsblur.serialization.BooleanTypeAdapter;
|
|||
import com.newsblur.serialization.DateStringTypeAdapter;
|
||||
import com.newsblur.serialization.StoryTypeAdapter;
|
||||
import com.newsblur.util.AppConstants;
|
||||
import com.newsblur.util.FeedSet;
|
||||
import com.newsblur.util.NetworkUtils;
|
||||
import com.newsblur.util.PrefConstants;
|
||||
import com.newsblur.util.PrefsUtils;
|
||||
|
@ -218,18 +220,6 @@ public class APIManager {
|
|||
return (UnreadStoryHashesResponse) response.getResponse(gson, UnreadStoryHashesResponse.class);
|
||||
}
|
||||
|
||||
public StoriesResponse getStoriesForFeed(String feedId, int pageNumber, StoryOrder order, ReadFilter filter) {
|
||||
final ContentValues values = new ContentValues();
|
||||
Uri feedUri = Uri.parse(APIConstants.URL_FEED_STORIES).buildUpon().appendPath(feedId).build();
|
||||
values.put(APIConstants.PARAMETER_FEEDS, feedId);
|
||||
values.put(APIConstants.PARAMETER_PAGE_NUMBER, Integer.toString(pageNumber));
|
||||
values.put(APIConstants.PARAMETER_ORDER, order.getParameterValue());
|
||||
values.put(APIConstants.PARAMETER_READ_FILTER, filter.getParameterValue());
|
||||
|
||||
APIResponse response = get(feedUri.toString(), values);
|
||||
return (StoriesResponse) response.getResponse(gson, StoriesResponse.class);
|
||||
}
|
||||
|
||||
public StoriesResponse getStoriesByHash(List<String> storyHashes) {
|
||||
ValueMultimap values = new ValueMultimap();
|
||||
for (String hash : storyHashes) {
|
||||
|
@ -239,126 +229,47 @@ public class APIManager {
|
|||
return (StoriesResponse) response.getResponse(gson, StoriesResponse.class);
|
||||
}
|
||||
|
||||
public StoriesResponse getStoriesForFeeds(String[] feedIds, int pageNumber, StoryOrder order, ReadFilter filter) {
|
||||
final ValueMultimap values = new ValueMultimap();
|
||||
for (String feedId : feedIds) {
|
||||
values.put(APIConstants.PARAMETER_FEEDS, feedId);
|
||||
}
|
||||
/**
|
||||
* Fetches stories for the given FeedSet, choosing the correct API and the right
|
||||
* request parameters as needed.
|
||||
*/
|
||||
public StoriesResponse getStories(FeedSet fs, int pageNumber, StoryOrder order, ReadFilter filter) {
|
||||
Uri uri;
|
||||
ValueMultimap values = new ValueMultimap();
|
||||
|
||||
// create the URI and populate request params depending on what kind of stories we want
|
||||
if (fs.getSingleFeed() != null) {
|
||||
uri = Uri.parse(APIConstants.URL_FEED_STORIES).buildUpon().appendPath(fs.getSingleFeed()).build();
|
||||
values.put(APIConstants.PARAMETER_FEEDS, fs.getSingleFeed());
|
||||
} else if (fs.getMultipleFeeds() != null) {
|
||||
uri = Uri.parse(APIConstants.URL_RIVER_STORIES);
|
||||
for (String feedId : fs.getMultipleFeeds()) values.put(APIConstants.PARAMETER_FEEDS, feedId);
|
||||
} else if (fs.getSingleSocialFeed() != null) {
|
||||
String feedId = fs.getSingleSocialFeed().getKey();
|
||||
String username = fs.getSingleSocialFeed().getValue();
|
||||
uri = Uri.parse(APIConstants.URL_SOCIALFEED_STORIES).buildUpon().appendPath(feedId).appendPath(username).build();
|
||||
values.put(APIConstants.PARAMETER_USER_ID, feedId);
|
||||
values.put(APIConstants.PARAMETER_USERNAME, username);
|
||||
} else if (fs.getMultipleSocialFeeds() != null) {
|
||||
uri = Uri.parse(APIConstants.URL_SHARED_RIVER_STORIES);
|
||||
for (Map.Entry<String,String> entry : fs.getMultipleSocialFeeds().entrySet()) {
|
||||
values.put(APIConstants.PARAMETER_FEEDS, entry.getKey());
|
||||
}
|
||||
} else if (fs.isAllSaved()) {
|
||||
uri = Uri.parse(APIConstants.URL_STARRED_STORIES);
|
||||
} else {
|
||||
Log.wtf(this.getClass().getName(), "Asked to get stories for FeedSet of unknown type.");
|
||||
return null;
|
||||
}
|
||||
|
||||
// request params common to all stories
|
||||
values.put(APIConstants.PARAMETER_PAGE_NUMBER, Integer.toString(pageNumber));
|
||||
values.put(APIConstants.PARAMETER_ORDER, order.getParameterValue());
|
||||
values.put(APIConstants.PARAMETER_READ_FILTER, filter.getParameterValue());
|
||||
final APIResponse response = get(APIConstants.URL_RIVER_STORIES, values);
|
||||
|
||||
StoriesResponse storiesResponse = (StoriesResponse) response.getResponse(gson, StoriesResponse.class);
|
||||
if (!response.isError()) {
|
||||
for (Story story : storiesResponse.stories) {
|
||||
Uri storyUri = FeedProvider.FEED_STORIES_URI.buildUpon().appendPath(story.feedId).build();
|
||||
contentResolver.insert(storyUri, story.getValues());
|
||||
insertComments(story);
|
||||
}
|
||||
|
||||
for (UserProfile user : storiesResponse.users) {
|
||||
contentResolver.insert(FeedProvider.USERS_URI, user.getValues());
|
||||
}
|
||||
}
|
||||
return storiesResponse;
|
||||
}
|
||||
|
||||
public StoriesResponse getStarredStories(int pageNumber) {
|
||||
ValueMultimap values = new ValueMultimap();
|
||||
values.put(APIConstants.PARAMETER_PAGE_NUMBER, Integer.toString(pageNumber));
|
||||
APIResponse response = get(APIConstants.URL_STARRED_STORIES, values);
|
||||
|
||||
StoriesResponse storiesResponse = (StoriesResponse) response.getResponse(gson, StoriesResponse.class);
|
||||
if (!response.isError()) {
|
||||
for (Story story : storiesResponse.stories) {
|
||||
contentResolver.insert(FeedProvider.STARRED_STORIES_URI, story.getValues());
|
||||
insertComments(story);
|
||||
}
|
||||
for (UserProfile user : storiesResponse.users) {
|
||||
contentResolver.insert(FeedProvider.USERS_URI, user.getValues());
|
||||
}
|
||||
}
|
||||
return storiesResponse;
|
||||
}
|
||||
|
||||
public SocialFeedResponse getSharedStoriesForFeeds(String[] feedIds, int pageNumber, StoryOrder order, ReadFilter filter) {
|
||||
final ValueMultimap values = new ValueMultimap();
|
||||
for (String feedId : feedIds) {
|
||||
values.put(APIConstants.PARAMETER_FEEDS, feedId);
|
||||
}
|
||||
values.put(APIConstants.PARAMETER_PAGE_NUMBER, Integer.toString(pageNumber));
|
||||
values.put(APIConstants.PARAMETER_ORDER, order.getParameterValue());
|
||||
values.put(APIConstants.PARAMETER_READ_FILTER, filter.getParameterValue());
|
||||
|
||||
final APIResponse response = get(APIConstants.URL_SHARED_RIVER_STORIES, values);
|
||||
SocialFeedResponse storiesResponse = (SocialFeedResponse) response.getResponse(gson, SocialFeedResponse.class);
|
||||
if (!response.isError()) {
|
||||
|
||||
for (Story story : storiesResponse.stories) {
|
||||
for (String userId : story.sharedUserIds) {
|
||||
Uri storySocialUri = FeedProvider.SOCIALFEED_STORIES_URI.buildUpon().appendPath(userId).build();
|
||||
contentResolver.insert(storySocialUri, story.getValues());
|
||||
}
|
||||
|
||||
Uri storyUri = FeedProvider.FEED_STORIES_URI.buildUpon().appendPath(story.feedId).build();
|
||||
contentResolver.insert(storyUri, story.getValues());
|
||||
|
||||
insertComments(story);
|
||||
}
|
||||
|
||||
for (UserProfile user : storiesResponse.userProfiles) {
|
||||
contentResolver.insert(FeedProvider.USERS_URI, user.getValues());
|
||||
}
|
||||
|
||||
if (storiesResponse != null && storiesResponse.feeds!= null) {
|
||||
for (Feed feed : storiesResponse.feeds) {
|
||||
contentResolver.insert(FeedProvider.FEEDS_URI, feed.getValues());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return storiesResponse;
|
||||
}
|
||||
|
||||
public SocialFeedResponse getStoriesForSocialFeed(String userId, String username, int pageNumber, StoryOrder order, ReadFilter filter) {
|
||||
final ContentValues values = new ContentValues();
|
||||
values.put(APIConstants.PARAMETER_USER_ID, userId);
|
||||
values.put(APIConstants.PARAMETER_USERNAME, username);
|
||||
values.put(APIConstants.PARAMETER_ORDER, order.getParameterValue());
|
||||
values.put(APIConstants.PARAMETER_READ_FILTER, filter.getParameterValue());
|
||||
values.put(APIConstants.PARAMETER_PAGE_NUMBER, Integer.toString(pageNumber));
|
||||
Uri feedUri = Uri.parse(APIConstants.URL_SOCIALFEED_STORIES).buildUpon().appendPath(userId).appendPath(username).build();
|
||||
final APIResponse response = get(feedUri.toString(), values);
|
||||
SocialFeedResponse socialFeedResponse = (SocialFeedResponse) response.getResponse(gson, SocialFeedResponse.class);
|
||||
if (!response.isError()) {
|
||||
|
||||
for (Story story : socialFeedResponse.stories) {
|
||||
insertComments(story);
|
||||
|
||||
Uri storyUri = FeedProvider.FEED_STORIES_URI.buildUpon().appendPath(story.feedId).build();
|
||||
Uri storySocialUri = FeedProvider.SOCIALFEED_STORIES_URI.buildUpon().appendPath(userId).build();
|
||||
contentResolver.insert(storyUri, story.getValues());
|
||||
contentResolver.insert(storySocialUri, story.getValues());
|
||||
}
|
||||
|
||||
if (socialFeedResponse.userProfiles != null) {
|
||||
for (UserProfile user : socialFeedResponse.userProfiles) {
|
||||
contentResolver.insert(FeedProvider.USERS_URI, user.getValues());
|
||||
}
|
||||
}
|
||||
|
||||
if (socialFeedResponse.feeds != null) {
|
||||
for (Feed feed : socialFeedResponse.feeds) {
|
||||
contentResolver.insert(FeedProvider.FEEDS_URI, feed.getValues());
|
||||
}
|
||||
}
|
||||
|
||||
return socialFeedResponse;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
APIResponse response = get(uri.toString(), values);
|
||||
return (StoriesResponse) response.getResponse(gson, StoriesResponse.class);
|
||||
}
|
||||
|
||||
private void insertComments(Story story) {
|
||||
for (Comment comment : story.publicComments) {
|
||||
|
|
|
@ -303,7 +303,7 @@ public class NBSyncService extends Service {
|
|||
if (HaltNow) return;
|
||||
|
||||
pageNumber++;
|
||||
StoriesResponse apiResponse /*= apiManager.getStoriesForFeed(feedId, pageNumber, order, filter)*/ = null;
|
||||
StoriesResponse apiResponse = apiManager.getStories(fs, pageNumber, order, filter);
|
||||
|
||||
if (! isStoryResponseGood(apiResponse)) break feedloop;
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import java.util.Collections;
|
|||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
|
@ -108,12 +109,40 @@ public class FeedSet implements Serializable {
|
|||
return fs;
|
||||
}
|
||||
|
||||
public Set<String> getFeeds() {
|
||||
return this.feeds;
|
||||
/**
|
||||
* Gets a single feed ID iff there is only one or null otherwise.
|
||||
*/
|
||||
public String getSingleFeed() {
|
||||
if (feeds != null && feeds.size() == 1) return feeds.iterator().next(); else return null;
|
||||
}
|
||||
|
||||
public Map<String,String> getSocialFeeds() {
|
||||
return this.socialFeeds;
|
||||
/**
|
||||
* Gets a set of feed IDs iff there are multiples or null otherwise.
|
||||
*/
|
||||
public Set<String> getMultipleFeeds() {
|
||||
if (feeds != null && feeds.size() > 1) return feeds; else return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a single social feed ID and username iff there is only one or null otherwise.
|
||||
*/
|
||||
public Map.Entry<String,String> getSingleSocialFeed() {
|
||||
if (socialFeeds != null && socialFeeds.size() == 1) return socialFeeds.entrySet().iterator().next(); else return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a set of social feed IDs and usernames iff there are multiples or null otherwise.
|
||||
*/
|
||||
public Map<String,String> getMultipleSocialFeeds() {
|
||||
if (socialFeeds != null && socialFeeds.size() > 1) return socialFeeds; else return null;
|
||||
}
|
||||
|
||||
public boolean isAllNormal() {
|
||||
return this.isAllNormal;
|
||||
}
|
||||
|
||||
public boolean isAllSocial() {
|
||||
return this.isAllSocial;
|
||||
}
|
||||
|
||||
public boolean isAllSaved() {
|
||||
|
|
|
@ -37,83 +37,6 @@ import com.newsblur.util.AppConstants;
|
|||
|
||||
public class FeedUtils {
|
||||
|
||||
public static void updateFeeds(final Context context, final ActionCompletionListener receiver, final String[] feedIds, final int pageNumber, final StoryOrder order, final ReadFilter filter) {
|
||||
new AsyncTask<Void, Void, StoriesResponse>() {
|
||||
@Override
|
||||
protected StoriesResponse doInBackground(Void... arg) {
|
||||
APIManager apiManager = new APIManager(context);
|
||||
return apiManager.getStoriesForFeeds(feedIds, pageNumber, order, filter);
|
||||
}
|
||||
@Override
|
||||
protected void onPostExecute(StoriesResponse result) {
|
||||
handleStoryResponse(context, result, result.stories, receiver);
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
public static void updateSocialFeed(final Context context, final ActionCompletionListener receiver, final String feedId, final String socialUsername, final int pageNumber, final StoryOrder order, final ReadFilter filter) {
|
||||
new AsyncTask<Void, Void, SocialFeedResponse>() {
|
||||
@Override
|
||||
protected SocialFeedResponse doInBackground(Void... arg) {
|
||||
APIManager apiManager = new APIManager(context);
|
||||
return apiManager.getStoriesForSocialFeed(feedId, socialUsername, pageNumber, order, filter);
|
||||
}
|
||||
@Override
|
||||
protected void onPostExecute(SocialFeedResponse result) {
|
||||
handleStoryResponse(context, result, result.stories, receiver);
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
public static void updateSocialFeeds(final Context context, final ActionCompletionListener receiver, final String[] feedIds, final int pageNumber, final StoryOrder order, final ReadFilter filter) {
|
||||
new AsyncTask<Void, Void, SocialFeedResponse>() {
|
||||
@Override
|
||||
protected SocialFeedResponse doInBackground(Void... arg) {
|
||||
APIManager apiManager = new APIManager(context);
|
||||
return apiManager.getSharedStoriesForFeeds(feedIds, pageNumber, order, filter);
|
||||
}
|
||||
@Override
|
||||
protected void onPostExecute(SocialFeedResponse result) {
|
||||
handleStoryResponse(context, result, result.stories, receiver);
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
public static void updateSavedStories(final Context context, final ActionCompletionListener receiver, final int pageNumber) {
|
||||
new AsyncTask<Void, Void, StoriesResponse>() {
|
||||
@Override
|
||||
protected StoriesResponse doInBackground(Void... arg) {
|
||||
APIManager apiManager = new APIManager(context);
|
||||
return apiManager.getStarredStories(pageNumber);
|
||||
}
|
||||
@Override
|
||||
protected void onPostExecute(StoriesResponse result) {
|
||||
handleStoryResponse(context, result, result.stories, receiver);
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
private static void handleStoryResponse(Context context, NewsBlurResponse response, Story[] stories, ActionCompletionListener receiver) {
|
||||
// the API may return both a valid stories block *and* an error, so check for stories first
|
||||
if (stories != null) {
|
||||
if (receiver != null) {
|
||||
receiver.actionCompleteCallback(stories.length == 0); // only keep loading if there are more stories left
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.isError()) {
|
||||
Log.e(FeedUtils.class.getName(), "Error response received loading stories.");
|
||||
Toast.makeText(context, response.getErrorMessage(context.getString(R.string.toast_error_loading_stories)), Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
Log.e(FeedUtils.class.getName(), "Null stories member received while loading stories with no error found.");
|
||||
Toast.makeText(context, R.string.toast_error_loading_stories, Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
// NB: we do not keep loading on error, since the calling class would need to know to adjust pagination
|
||||
receiver.actionCompleteCallback(true);
|
||||
}
|
||||
|
||||
private static void setStorySaved(final Story story, final boolean saved, final Context context, final APIManager apiManager) {
|
||||
new AsyncTask<Void, Void, NewsBlurResponse>() {
|
||||
@Override
|
||||
|
|
|
@ -293,24 +293,24 @@ public class PrefsUtils {
|
|||
}
|
||||
|
||||
public static StoryOrder getStoryOrder(Context context, FeedSet fs) {
|
||||
if (fs.getFeeds() != null) {
|
||||
if (fs.getFeeds().size() == 0) {
|
||||
return getStoryOrderForFolder(context, PrefConstants.ALL_STORIES_FOLDER_NAME);
|
||||
} else if (fs.getFeeds().size() == 1) {
|
||||
return getStoryOrderForFeed(context, fs.getFeeds().iterator().next());
|
||||
} else {
|
||||
return getStoryOrderForFolder(context, fs.getFolderName());
|
||||
}
|
||||
if (fs.isAllNormal()) {
|
||||
return getStoryOrderForFolder(context, PrefConstants.ALL_STORIES_FOLDER_NAME);
|
||||
}
|
||||
if (fs.getSingleFeed() != null) {
|
||||
return getStoryOrderForFeed(context, fs.getSingleFeed());
|
||||
}
|
||||
if (fs.getMultipleFeeds() != null) {
|
||||
return getStoryOrderForFolder(context, fs.getFolderName());
|
||||
}
|
||||
|
||||
if (fs.getSocialFeeds() != null) {
|
||||
if (fs.getSocialFeeds().size() == 0) {
|
||||
return getStoryOrderForFolder(context, PrefConstants.ALL_SHARED_STORIES_FOLDER_NAME);
|
||||
} else if (fs.getSocialFeeds().size() == 1) {
|
||||
return getStoryOrderForFeed(context, fs.getSocialFeeds().keySet().iterator().next());
|
||||
} else {
|
||||
throw new IllegalArgumentException( "requests for multiple social feeds not supported" );
|
||||
}
|
||||
if (fs.isAllSocial()) {
|
||||
return getStoryOrderForFolder(context, PrefConstants.ALL_SHARED_STORIES_FOLDER_NAME);
|
||||
}
|
||||
if (fs.getSingleSocialFeed() != null) {
|
||||
return getStoryOrderForFeed(context, fs.getSingleSocialFeed().getKey());
|
||||
}
|
||||
if (fs.getMultipleSocialFeeds() != null) {
|
||||
throw new IllegalArgumentException( "requests for multiple social feeds not supported" );
|
||||
}
|
||||
|
||||
if (fs.isAllSaved()) {
|
||||
|
@ -321,24 +321,24 @@ public class PrefsUtils {
|
|||
}
|
||||
|
||||
public static ReadFilter getReadFilter(Context context, FeedSet fs) {
|
||||
if (fs.getFeeds() != null) {
|
||||
if (fs.getFeeds().size() == 0) {
|
||||
return getReadFilterForFolder(context, PrefConstants.ALL_STORIES_FOLDER_NAME);
|
||||
} else if (fs.getFeeds().size() == 1) {
|
||||
return getReadFilterForFeed(context, fs.getFeeds().iterator().next());
|
||||
} else {
|
||||
return getReadFilterForFolder(context, fs.getFolderName());
|
||||
}
|
||||
if (fs.isAllNormal()) {
|
||||
return getReadFilterForFolder(context, PrefConstants.ALL_STORIES_FOLDER_NAME);
|
||||
}
|
||||
if (fs.getSingleFeed() != null) {
|
||||
return getReadFilterForFeed(context, fs.getSingleFeed());
|
||||
}
|
||||
if (fs.getMultipleFeeds() != null) {
|
||||
return getReadFilterForFolder(context, fs.getFolderName());
|
||||
}
|
||||
|
||||
if (fs.getSocialFeeds() != null) {
|
||||
if (fs.getSocialFeeds().size() == 0) {
|
||||
return getReadFilterForFolder(context, PrefConstants.ALL_SHARED_STORIES_FOLDER_NAME);
|
||||
} else if (fs.getSocialFeeds().size() == 1) {
|
||||
return getReadFilterForFeed(context, fs.getSocialFeeds().keySet().iterator().next());
|
||||
} else {
|
||||
throw new IllegalArgumentException( "requests for multiple social feeds not supported" );
|
||||
}
|
||||
if (fs.isAllSocial()) {
|
||||
return getReadFilterForFolder(context, PrefConstants.ALL_SHARED_STORIES_FOLDER_NAME);
|
||||
}
|
||||
if (fs.getSingleSocialFeed() != null) {
|
||||
return getReadFilterForFeed(context, fs.getSingleSocialFeed().getKey());
|
||||
}
|
||||
if (fs.getMultipleSocialFeeds() != null) {
|
||||
throw new IllegalArgumentException( "requests for multiple social feeds not supported" );
|
||||
}
|
||||
|
||||
if (fs.isAllSaved()) {
|
||||
|
|
Loading…
Add table
Reference in a new issue