mirror of
https://github.com/viq/NewsBlur.git
synced 2025-09-18 21:43:31 +00:00
Complete unread recounting after reading sessions.
This commit is contained in:
parent
73136825ab
commit
90116ee45d
7 changed files with 149 additions and 1 deletions
|
@ -74,6 +74,7 @@ public class Main extends NbActivity implements StateChangedListener, SwipeRefre
|
|||
super.onResume();
|
||||
|
||||
NBSyncService.clearPendingStoryRequest();
|
||||
NBSyncService.flushRecounts();
|
||||
NBSyncService.setActivationMode(NBSyncService.ActivationMode.ALL);
|
||||
FeedUtils.activateAllStories();
|
||||
FeedUtils.clearReadingSession();
|
||||
|
|
|
@ -529,6 +529,14 @@ public class BlurDatabaseHelper {
|
|||
return result;
|
||||
}
|
||||
|
||||
public void updateFeedCounts(String feedId, ContentValues values) {
|
||||
synchronized (RW_MUTEX) {dbRW.update(DatabaseConstants.FEED_TABLE, values, DatabaseConstants.FEED_ID + " = ?", new String[]{feedId});}
|
||||
}
|
||||
|
||||
public void updateSocialFeedCounts(String feedId, ContentValues values) {
|
||||
synchronized (RW_MUTEX) {dbRW.update(DatabaseConstants.SOCIALFEED_TABLE, values, DatabaseConstants.SOCIAL_FEED_ID + " = ?", new String[]{feedId});}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the counts in the feeds/socialfeeds tables by counting stories in the story table.
|
||||
*/
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.Date;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
|
@ -37,6 +38,7 @@ import com.newsblur.network.domain.ProfileResponse;
|
|||
import com.newsblur.network.domain.RegisterResponse;
|
||||
import com.newsblur.network.domain.StoriesResponse;
|
||||
import com.newsblur.network.domain.StoryTextResponse;
|
||||
import com.newsblur.network.domain.UnreadCountResponse;
|
||||
import com.newsblur.network.domain.UnreadStoryHashesResponse;
|
||||
import com.newsblur.serialization.BooleanTypeAdapter;
|
||||
import com.newsblur.serialization.ClassifierMapTypeAdapter;
|
||||
|
@ -243,6 +245,15 @@ public class APIManager {
|
|||
}
|
||||
}
|
||||
|
||||
public UnreadCountResponse getFeedUnreadCounts(Set<String> apiIds) {
|
||||
ValueMultimap values = new ValueMultimap();
|
||||
for (String id : apiIds) {
|
||||
values.put(APIConstants.PARAMETER_FEEDID, id);
|
||||
}
|
||||
APIResponse response = get(APIConstants.URL_FEED_UNREAD_COUNT, values);
|
||||
return (UnreadCountResponse) response.getResponse(gson, UnreadCountResponse.class);
|
||||
}
|
||||
|
||||
public UnreadStoryHashesResponse getUnreadStoryHashes() {
|
||||
ValueMultimap values = new ValueMultimap();
|
||||
values.put(APIConstants.PARAMETER_INCLUDE_TIMESTAMPS, "1");
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package com.newsblur.network.domain;
|
||||
|
||||
import android.content.ContentValues;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import com.newsblur.database.DatabaseConstants;
|
||||
|
||||
public class UnreadCountResponse extends NewsBlurResponse {
|
||||
|
||||
@SerializedName("feeds")
|
||||
public Map<String,UnreadMD> feeds;
|
||||
|
||||
@SerializedName("social_feeds")
|
||||
public Map<String,UnreadMD> socialFeeds;
|
||||
|
||||
public class UnreadMD {
|
||||
|
||||
public int ps;
|
||||
public int nt;
|
||||
public int ng;
|
||||
|
||||
public ContentValues getValues() {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(DatabaseConstants.FEED_POSITIVE_COUNT, ps);
|
||||
values.put(DatabaseConstants.FEED_NEUTRAL_COUNT, nt);
|
||||
values.put(DatabaseConstants.FEED_NEGATIVE_COUNT, ng);
|
||||
return values;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -20,10 +20,12 @@ import static com.newsblur.database.BlurDatabaseHelper.closeQuietly;
|
|||
import com.newsblur.database.DatabaseConstants;
|
||||
import com.newsblur.domain.SocialFeed;
|
||||
import com.newsblur.domain.Story;
|
||||
import com.newsblur.network.APIConstants;
|
||||
import com.newsblur.network.APIManager;
|
||||
import com.newsblur.network.domain.FeedFolderResponse;
|
||||
import com.newsblur.network.domain.NewsBlurResponse;
|
||||
import com.newsblur.network.domain.StoriesResponse;
|
||||
import com.newsblur.network.domain.UnreadCountResponse;
|
||||
import com.newsblur.network.domain.UnreadStoryHashesResponse;
|
||||
import com.newsblur.util.AppConstants;
|
||||
import com.newsblur.util.FeedSet;
|
||||
|
@ -76,6 +78,7 @@ public class NBSyncService extends Service {
|
|||
private volatile static boolean FFSyncRunning = false;
|
||||
private volatile static boolean StorySyncRunning = false;
|
||||
private volatile static boolean HousekeepingRunning = false;
|
||||
private volatile static boolean RecountsRunning = false;
|
||||
|
||||
private volatile static boolean DoFeedsFolders = false;
|
||||
private volatile static boolean DoUnreads = false;
|
||||
|
@ -108,6 +111,11 @@ public class NBSyncService extends Service {
|
|||
private static List<ReadingAction> FollowupActions;
|
||||
static { FollowupActions = new ArrayList<ReadingAction>(); }
|
||||
|
||||
/** Feed IDs (API stype) that have been acted upon and need a double-check for counts. */
|
||||
private static Set<FeedSet> RecountCandidates;
|
||||
static { RecountCandidates = new HashSet<FeedSet>(); }
|
||||
private volatile static boolean FlushRecounts = false;
|
||||
|
||||
Set<String> orphanFeedIds;
|
||||
|
||||
private ExecutorService primaryExecutor;
|
||||
|
@ -212,6 +220,8 @@ public class NBSyncService extends Service {
|
|||
|
||||
syncMetadata(startId);
|
||||
|
||||
checkRecounts();
|
||||
|
||||
unreadsService.start(startId);
|
||||
|
||||
imagePrefetchService.start(startId);
|
||||
|
@ -368,6 +378,7 @@ public class NBSyncService extends Service {
|
|||
FeedPagesSeen.clear();
|
||||
FeedStoriesSeen.clear();
|
||||
UnreadsService.clearHashes();
|
||||
RecountCandidates.clear();
|
||||
|
||||
FeedFolderResponse feedResponse = apiManager.getFolderFeedMapping(true);
|
||||
|
||||
|
@ -454,6 +465,58 @@ public class NBSyncService extends Service {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* See if any feeds have been touched in a way that require us to double-check unread counts;
|
||||
*/
|
||||
private void checkRecounts() {
|
||||
if (stopSync()) return;
|
||||
if (!FlushRecounts) return;
|
||||
|
||||
try {
|
||||
if (RecountCandidates.size() < 1) return;
|
||||
|
||||
RecountsRunning = true;
|
||||
NbActivity.updateAllActivities(false);
|
||||
|
||||
// if we are offline, the best we can do is perform a local unread recount and
|
||||
// save the true one for when we go back online.
|
||||
if (!NetworkUtils.isOnline(this)) {
|
||||
for (FeedSet fs : RecountCandidates) {
|
||||
dbHelper.updateLocalFeedCounts(fs);
|
||||
}
|
||||
} else {
|
||||
Set<String> apiIds = new HashSet<String>();
|
||||
for (FeedSet fs : RecountCandidates) {
|
||||
apiIds.addAll(fs.getFlatFeedIds());
|
||||
}
|
||||
Log.d(this.getClass().getName(), "IDs to check: " + apiIds);
|
||||
UnreadCountResponse apiResponse = apiManager.getFeedUnreadCounts(apiIds);
|
||||
if ((apiResponse == null) || (apiResponse.isError())) {
|
||||
Log.w(this.getClass().getName(), "Bad response to feed_unread_count");
|
||||
return;
|
||||
}
|
||||
if (apiResponse.feeds != null ) {
|
||||
for (Map.Entry<String,UnreadCountResponse.UnreadMD> entry : apiResponse.feeds.entrySet()) {
|
||||
dbHelper.updateFeedCounts(entry.getKey(), entry.getValue().getValues());
|
||||
}
|
||||
}
|
||||
if (apiResponse.socialFeeds != null ) {
|
||||
for (Map.Entry<String,UnreadCountResponse.UnreadMD> entry : apiResponse.socialFeeds.entrySet()) {
|
||||
String feedId = entry.getKey().replaceAll(APIConstants.VALUE_PREFIX_SOCIAL, "");
|
||||
dbHelper.updateSocialFeedCounts(feedId, entry.getValue().getValues());
|
||||
}
|
||||
}
|
||||
RecountCandidates.clear();
|
||||
}
|
||||
} finally {
|
||||
if (RecountsRunning) {
|
||||
RecountsRunning = false;
|
||||
NbActivity.updateAllActivities(false);
|
||||
}
|
||||
FlushRecounts = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch stories needed because the user is actively viewing a feed or folder.
|
||||
*/
|
||||
|
@ -626,6 +689,10 @@ public class NBSyncService extends Service {
|
|||
DoFeedsFolders = true;
|
||||
}
|
||||
|
||||
public static void flushRecounts() {
|
||||
FlushRecounts = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the service which stories can be activated if received. See ActivationMode.
|
||||
*/
|
||||
|
@ -695,6 +762,10 @@ public class NBSyncService extends Service {
|
|||
OriginalTextService.addHash(hash);
|
||||
}
|
||||
|
||||
public static void addRecountCandidates(Set<FeedSet> fs) {
|
||||
RecountCandidates.addAll(fs);
|
||||
}
|
||||
|
||||
public static void softInterrupt() {
|
||||
if (AppConstants.VERBOSE_LOG) Log.d(NBSyncService.class.getName(), "soft stop");
|
||||
HaltNow = true;
|
||||
|
|
|
@ -10,6 +10,8 @@ import java.util.Iterator;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.newsblur.network.APIConstants;
|
||||
|
||||
/**
|
||||
* A subset of one, several, or all NewsBlur feeds or social feeds. Used to encapsulate the
|
||||
* complexity of the fact that social feeds are special and requesting a river of feeds is not
|
||||
|
@ -195,6 +197,26 @@ public class FeedSet implements Serializable {
|
|||
return this.folderName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a flat set of feed IDs that can be passed to API calls that take raw numeric IDs or
|
||||
* social IDs prefixed with "social:". Returns an empty set for feed sets that don't track
|
||||
* unread counts or that are essentially "everything".
|
||||
*/
|
||||
public Set<String> getFlatFeedIds() {
|
||||
Set<String> result = new HashSet<String>();
|
||||
if (feeds != null) {
|
||||
for (String id : feeds) {
|
||||
result.add(id);
|
||||
}
|
||||
}
|
||||
if (socialFeeds != null) {
|
||||
for (Map.Entry<String,String> e : socialFeeds.entrySet()) {
|
||||
result.add(APIConstants.VALUE_PREFIX_SOCIAL + e.getKey());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static final String COM_SER_NUL = "NUL";
|
||||
|
||||
public String toCompactSerial() {
|
||||
|
|
|
@ -133,13 +133,14 @@ public class FeedUtils {
|
|||
story.read = read;
|
||||
|
||||
// update unread state and unread counts in the local DB
|
||||
dbHelper.setStoryReadState(story, read);
|
||||
Set<FeedSet> impactedFeeds = dbHelper.setStoryReadState(story, read);
|
||||
NbActivity.updateAllActivities();
|
||||
|
||||
// tell the sync service we need to mark read
|
||||
ReadingAction ra = (read ? ReadingAction.markStoryRead(story.storyHash) : ReadingAction.markStoryUnread(story.storyHash));
|
||||
dbHelper.enqueueAction(ra);
|
||||
triggerSync(context);
|
||||
NBSyncService.addRecountCandidates(impactedFeeds);
|
||||
}
|
||||
|
||||
public static void markFeedsRead(final FeedSet fs, final Long olderThan, final Long newerThan, final Context context) {
|
||||
|
|
Loading…
Add table
Reference in a new issue