mirror of
https://github.com/viq/NewsBlur.git
synced 2025-09-18 21:43:31 +00:00
Refactor/fix mark-as-read-while-reading workflow.
This commit is contained in:
parent
70877d4323
commit
35b680c0d9
16 changed files with 138 additions and 362 deletions
|
@ -10,14 +10,11 @@ import com.newsblur.R;
|
|||
import com.newsblur.database.DatabaseConstants;
|
||||
import com.newsblur.database.FeedProvider;
|
||||
import com.newsblur.database.MixedFeedsReadingAdapter;
|
||||
import com.newsblur.domain.ValueMultimap;
|
||||
import com.newsblur.network.MarkMixedStoriesAsReadTask;
|
||||
import com.newsblur.service.SyncService;
|
||||
|
||||
public class AllSharedStoriesReading extends Reading {
|
||||
|
||||
private Cursor stories;
|
||||
private ValueMultimap storiesToMarkAsRead;
|
||||
private int currentPage;
|
||||
private ArrayList<String> feedIds;
|
||||
private boolean requestingPage = false;
|
||||
|
@ -33,13 +30,11 @@ public class AllSharedStoriesReading extends Reading {
|
|||
|
||||
stories = contentResolver.query(FeedProvider.ALL_SHARED_STORIES_URI, null, DatabaseConstants.getStorySelectionFromState(currentState), null, DatabaseConstants.STORY_DATE + " desc");
|
||||
setTitle(getResources().getString(R.string.all_shared_stories));
|
||||
storiesToMarkAsRead = new ValueMultimap();
|
||||
readingAdapter = new MixedFeedsReadingAdapter(getSupportFragmentManager(), getContentResolver(), stories);
|
||||
|
||||
setupPager();
|
||||
|
||||
addStoryToMarkAsRead(readingAdapter.getStory(passedPosition));
|
||||
storiesToMarkAsRead.put(readingAdapter.getStory(passedPosition).feedId, readingAdapter.getStory(passedPosition).id);
|
||||
}
|
||||
|
||||
private void setupCountCursor() {
|
||||
|
@ -55,17 +50,10 @@ public class AllSharedStoriesReading extends Reading {
|
|||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
super.onPageSelected(position);
|
||||
storiesToMarkAsRead.put(readingAdapter.getStory(position).feedId, readingAdapter.getStory(position).id);
|
||||
addStoryToMarkAsRead(readingAdapter.getStory(position));
|
||||
checkStoryCount(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
new MarkMixedStoriesAsReadTask(this, syncFragment, storiesToMarkAsRead).execute();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triggerRefresh() {
|
||||
triggerRefresh(1);
|
||||
|
|
|
@ -11,14 +11,11 @@ import com.newsblur.R;
|
|||
import com.newsblur.database.DatabaseConstants;
|
||||
import com.newsblur.database.FeedProvider;
|
||||
import com.newsblur.database.MixedFeedsReadingAdapter;
|
||||
import com.newsblur.domain.ValueMultimap;
|
||||
import com.newsblur.network.MarkMixedStoriesAsReadTask;
|
||||
import com.newsblur.service.SyncService;
|
||||
|
||||
public class AllStoriesReading extends Reading {
|
||||
|
||||
private Cursor stories;
|
||||
private ValueMultimap storiesToMarkAsRead;
|
||||
private int currentPage;
|
||||
private ArrayList<String> feedIds;
|
||||
private boolean stopLoading = false;
|
||||
|
@ -34,15 +31,13 @@ public class AllStoriesReading extends Reading {
|
|||
|
||||
stories = contentResolver.query(FeedProvider.ALL_STORIES_URI, null, DatabaseConstants.getStorySelectionFromState(currentState), null, null);
|
||||
setTitle(getResources().getString(R.string.all_stories));
|
||||
storiesToMarkAsRead = new ValueMultimap();
|
||||
readingAdapter = new MixedFeedsReadingAdapter(getSupportFragmentManager(), getContentResolver(), stories);
|
||||
|
||||
setupPager();
|
||||
|
||||
addStoryToMarkAsRead(readingAdapter.getStory(passedPosition));
|
||||
storiesToMarkAsRead.put(readingAdapter.getStory(passedPosition).feedId, readingAdapter.getStory(passedPosition).id);
|
||||
addStoryToMarkAsRead(readingAdapter.getStory(passedPosition));
|
||||
}
|
||||
|
||||
|
||||
private void setupCountCursor() {
|
||||
Cursor cursor = getContentResolver().query(FeedProvider.FEEDS_URI, null, DatabaseConstants.getStorySelectionFromState(currentState), null, null);
|
||||
feedIds = new ArrayList<String>();
|
||||
|
@ -54,17 +49,10 @@ public class AllStoriesReading extends Reading {
|
|||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
super.onPageSelected(position);
|
||||
storiesToMarkAsRead.put(readingAdapter.getStory(position).feedId, readingAdapter.getStory(position).id);
|
||||
addStoryToMarkAsRead(readingAdapter.getStory(position));
|
||||
checkStoryCount(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
new MarkMixedStoriesAsReadTask(this, syncFragment, storiesToMarkAsRead).execute();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triggerRefresh() {
|
||||
triggerRefresh(1);
|
||||
|
|
|
@ -17,13 +17,11 @@ import com.newsblur.domain.Classifier;
|
|||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.domain.Story;
|
||||
import com.newsblur.fragment.SyncUpdateFragment;
|
||||
import com.newsblur.network.MarkStoryAsReadTask;
|
||||
import com.newsblur.service.SyncService;
|
||||
import com.newsblur.util.AppConstants;
|
||||
|
||||
public class FeedReading extends Reading {
|
||||
|
||||
protected Set<String> storiesToMarkAsRead;
|
||||
String feedId;
|
||||
private Feed feed;
|
||||
private int currentPage;
|
||||
|
@ -42,7 +40,6 @@ public class FeedReading extends Reading {
|
|||
Classifier classifier = Classifier.fromCursor(feedClassifierCursor);
|
||||
|
||||
Uri storiesURI = FeedProvider.FEED_STORIES_URI.buildUpon().appendPath(feedId).build();
|
||||
storiesToMarkAsRead = new HashSet<String>();
|
||||
stories = contentResolver.query(storiesURI, null, DatabaseConstants.getStorySelectionFromState(currentState), null, DatabaseConstants.STORY_DATE + " DESC");
|
||||
|
||||
final Uri feedUri = FeedProvider.FEEDS_URI.buildUpon().appendPath(feedId).build();
|
||||
|
@ -62,19 +59,14 @@ public class FeedReading extends Reading {
|
|||
fragmentManager.beginTransaction().add(syncFragment, SyncUpdateFragment.TAG).commit();
|
||||
}
|
||||
|
||||
updateReadStories(readingAdapter.getStory(passedPosition));
|
||||
}
|
||||
|
||||
private void updateReadStories(Story story) {
|
||||
storiesToMarkAsRead.add(story.id);
|
||||
addStoryToMarkAsRead(story);
|
||||
addStoryToMarkAsRead(readingAdapter.getStory(passedPosition));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
super.onPageSelected(position);
|
||||
if (readingAdapter.getStory(position) != null) {
|
||||
updateReadStories(readingAdapter.getStory(position));
|
||||
addStoryToMarkAsRead(readingAdapter.getStory(position));
|
||||
checkStoryCount(position);
|
||||
}
|
||||
}
|
||||
|
@ -97,14 +89,6 @@ public class FeedReading extends Reading {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
ArrayList<String> storyIds = new ArrayList<String>();
|
||||
storyIds.addAll(storiesToMarkAsRead);
|
||||
new MarkStoryAsReadTask(this, syncFragment, storyIds, feedId).execute();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triggerRefresh() {
|
||||
triggerRefresh(1);
|
||||
|
|
|
@ -8,12 +8,10 @@ import android.util.Log;
|
|||
import com.newsblur.database.DatabaseConstants;
|
||||
import com.newsblur.database.FeedProvider;
|
||||
import com.newsblur.database.MixedFeedsReadingAdapter;
|
||||
import com.newsblur.domain.ValueMultimap;
|
||||
import com.newsblur.network.MarkMixedStoriesAsReadTask;
|
||||
import com.newsblur.service.SyncService;
|
||||
|
||||
public class FolderReading extends Reading {
|
||||
protected ValueMultimap storiesToMarkAsRead;
|
||||
|
||||
private String[] feedIds;
|
||||
private String folderName;
|
||||
private boolean stopLoading = false;
|
||||
|
@ -31,30 +29,21 @@ public class FolderReading extends Reading {
|
|||
setTitle(folderName);
|
||||
|
||||
Uri storiesURI = FeedProvider.MULTIFEED_STORIES_URI;
|
||||
storiesToMarkAsRead = new ValueMultimap();
|
||||
stories = contentResolver.query(storiesURI, null, DatabaseConstants.getStorySelectionFromState(currentState), feedIds, null);
|
||||
|
||||
readingAdapter = new MixedFeedsReadingAdapter(getSupportFragmentManager(), getContentResolver(), stories);
|
||||
setupPager();
|
||||
|
||||
storiesToMarkAsRead.put(readingAdapter.getStory(passedPosition).feedId, readingAdapter.getStory(passedPosition).id);
|
||||
addStoryToMarkAsRead(readingAdapter.getStory(passedPosition));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
storiesToMarkAsRead.put(readingAdapter.getStory(position).feedId, readingAdapter.getStory(position).id);
|
||||
addStoryToMarkAsRead(readingAdapter.getStory(position));
|
||||
checkStoryCount(position);
|
||||
super.onPageSelected(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
new MarkMixedStoriesAsReadTask(this, syncFragment, storiesToMarkAsRead).execute();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triggerRefresh() {
|
||||
triggerRefresh(1);
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.newsblur.activity;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import android.content.ContentProviderOperation;
|
||||
import android.content.ContentResolver;
|
||||
|
@ -41,7 +42,6 @@ import com.newsblur.util.UIUtils;
|
|||
public abstract class Reading extends NbFragmentActivity implements OnPageChangeListener, SyncUpdateFragment.SyncUpdateFragmentInterface, OnSeekBarChangeListener {
|
||||
|
||||
public static final String EXTRA_FEED = "feed_selected";
|
||||
public static final String TAG = "ReadingActivity";
|
||||
public static final String EXTRA_POSITION = "feed_position";
|
||||
public static final String EXTRA_USERID = "user_id";
|
||||
public static final String EXTRA_USERNAME = "username";
|
||||
|
@ -58,9 +58,8 @@ public abstract class Reading extends NbFragmentActivity implements OnPageChange
|
|||
protected ContentResolver contentResolver;
|
||||
private APIManager apiManager;
|
||||
protected SyncUpdateFragment syncFragment;
|
||||
private ArrayList<ContentProviderOperation> operations;
|
||||
protected Cursor stories;
|
||||
private HashSet<String> storiesToMarkAsRead;
|
||||
private Set<Story> storiesToMarkAsRead;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceBundle) {
|
||||
|
@ -69,10 +68,9 @@ public abstract class Reading extends NbFragmentActivity implements OnPageChange
|
|||
super.onCreate(savedInstanceBundle);
|
||||
setContentView(R.layout.activity_reading);
|
||||
|
||||
operations = new ArrayList<ContentProviderOperation>();
|
||||
fragmentManager = getSupportFragmentManager();
|
||||
|
||||
storiesToMarkAsRead = new HashSet<String>();
|
||||
storiesToMarkAsRead = new HashSet<Story>();
|
||||
|
||||
passedPosition = getIntent().getIntExtra(EXTRA_POSITION, 0);
|
||||
currentState = getIntent().getIntExtra(ItemsList.EXTRA_STATE, 0);
|
||||
|
@ -192,27 +190,24 @@ public abstract class Reading extends NbFragmentActivity implements OnPageChange
|
|||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
if (isFinishing()) {
|
||||
try {
|
||||
contentResolver.applyBatch(FeedProvider.AUTHORITY, operations);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to do any updating.");
|
||||
e.printStackTrace();
|
||||
} catch (OperationApplicationException e) {
|
||||
Log.e(TAG, "Failed to do any updating.");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
synchronized(this.storiesToMarkAsRead) {
|
||||
FeedUtils.markStoriesAsRead(this.storiesToMarkAsRead, this);
|
||||
this.storiesToMarkAsRead.clear();
|
||||
}
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
protected void addStoryToMarkAsRead(Story story) {
|
||||
if (story.read != Story.READ && !storiesToMarkAsRead.contains(story.id)) {
|
||||
storiesToMarkAsRead.add(story.id);
|
||||
FeedUtils.appendStoryReadOperations(story, operations);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a story as having been read. The local DB and remote server will be updated
|
||||
* batch-wise when the activity pauses.
|
||||
*/
|
||||
protected void addStoryToMarkAsRead(Story story) {
|
||||
if (story == null) return;
|
||||
if (story.read != Story.UNREAD) return;
|
||||
synchronized (this.storiesToMarkAsRead) {
|
||||
this.storiesToMarkAsRead.add(story);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
|
|
|
@ -13,12 +13,10 @@ import com.newsblur.database.FeedProvider;
|
|||
import com.newsblur.database.MixedFeedsReadingAdapter;
|
||||
import com.newsblur.domain.SocialFeed;
|
||||
import com.newsblur.domain.Story;
|
||||
import com.newsblur.network.MarkSocialStoryAsReadTask;
|
||||
import com.newsblur.service.SyncService;
|
||||
|
||||
public class SocialFeedReading extends Reading {
|
||||
|
||||
MarkSocialAsReadUpdate markSocialAsReadList;
|
||||
private String userId;
|
||||
private String username;
|
||||
private SocialFeed socialFeed;
|
||||
|
@ -34,7 +32,6 @@ public class SocialFeedReading extends Reading {
|
|||
|
||||
userId = getIntent().getStringExtra(Reading.EXTRA_USERID);
|
||||
username = getIntent().getStringExtra(Reading.EXTRA_USERNAME);
|
||||
markSocialAsReadList = new MarkSocialAsReadUpdate(userId);
|
||||
|
||||
Uri socialFeedUri = FeedProvider.SOCIAL_FEEDS_URI.buildUpon().appendPath(userId).build();
|
||||
socialFeed = SocialFeed.fromCursor(contentResolver.query(socialFeedUri, null, null, null, null));
|
||||
|
@ -47,55 +44,16 @@ public class SocialFeedReading extends Reading {
|
|||
|
||||
setupPager();
|
||||
|
||||
Story story = readingAdapter.getStory(passedPosition);
|
||||
addStoryToMarkAsRead(story);
|
||||
markSocialAsReadList.add(story.feedId, story.id);
|
||||
addStoryToMarkAsRead(readingAdapter.getStory(passedPosition));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
super.onPageSelected(position);
|
||||
Story story = readingAdapter.getStory(position);
|
||||
if (story != null) {
|
||||
markSocialAsReadList.add(story.feedId, story.id);
|
||||
addStoryToMarkAsRead(story);
|
||||
}
|
||||
addStoryToMarkAsRead(readingAdapter.getStory(position));
|
||||
checkStoryCount(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
new MarkSocialStoryAsReadTask(this, syncFragment, markSocialAsReadList).execute();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
public class MarkSocialAsReadUpdate {
|
||||
public String userId;
|
||||
HashMap<String, Set<String>> feedStoryMap;
|
||||
|
||||
public MarkSocialAsReadUpdate(final String userId) {
|
||||
this.userId = userId;
|
||||
feedStoryMap = new HashMap<String, Set<String>>();
|
||||
}
|
||||
|
||||
public void add(final String feedId, final String storyId) {
|
||||
if (feedStoryMap.get(feedId) == null) {
|
||||
Set<String> storiesForFeed = new HashSet<String>();
|
||||
storiesForFeed.add(storyId);
|
||||
feedStoryMap.put(feedId, storiesForFeed);
|
||||
} else {
|
||||
feedStoryMap.get(feedId).add(storyId);
|
||||
}
|
||||
}
|
||||
|
||||
public Object getJsonObject() {
|
||||
HashMap<String, HashMap<String, Set<String>>> jsonMap = new HashMap<String, HashMap<String, Set<String>>>();
|
||||
jsonMap.put(userId, feedStoryMap);
|
||||
return jsonMap;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void triggerRefresh() {
|
||||
triggerRefresh(0);
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
package com.newsblur.domain;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.newsblur.database.DatabaseConstants;
|
||||
|
||||
public class OfflineUpdate {
|
||||
|
||||
public int id;
|
||||
public UpdateType type;
|
||||
public String[] arguments;
|
||||
|
||||
public ContentValues getContentValues() {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(DatabaseConstants.UPDATE_ARGUMENTS, TextUtils.join(",", arguments));
|
||||
values.put(DatabaseConstants.UPDATE_TYPE, type.name());
|
||||
return values;
|
||||
}
|
||||
|
||||
public static OfflineUpdate fromCursor(final Cursor cursor) {
|
||||
OfflineUpdate update = new OfflineUpdate();
|
||||
update.arguments = TextUtils.split(cursor.getString(cursor.getColumnIndex(DatabaseConstants.UPDATE_ARGUMENTS)), ",");
|
||||
update.type = UpdateType.valueOf(cursor.getString(cursor.getColumnIndex(DatabaseConstants.UPDATE_TYPE)));
|
||||
update.id = cursor.getInt(cursor.getColumnIndex(DatabaseConstants.UPDATE_ID));
|
||||
return update;
|
||||
}
|
||||
|
||||
public static enum UpdateType { MARK_FEED_AS_READ };
|
||||
}
|
|
@ -178,4 +178,27 @@ public class Story implements Serializable {
|
|||
return score;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom equality based on storyID/feedID equality so that a Set can de-duplicate story objects.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == null) return false;
|
||||
if (!(o instanceof Story)) return false;
|
||||
Story s = (Story) o;
|
||||
return ( (this.id == null ? s.id == null : this.id.equals(s.id)) && (this.feedId == null ? s.feedId == null : this.feedId.equals(s.feedId)) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Per the contract of Object, since we redefined equals(), we have to redefine hashCode().
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 17;
|
||||
if (this.id == null) { result = 37*result; } else { result = 37*result + this.id.hashCode();}
|
||||
if (this.feedId == null) { result = 37*result; } else { result = 37*result + this.feedId.hashCode();}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,6 +12,9 @@ import android.text.TextUtils;
|
|||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
/**
|
||||
* This utility class is simply a Map<String,String> that serializes to JSON.
|
||||
*/
|
||||
public class ValueMultimap implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 3102965432185825759L;
|
||||
|
|
|
@ -39,7 +39,6 @@ import com.newsblur.database.FeedItemsAdapter;
|
|||
import com.newsblur.database.FeedProvider;
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.domain.Story;
|
||||
import com.newsblur.network.MarkStoryAsReadTask;
|
||||
import com.newsblur.util.FeedUtils;
|
||||
import com.newsblur.util.NetworkUtils;
|
||||
import com.newsblur.view.FeedItemViewBinder;
|
||||
|
@ -187,7 +186,8 @@ public class FeedItemListFragment extends ItemListFragment implements LoaderMana
|
|||
if(story.read == Story.UNREAD) {
|
||||
ArrayList<Story> storiesToMarkAsRead = new ArrayList<Story>();
|
||||
storiesToMarkAsRead.add(story);
|
||||
markStoriesRead(storiesToMarkAsRead);
|
||||
FeedUtils.markStoriesAsRead(storiesToMarkAsRead, getActivity());
|
||||
refreshStories();
|
||||
}
|
||||
} else if (item.getItemId() == R.id.menu_mark_previous_stories_as_read) {
|
||||
final ArrayList<Story> previousStories = adapter.getPreviousStories(menuInfo.position);
|
||||
|
@ -197,36 +197,12 @@ public class FeedItemListFragment extends ItemListFragment implements LoaderMana
|
|||
storiesToMarkAsRead.add(story);
|
||||
}
|
||||
}
|
||||
markStoriesRead(storiesToMarkAsRead);
|
||||
FeedUtils.markStoriesAsRead(storiesToMarkAsRead, getActivity());
|
||||
refreshStories();
|
||||
}
|
||||
return super.onContextItemSelected(item);
|
||||
}
|
||||
|
||||
private void markStoriesRead(final ArrayList<Story> storiesToMarkRead) {
|
||||
ArrayList<String> storyIdsToMarkRead = new ArrayList<String>();
|
||||
for(Story story: storiesToMarkRead) {
|
||||
storyIdsToMarkRead.add(story.id);
|
||||
}
|
||||
new MarkStoryAsReadTask(getActivity(), storyIdsToMarkRead, feedId) {
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Void result) {
|
||||
ArrayList<ContentProviderOperation> operations = new ArrayList<ContentProviderOperation>();
|
||||
for(Story story: storiesToMarkRead) {
|
||||
FeedUtils.appendStoryReadOperations(story, operations);
|
||||
}
|
||||
try {
|
||||
contentResolver.applyBatch(FeedProvider.AUTHORITY, operations);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Failed to update feed read status in local DB for " + storiesToMarkRead.size() + " stories");
|
||||
e.printStackTrace();
|
||||
}
|
||||
refreshStories();
|
||||
}
|
||||
|
||||
}.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||
ContextMenuInfo menuInfo) {
|
||||
|
|
|
@ -126,21 +126,6 @@ public class APIManager {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean markStoryAsRead(final String feedId, final ArrayList<String> storyIds) {
|
||||
final APIClient client = new APIClient(context);
|
||||
final ValueMultimap values = new ValueMultimap();
|
||||
values.put(APIConstants.PARAMETER_FEEDID, feedId);
|
||||
for (String storyId : storyIds) {
|
||||
values.put(APIConstants.PARAMETER_STORYID, storyId);
|
||||
}
|
||||
final APIResponse response = client.post(APIConstants.URL_MARK_STORY_AS_READ, values, false);
|
||||
if (!response.isOffline && response.responseCode == HttpStatus.SC_OK && !response.hasRedirected) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean markSocialStoryAsRead(final String updateJson) {
|
||||
final APIClient client = new APIClient(context);
|
||||
final ContentValues values = new ContentValues();
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
package com.newsblur.network;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import com.newsblur.domain.ValueMultimap;
|
||||
import com.newsblur.fragment.SyncUpdateFragment;
|
||||
import com.newsblur.service.SyncService;
|
||||
|
||||
public class MarkMixedStoriesAsReadTask extends AsyncTask<Void, Void, Void> {
|
||||
|
||||
private Context context;
|
||||
private SyncUpdateFragment receiver;
|
||||
private final ValueMultimap stories;
|
||||
|
||||
public MarkMixedStoriesAsReadTask(final Context context, final SyncUpdateFragment fragment, final ValueMultimap stories) {
|
||||
this.context = context;
|
||||
this.receiver = fragment;
|
||||
this.stories = stories;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
final Intent intent = new Intent(Intent.ACTION_SYNC, null, context, SyncService.class);
|
||||
intent.putExtra(SyncService.EXTRA_STATUS_RECEIVER, receiver.receiver);
|
||||
intent.putExtra(SyncService.SYNCSERVICE_TASK, SyncService.EXTRA_TASK_MARK_MULTIPLE_STORIES_READ);
|
||||
intent.putExtra(SyncService.EXTRA_TASK_STORIES, stories);
|
||||
context.startService(intent);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
package com.newsblur.network;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.newsblur.activity.SocialFeedReading.MarkSocialAsReadUpdate;
|
||||
import com.newsblur.domain.Story;
|
||||
import com.newsblur.fragment.SyncUpdateFragment;
|
||||
import com.newsblur.service.SyncService;
|
||||
|
||||
public class MarkSocialStoryAsReadTask extends AsyncTask<Story, Void, Void> {
|
||||
|
||||
private Context context;
|
||||
private SyncUpdateFragment receiver;
|
||||
private Gson gson;
|
||||
private final MarkSocialAsReadUpdate readUpdate;
|
||||
|
||||
public MarkSocialStoryAsReadTask(final Context context, final SyncUpdateFragment fragment, MarkSocialAsReadUpdate update) {
|
||||
this.context = context;
|
||||
this.receiver = fragment;
|
||||
this.readUpdate = update;
|
||||
|
||||
gson = new Gson();
|
||||
}
|
||||
|
||||
protected Void doInBackground(Story... params) {
|
||||
|
||||
final Intent intent = new Intent(Intent.ACTION_SYNC, null, context, SyncService.class);
|
||||
intent.putExtra(SyncService.EXTRA_STATUS_RECEIVER, receiver.receiver);
|
||||
intent.putExtra(SyncService.SYNCSERVICE_TASK, SyncService.EXTRA_TASK_MARK_SOCIALSTORY_READ);
|
||||
intent.putExtra(SyncService.EXTRA_TASK_MARK_SOCIAL_JSON, gson.toJson(readUpdate.getJsonObject()));
|
||||
context.startService(intent);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,44 +0,0 @@
|
|||
package com.newsblur.network;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import com.newsblur.fragment.SyncUpdateFragment;
|
||||
import com.newsblur.service.SyncService;
|
||||
|
||||
public class MarkStoryAsReadTask extends AsyncTask<Void, Void, Void> {
|
||||
|
||||
private Context context;
|
||||
private SyncUpdateFragment receiver;
|
||||
private final String feedId;
|
||||
private final ArrayList<String> storyIds;
|
||||
|
||||
public MarkStoryAsReadTask(final Context context, final ArrayList<String> storyIds, final String feedId) {
|
||||
this(context, null, storyIds, feedId);
|
||||
}
|
||||
|
||||
public MarkStoryAsReadTask(final Context context, final SyncUpdateFragment fragment, final ArrayList<String> storyIds, final String feedId) {
|
||||
this.context = context;
|
||||
this.receiver = fragment;
|
||||
this.storyIds = storyIds;
|
||||
this.feedId = feedId;
|
||||
}
|
||||
|
||||
protected Void doInBackground(Void... stories) {
|
||||
|
||||
final Intent intent = new Intent(Intent.ACTION_SYNC, null, context, SyncService.class);
|
||||
if(receiver != null) {
|
||||
intent.putExtra(SyncService.EXTRA_STATUS_RECEIVER, receiver.receiver);
|
||||
}
|
||||
intent.putExtra(SyncService.SYNCSERVICE_TASK, SyncService.EXTRA_TASK_MARK_STORY_READ);
|
||||
intent.putExtra(SyncService.EXTRA_TASK_FEED_ID, feedId);
|
||||
intent.putStringArrayListExtra(SyncService.EXTRA_TASK_STORY_ID, storyIds);
|
||||
context.startService(intent);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -17,7 +17,6 @@ import android.widget.Toast;
|
|||
import com.newsblur.R;
|
||||
import com.newsblur.database.DatabaseConstants;
|
||||
import com.newsblur.database.FeedProvider;
|
||||
import com.newsblur.domain.OfflineUpdate;
|
||||
import com.newsblur.domain.ValueMultimap;
|
||||
import com.newsblur.network.APIClient;
|
||||
import com.newsblur.network.APIConstants;
|
||||
|
@ -58,7 +57,6 @@ public class SyncService extends IntentService {
|
|||
public static final int EXTRA_TASK_FOLDER_UPDATE_TWO_STEP = 30;
|
||||
public static final int EXTRA_TASK_FOLDER_UPDATE_WITH_COUNT = 41;
|
||||
public static final int EXTRA_TASK_FEED_UPDATE = 31;
|
||||
public static final int EXTRA_TASK_MARK_STORY_READ = 33;
|
||||
public static final int EXTRA_TASK_SOCIALFEED_UPDATE = 34;
|
||||
public static final int EXTRA_TASK_MARK_SOCIALSTORY_READ = 35;
|
||||
public static final int EXTRA_TASK_MULTIFEED_UPDATE = 36;
|
||||
|
@ -114,38 +112,11 @@ public class SyncService extends IntentService {
|
|||
apiManager.getFolderFeedMapping(true);
|
||||
break;
|
||||
|
||||
case EXTRA_TASK_MARK_STORY_READ:
|
||||
final String feedId = intent.getStringExtra(EXTRA_TASK_FEED_ID);
|
||||
final ArrayList<String> storyIds = intent.getStringArrayListExtra(EXTRA_TASK_STORY_ID);
|
||||
if (!TextUtils.isEmpty(feedId) && storyIds.size() > 0) {
|
||||
if (!apiManager.markStoryAsRead(feedId, storyIds)) {
|
||||
for (String storyId : storyIds) {
|
||||
OfflineUpdate update = new OfflineUpdate();
|
||||
update.arguments = new String[] { feedId, storyId };
|
||||
update.type = OfflineUpdate.UpdateType.MARK_FEED_AS_READ;
|
||||
getContentResolver().insert(FeedProvider.OFFLINE_URI, update.getContentValues());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.e(this.getClass().getName(), "No feed/stories to mark as read included in SyncRequest");
|
||||
receiver.send(STATUS_ERROR, Bundle.EMPTY);
|
||||
}
|
||||
break;
|
||||
|
||||
case EXTRA_TASK_MARK_MULTIPLE_STORIES_READ:
|
||||
final ValueMultimap stories = (ValueMultimap) intent.getSerializableExtra(EXTRA_TASK_STORIES);
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(APIConstants.PARAMETER_FEEDS_STORIES, stories.getJsonString());
|
||||
if (!apiManager.markMultipleStoriesAsRead(values)) {
|
||||
for (String key : stories.getKeys()) {
|
||||
for (String value : stories.getValues(key)) {
|
||||
OfflineUpdate update = new OfflineUpdate();
|
||||
update.arguments = new String[] { key, value };
|
||||
update.type = OfflineUpdate.UpdateType.MARK_FEED_AS_READ;
|
||||
getContentResolver().insert(FeedProvider.OFFLINE_URI, update.getContentValues());
|
||||
}
|
||||
}
|
||||
}
|
||||
apiManager.markMultipleStoriesAsRead(values);
|
||||
break;
|
||||
|
||||
case EXTRA_TASK_MARK_SOCIALSTORY_READ:
|
||||
|
@ -258,19 +229,4 @@ public class SyncService extends IntentService {
|
|||
}
|
||||
}
|
||||
|
||||
/* TODO: this code existed in the refresh_feeds intent, but was never used. Now that
|
||||
we are actually using the API as intended, it is possible this needs to
|
||||
actually get called somewhere.
|
||||
Cursor cursor = getContentResolver().query(FeedProvider.OFFLINE_URI, null, null, null, null);
|
||||
while (cursor.moveToNext()) {
|
||||
OfflineUpdate update = OfflineUpdate.fromCursor(cursor);
|
||||
ArrayList<String> storyId = new ArrayList<String>();
|
||||
storyId.add(update.arguments[1]);
|
||||
if (apiManager.markStoryAsRead(update.arguments[0], storyId)) {
|
||||
getContentResolver().delete(FeedProvider.OFFLINE_URI, DatabaseConstants.UPDATE_ID + " = ?", new String[] { Integer.toString(update.id) });
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
*/
|
||||
|
||||
}
|
||||
|
|
|
@ -1,24 +1,36 @@
|
|||
package com.newsblur.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import android.content.ContentProviderOperation;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.newsblur.R;
|
||||
import com.newsblur.database.DatabaseConstants;
|
||||
import com.newsblur.database.FeedProvider;
|
||||
import com.newsblur.domain.Story;
|
||||
import com.newsblur.domain.ValueMultimap;
|
||||
import com.newsblur.network.APIManager;
|
||||
import com.newsblur.service.SyncService;
|
||||
|
||||
public class FeedUtils {
|
||||
|
||||
private static Gson gson = new Gson();
|
||||
|
||||
public static void saveStory(final Story story, final Context context, final APIManager apiManager) {
|
||||
if (story != null) {
|
||||
final String feedId = story.feedId;
|
||||
|
@ -42,7 +54,76 @@ public class FeedUtils {
|
|||
}
|
||||
}
|
||||
|
||||
public static void appendStoryReadOperations(Story story, ArrayList<ContentProviderOperation> operations) {
|
||||
/**
|
||||
* This utility method is a fast-returning way to mark as read a batch of stories in both
|
||||
* the local DB and on the server.
|
||||
*
|
||||
* TODO: the next version of the NB API will let us mark-as-read by a UUID, so we can
|
||||
* hopefully remove the ugly detection of social stories and their whole different
|
||||
* API call.
|
||||
*/
|
||||
public static void markStoriesAsRead( Collection<Story> stories, Context context ) {
|
||||
|
||||
// the map of non-social feedIds->storyIds to mark (auto-serializing)
|
||||
ValueMultimap storiesJson = new ValueMultimap();
|
||||
// the map of social userIds->feedIds->storyIds to mark
|
||||
Map<String, Map<String, Set<String>>> socialStories = new HashMap<String, Map<String, Set<String>>>();
|
||||
// a list of local DB ops to perform
|
||||
ArrayList<ContentProviderOperation> updateOps = new ArrayList<ContentProviderOperation>();
|
||||
|
||||
for (Story story : stories) {
|
||||
appendStoryReadOperations(story, updateOps);
|
||||
if (story.socialUserId != null) {
|
||||
// TODO: some stories returned by /social/river_stories seem to have neither a
|
||||
// socialUserId nor a sourceUserId, so they accidentally get submitted non-
|
||||
// socially. If the API fixes this before we ditch social-specific logic,
|
||||
// we can fix that bug right here.
|
||||
putMapHeirarchy(socialStories, story.socialUserId, story.feedId, story.id);
|
||||
} else {
|
||||
storiesJson.put(story.feedId, story.id);
|
||||
}
|
||||
}
|
||||
|
||||
// first, update unread counts in the local DB
|
||||
try {
|
||||
context.getContentResolver().applyBatch(FeedProvider.AUTHORITY, updateOps);
|
||||
} catch (Exception e) {
|
||||
Log.w(FeedUtils.class.getName(), "Could not update unread counts in local storage.", e);
|
||||
}
|
||||
|
||||
// next, update the server for normal stories
|
||||
if (storiesJson.size() > 0) {
|
||||
Intent intent = new Intent(Intent.ACTION_SYNC, null, context, SyncService.class);
|
||||
intent.putExtra(SyncService.SYNCSERVICE_TASK, SyncService.EXTRA_TASK_MARK_MULTIPLE_STORIES_READ);
|
||||
intent.putExtra(SyncService.EXTRA_TASK_STORIES, storiesJson);
|
||||
context.startService(intent);
|
||||
}
|
||||
|
||||
// finally, update the server for social stories
|
||||
if (socialStories.size() > 0) {
|
||||
Intent intent = new Intent(Intent.ACTION_SYNC, null, context, SyncService.class);
|
||||
intent.putExtra(SyncService.SYNCSERVICE_TASK, SyncService.EXTRA_TASK_MARK_SOCIALSTORY_READ);
|
||||
intent.putExtra(SyncService.EXTRA_TASK_MARK_SOCIAL_JSON, gson.toJson(socialStories));
|
||||
context.startService(intent);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility method to help populate the 3-level map structure that the NB API uses in JSON calls.
|
||||
*/
|
||||
private static void putMapHeirarchy(Map<String, Map<String, Set<String>>> map, String s1, String s2, String s3) {
|
||||
if (! map.containsKey(s1)) {
|
||||
map.put(s1, new HashMap<String, Set<String>>());
|
||||
}
|
||||
Map<String, Set<String>> innerMap = map.get(s1);
|
||||
if (! innerMap.containsKey(s2)) {
|
||||
innerMap.put(s2, new HashSet<String>());
|
||||
}
|
||||
innerMap.get(s2).add(s3);
|
||||
}
|
||||
|
||||
private static void appendStoryReadOperations(Story story, List<ContentProviderOperation> operations) {
|
||||
String[] selectionArgs;
|
||||
ContentValues emptyValues = new ContentValues();
|
||||
emptyValues.put(DatabaseConstants.FEED_ID, story.feedId);
|
||||
|
|
Loading…
Add table
Reference in a new issue