2014-06-04 13:46:10 -07:00
|
|
|
package com.newsblur.database;
|
|
|
|
|
|
2014-06-04 17:09:40 -07:00
|
|
|
import android.content.ContentValues;
|
2014-06-04 13:46:10 -07:00
|
|
|
import android.content.Context;
|
2014-07-27 00:39:40 -07:00
|
|
|
import android.content.Loader;
|
2014-06-04 17:09:40 -07:00
|
|
|
import android.database.Cursor;
|
|
|
|
|
import android.database.sqlite.SQLiteDatabase;
|
2014-06-05 04:04:14 -07:00
|
|
|
import android.text.TextUtils;
|
2014-06-05 15:51:29 -07:00
|
|
|
import android.util.Log;
|
2014-06-04 13:46:10 -07:00
|
|
|
|
2014-06-05 04:04:14 -07:00
|
|
|
import com.newsblur.domain.Classifier;
|
|
|
|
|
import com.newsblur.domain.Comment;
|
|
|
|
|
import com.newsblur.domain.Feed;
|
|
|
|
|
import com.newsblur.domain.FeedResult;
|
|
|
|
|
import com.newsblur.domain.Reply;
|
|
|
|
|
import com.newsblur.domain.SocialFeed;
|
|
|
|
|
import com.newsblur.domain.Story;
|
|
|
|
|
import com.newsblur.domain.UserProfile;
|
|
|
|
|
import com.newsblur.network.domain.StoriesResponse;
|
2014-06-04 13:46:10 -07:00
|
|
|
import com.newsblur.util.AppConstants;
|
2014-08-14 17:46:16 -07:00
|
|
|
import com.newsblur.util.FeedSet;
|
2014-07-10 15:11:43 -07:00
|
|
|
import com.newsblur.util.FeedUtils;
|
2014-08-14 17:46:16 -07:00
|
|
|
import com.newsblur.util.PrefsUtils;
|
|
|
|
|
import com.newsblur.util.ReadFilter;
|
|
|
|
|
import com.newsblur.util.StoryOrder;
|
2014-06-04 13:46:10 -07:00
|
|
|
|
2014-06-05 04:04:14 -07:00
|
|
|
import java.util.ArrayList;
|
2014-08-25 16:37:37 -07:00
|
|
|
import java.util.HashSet;
|
2014-06-04 17:09:40 -07:00
|
|
|
import java.util.List;
|
2014-07-28 15:41:17 -07:00
|
|
|
import java.util.Map;
|
2014-08-25 16:37:37 -07:00
|
|
|
import java.util.Set;
|
2014-06-04 17:09:40 -07:00
|
|
|
|
2014-06-04 13:46:10 -07:00
|
|
|
/**
|
|
|
|
|
* Utility class for executing DB operations on the local, private NB database.
|
|
|
|
|
*
|
|
|
|
|
* It is the intent of this class to be the single location of SQL executed on
|
|
|
|
|
* our DB, replacing the deprecated ContentProvider access pattern.
|
|
|
|
|
*/
|
|
|
|
|
public class BlurDatabaseHelper {
|
|
|
|
|
|
2014-07-27 00:39:40 -07:00
|
|
|
private Context context;
|
2014-06-04 17:09:40 -07:00
|
|
|
private BlurDatabase dbWrapper;
|
|
|
|
|
private SQLiteDatabase dbRO;
|
|
|
|
|
private SQLiteDatabase dbRW;
|
2014-06-04 13:46:10 -07:00
|
|
|
|
|
|
|
|
public BlurDatabaseHelper(Context context) {
|
2014-07-27 00:39:40 -07:00
|
|
|
this.context = context;
|
2014-06-04 17:09:40 -07:00
|
|
|
dbWrapper = new BlurDatabase(context);
|
|
|
|
|
dbRO = dbWrapper.getRO();
|
|
|
|
|
dbRW = dbWrapper.getRW();
|
2014-06-04 13:46:10 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void close() {
|
2014-06-04 17:09:40 -07:00
|
|
|
dbWrapper.close();
|
2014-06-04 13:46:10 -07:00
|
|
|
}
|
|
|
|
|
|
2014-09-05 15:02:25 -07:00
|
|
|
public boolean isOpen() {
|
|
|
|
|
return dbRW.isOpen();
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-30 19:58:04 -07:00
|
|
|
public void cleanupStories(boolean keepOldStories) {
|
2014-06-28 20:59:24 -07:00
|
|
|
String q1 = "SELECT " + DatabaseConstants.FEED_ID +
|
|
|
|
|
" FROM " + DatabaseConstants.FEED_TABLE;
|
|
|
|
|
Cursor c = dbRO.rawQuery(q1, null);
|
|
|
|
|
List<String> feedIds = new ArrayList<String>(c.getCount());
|
|
|
|
|
while (c.moveToNext()) {
|
|
|
|
|
feedIds.add(c.getString(c.getColumnIndexOrThrow(DatabaseConstants.FEED_ID)));
|
|
|
|
|
}
|
|
|
|
|
c.close();
|
|
|
|
|
for (String feedId : feedIds) {
|
|
|
|
|
String q = "DELETE FROM " + DatabaseConstants.STORY_TABLE +
|
|
|
|
|
" WHERE " + DatabaseConstants.STORY_ID + " IN " +
|
|
|
|
|
"( SELECT " + DatabaseConstants.STORY_ID + " FROM " + DatabaseConstants.STORY_TABLE +
|
2014-06-29 16:11:43 -07:00
|
|
|
" WHERE " + DatabaseConstants.STORY_READ + " = 1" +
|
|
|
|
|
" AND " + DatabaseConstants.STORY_FEED_ID + " = " + feedId +
|
2014-06-28 20:59:24 -07:00
|
|
|
" ORDER BY " + DatabaseConstants.STORY_TIMESTAMP + " DESC" +
|
2014-06-30 19:58:04 -07:00
|
|
|
" LIMIT -1 OFFSET " + (keepOldStories ? AppConstants.MAX_READ_STORIES_STORED : 0) +
|
2014-06-28 20:59:24 -07:00
|
|
|
")";
|
|
|
|
|
dbRW.execSQL(q);
|
|
|
|
|
}
|
2014-06-04 17:09:40 -07:00
|
|
|
}
|
|
|
|
|
|
2014-08-25 16:37:37 -07:00
|
|
|
public void cleanupActions() {
|
|
|
|
|
// TODO: write me, use me
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-04 17:09:40 -07:00
|
|
|
public void cleanupFeedsFolders() {
|
|
|
|
|
dbRW.delete(DatabaseConstants.FEED_TABLE, null, null);
|
|
|
|
|
dbRW.delete(DatabaseConstants.FOLDER_TABLE, null, null);
|
|
|
|
|
dbRW.delete(DatabaseConstants.FEED_FOLDER_MAP_TABLE, null, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void bulkInsertValues(String table, List<ContentValues> valuesList) {
|
2014-06-05 04:04:14 -07:00
|
|
|
if (valuesList.size() < 1) return;
|
2014-06-04 17:09:40 -07:00
|
|
|
dbRW.beginTransaction();
|
|
|
|
|
try {
|
|
|
|
|
for(ContentValues values: valuesList) {
|
|
|
|
|
dbRW.insertWithOnConflict(table, null, values, SQLiteDatabase.CONFLICT_REPLACE);
|
|
|
|
|
}
|
|
|
|
|
dbRW.setTransactionSuccessful();
|
|
|
|
|
} finally {
|
|
|
|
|
dbRW.endTransaction();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void insertFeedsFolders(List<ContentValues> feedValues,
|
|
|
|
|
List<ContentValues> folderValues,
|
|
|
|
|
List<ContentValues> ffmValues,
|
|
|
|
|
List<ContentValues> socialFeedValues) {
|
|
|
|
|
bulkInsertValues(DatabaseConstants.FEED_TABLE, feedValues);
|
|
|
|
|
bulkInsertValues(DatabaseConstants.FOLDER_TABLE, folderValues);
|
|
|
|
|
bulkInsertValues(DatabaseConstants.FEED_FOLDER_MAP_TABLE, ffmValues);
|
|
|
|
|
bulkInsertValues(DatabaseConstants.SOCIALFEED_TABLE, socialFeedValues);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void updateStarredStoriesCount(int count) {
|
|
|
|
|
ContentValues values = new ContentValues();
|
|
|
|
|
values.put(DatabaseConstants.STARRED_STORY_COUNT_COUNT, count);
|
|
|
|
|
// this DB just has one row and one column. blow it away and replace it.
|
|
|
|
|
dbRW.delete(DatabaseConstants.STARRED_STORY_COUNT_TABLE, null, null);
|
|
|
|
|
dbRW.insert(DatabaseConstants.STARRED_STORY_COUNT_TABLE, null, values);
|
2014-06-04 13:46:10 -07:00
|
|
|
}
|
2014-06-05 04:04:14 -07:00
|
|
|
|
|
|
|
|
public List<String> getStoryHashesForFeed(String feedId) {
|
|
|
|
|
String q = "SELECT " + DatabaseConstants.STORY_HASH +
|
|
|
|
|
" FROM " + DatabaseConstants.STORY_TABLE +
|
|
|
|
|
" WHERE " + DatabaseConstants.STORY_FEED_ID + " = ?";
|
|
|
|
|
Cursor c = dbRO.rawQuery(q, new String[]{feedId});
|
|
|
|
|
List<String> hashes = new ArrayList<String>(c.getCount());
|
|
|
|
|
while (c.moveToNext()) {
|
|
|
|
|
hashes.add(c.getString(c.getColumnIndexOrThrow(DatabaseConstants.STORY_HASH)));
|
|
|
|
|
}
|
|
|
|
|
c.close();
|
|
|
|
|
return hashes;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-05 15:51:29 -07:00
|
|
|
public List<String> getUnreadStoryHashes() {
|
|
|
|
|
String q = "SELECT " + DatabaseConstants.STORY_HASH +
|
|
|
|
|
" FROM " + DatabaseConstants.STORY_TABLE +
|
|
|
|
|
" WHERE " + DatabaseConstants.STORY_READ + " = 0" ;
|
|
|
|
|
Cursor c = dbRO.rawQuery(q, null);
|
|
|
|
|
List<String> hashes = new ArrayList<String>(c.getCount());
|
|
|
|
|
while (c.moveToNext()) {
|
|
|
|
|
hashes.add(c.getString(c.getColumnIndexOrThrow(DatabaseConstants.STORY_HASH)));
|
|
|
|
|
}
|
|
|
|
|
c.close();
|
|
|
|
|
return hashes;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-05 04:04:14 -07:00
|
|
|
public void insertStories(StoriesResponse apiResponse) {
|
2014-07-05 16:21:41 -07:00
|
|
|
// to insert classifiers, we need to determine the feed ID of the stories in this
|
|
|
|
|
// response, so sniff one out.
|
|
|
|
|
String impliedFeedId = null;
|
|
|
|
|
|
2014-06-05 04:04:14 -07:00
|
|
|
// handle users
|
2014-07-13 19:32:40 -07:00
|
|
|
if (apiResponse.users != null) {
|
|
|
|
|
List<ContentValues> userValues = new ArrayList<ContentValues>(apiResponse.users.length);
|
|
|
|
|
for (UserProfile user : apiResponse.users) {
|
|
|
|
|
userValues.add(user.getValues());
|
|
|
|
|
}
|
|
|
|
|
bulkInsertValues(DatabaseConstants.USER_TABLE, userValues);
|
2014-06-05 04:04:14 -07:00
|
|
|
}
|
|
|
|
|
|
2014-07-08 18:08:36 -07:00
|
|
|
// handle supplemental feed data that may have been included (usually in social requests)
|
2014-07-09 17:01:09 -07:00
|
|
|
if (apiResponse.feeds != null) {
|
2014-07-27 00:39:40 -07:00
|
|
|
List<ContentValues> feedValues = new ArrayList<ContentValues>(apiResponse.feeds.size());
|
2014-07-09 17:01:09 -07:00
|
|
|
for (Feed feed : apiResponse.feeds) {
|
|
|
|
|
feedValues.add(feed.getValues());
|
|
|
|
|
}
|
|
|
|
|
bulkInsertValues(DatabaseConstants.FEED_TABLE, feedValues);
|
2014-07-08 18:08:36 -07:00
|
|
|
}
|
|
|
|
|
|
2014-06-05 04:04:14 -07:00
|
|
|
// handle story content
|
|
|
|
|
List<ContentValues> storyValues = new ArrayList<ContentValues>(apiResponse.stories.length);
|
2014-07-08 18:08:36 -07:00
|
|
|
List<ContentValues> socialStoryValues = new ArrayList<ContentValues>();
|
2014-06-05 04:04:14 -07:00
|
|
|
for (Story story : apiResponse.stories) {
|
2014-07-08 18:08:36 -07:00
|
|
|
ContentValues values = story.getValues();
|
|
|
|
|
// the basic columns are fine for the stories table
|
|
|
|
|
storyValues.add(values);
|
|
|
|
|
// if a story was shared by a user, also insert it into the social table under their userid, too
|
|
|
|
|
for (String sharedUserId : story.sharedUserIds) {
|
2014-07-09 17:01:09 -07:00
|
|
|
ContentValues socialValues = new ContentValues();
|
|
|
|
|
socialValues.put(DatabaseConstants.SOCIALFEED_STORY_USER_ID, sharedUserId);
|
|
|
|
|
socialValues.put(DatabaseConstants.SOCIALFEED_STORY_STORYID, values.getAsString(DatabaseConstants.STORY_ID));
|
|
|
|
|
socialStoryValues.add(socialValues);
|
2014-07-08 18:08:36 -07:00
|
|
|
}
|
2014-07-05 16:21:41 -07:00
|
|
|
impliedFeedId = story.feedId;
|
2014-06-05 04:04:14 -07:00
|
|
|
}
|
|
|
|
|
bulkInsertValues(DatabaseConstants.STORY_TABLE, storyValues);
|
2014-07-09 17:01:09 -07:00
|
|
|
bulkInsertValues(DatabaseConstants.SOCIALFEED_STORY_MAP_TABLE, socialStoryValues);
|
2014-07-05 16:21:41 -07:00
|
|
|
|
|
|
|
|
// handle classifiers
|
|
|
|
|
if (apiResponse.classifiers != null) {
|
2014-07-28 15:41:17 -07:00
|
|
|
for (Map.Entry<String,Classifier> entry : apiResponse.classifiers.entrySet()) {
|
|
|
|
|
// the API might not have included a feed ID, in which case it deserialized as -1 and must be implied
|
|
|
|
|
String classifierFeedId = entry.getKey();
|
|
|
|
|
if (classifierFeedId.equals("-1")) {
|
|
|
|
|
classifierFeedId = impliedFeedId;
|
|
|
|
|
}
|
|
|
|
|
List<ContentValues> classifierValues = entry.getValue().getContentValues();
|
|
|
|
|
for (ContentValues values : classifierValues) {
|
|
|
|
|
values.put(DatabaseConstants.CLASSIFIER_ID, classifierFeedId);
|
|
|
|
|
}
|
|
|
|
|
dbRW.delete(DatabaseConstants.CLASSIFIER_TABLE, DatabaseConstants.CLASSIFIER_ID + " = ?", new String[] { classifierFeedId });
|
|
|
|
|
bulkInsertValues(DatabaseConstants.CLASSIFIER_TABLE, classifierValues);
|
2014-07-05 16:21:41 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-05 04:04:14 -07:00
|
|
|
// handle comments
|
|
|
|
|
List<ContentValues> commentValues = new ArrayList<ContentValues>();
|
|
|
|
|
List<ContentValues> replyValues = new ArrayList<ContentValues>();
|
|
|
|
|
for (Story story : apiResponse.stories) {
|
|
|
|
|
for (Comment comment : story.publicComments) {
|
|
|
|
|
comment.storyId = story.id;
|
|
|
|
|
comment.id = TextUtils.concat(story.id, story.feedId, comment.userId).toString();
|
|
|
|
|
commentValues.add(comment.getValues());
|
|
|
|
|
for (Reply reply : comment.replies) {
|
|
|
|
|
reply.commentId = comment.id;
|
|
|
|
|
replyValues.add(reply.getValues());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (Comment comment : story.friendsComments) {
|
|
|
|
|
comment.storyId = story.id;
|
|
|
|
|
comment.id = TextUtils.concat(story.id, story.feedId, comment.userId).toString();
|
|
|
|
|
commentValues.add(comment.getValues());
|
|
|
|
|
for (Reply reply : comment.replies) {
|
|
|
|
|
reply.commentId = comment.id;
|
|
|
|
|
replyValues.add(reply.getValues());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
bulkInsertValues(DatabaseConstants.COMMENT_TABLE, commentValues);
|
|
|
|
|
bulkInsertValues(DatabaseConstants.REPLY_TABLE, replyValues);
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-05 03:04:55 -07:00
|
|
|
public Set<String> getFeedsForFolder(String folderName) {
|
|
|
|
|
Set<String> feedIds = new HashSet<String>();
|
|
|
|
|
String q = "SELECT " + DatabaseConstants.FEED_FOLDER_FEED_ID +
|
|
|
|
|
" FROM " + DatabaseConstants.FEED_FOLDER_MAP_TABLE +
|
|
|
|
|
" WHERE " + DatabaseConstants.FEED_FOLDER_FOLDER_NAME + " = ?" ;
|
|
|
|
|
Cursor c = dbRO.rawQuery(q, new String[]{folderName});
|
|
|
|
|
while (c.moveToNext()) {
|
|
|
|
|
feedIds.add(c.getString(c.getColumnIndexOrThrow(DatabaseConstants.FEED_FOLDER_FEED_ID)));
|
|
|
|
|
}
|
|
|
|
|
c.close();
|
|
|
|
|
return feedIds;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-05 15:51:29 -07:00
|
|
|
public void markStoryHashesRead(List<String> hashes) {
|
|
|
|
|
// NOTE: attempting to wrap these updates in a transaction for speed makes them silently fail
|
|
|
|
|
for (String hash : hashes) {
|
2014-08-14 17:46:16 -07:00
|
|
|
setStoryReadState(hash, true);
|
2014-06-05 15:51:29 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-14 17:46:16 -07:00
|
|
|
public void setStoryReadState(String hash, boolean read) {
|
|
|
|
|
ContentValues values = new ContentValues();
|
|
|
|
|
values.put(DatabaseConstants.STORY_READ, read);
|
|
|
|
|
values.put(DatabaseConstants.STORY_READ_THIS_SESSION, read);
|
|
|
|
|
dbRW.update(DatabaseConstants.STORY_TABLE, values, DatabaseConstants.STORY_HASH + " = ?", new String[]{hash});
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-25 16:37:37 -07:00
|
|
|
/**
|
|
|
|
|
* Marks a story (un)read and also adjusts unread counts for it.
|
|
|
|
|
*/
|
|
|
|
|
public void setStoryReadState(Story story, boolean read) {
|
|
|
|
|
setStoryReadState(story.storyHash, read);
|
|
|
|
|
String incDec = read ? " - 1" : " + 1";
|
|
|
|
|
String column = DatabaseConstants.getFeedCountColumnForStoryIntelValue(story.getIntelligenceTotal());
|
|
|
|
|
// non-social feed count
|
|
|
|
|
StringBuilder q = new StringBuilder("UPDATE " + DatabaseConstants.FEED_TABLE);
|
|
|
|
|
q.append(" SET ").append(column).append(" = ").append(column).append(incDec);
|
|
|
|
|
q.append(" WHERE " + DatabaseConstants.FEED_ID + " = ").append(story.feedId);
|
|
|
|
|
dbRW.execSQL(q.toString());
|
|
|
|
|
// social feed counts
|
|
|
|
|
Set<String> socialIds = new HashSet<String>();
|
|
|
|
|
if (!TextUtils.isEmpty(story.socialUserId)) {
|
|
|
|
|
socialIds.add(story.socialUserId);
|
|
|
|
|
}
|
|
|
|
|
if (story.friendUserIds != null) {
|
|
|
|
|
for (String id : story.friendUserIds) {
|
|
|
|
|
socialIds.add(id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (String id : socialIds) {
|
|
|
|
|
column = DatabaseConstants.getFeedCountColumnForStoryIntelValue(story.getIntelligenceTotal());
|
|
|
|
|
q = new StringBuilder("UPDATE " + DatabaseConstants.SOCIALFEED_TABLE);
|
|
|
|
|
q.append(" SET ").append(column).append(" = ").append(column).append(incDec);
|
|
|
|
|
q.append(" WHERE " + DatabaseConstants.SOCIAL_FEED_ID + " = ").append(id);
|
|
|
|
|
dbRW.execSQL(q.toString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-05 03:04:55 -07:00
|
|
|
public void markFeedsRead(FeedSet fs, Long olderThan, Long newerThan) {
|
|
|
|
|
// TODO: impl at least the older/newer than cases
|
|
|
|
|
|
|
|
|
|
// TODO: stories
|
|
|
|
|
|
|
|
|
|
// feed counts
|
|
|
|
|
if (fs.isAllNormal()) {
|
|
|
|
|
setFeedUnreadCount(0, null, null);
|
|
|
|
|
} else if (fs.isAllSocial()) {
|
|
|
|
|
// TODO: oddly, the client never supported this before, so there is no button to invoke it. The API call
|
|
|
|
|
// works, though, so adding an impl. here should let us enable the button.
|
|
|
|
|
} else if (fs.getMultipleFeeds() != null) {
|
|
|
|
|
for (String feedId : fs.getMultipleFeeds()) {
|
|
|
|
|
setFeedUnreadCount(0, DatabaseConstants.FEED_ID + " = ?", new String[]{feedId});
|
|
|
|
|
}
|
|
|
|
|
} else if (fs.getSingleFeed() != null) {
|
|
|
|
|
setFeedUnreadCount(0, DatabaseConstants.FEED_ID + " = ?", new String[]{fs.getSingleFeed()});
|
|
|
|
|
} else if (fs.getSingleSocialFeed() != null) {
|
|
|
|
|
setSocialFeedUnreadCount(0, DatabaseConstants.SOCIAL_FEED_ID + " = ?", new String[]{fs.getSingleSocialFeed().getKey()});
|
|
|
|
|
} else {
|
|
|
|
|
throw new IllegalStateException("Asked to get stories for FeedSet of unknown type.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void setFeedUnreadCount(int count, String whereClause, String[] whereArgs) {
|
|
|
|
|
ContentValues values = new ContentValues();
|
|
|
|
|
values.put(DatabaseConstants.FEED_NEGATIVE_COUNT, count);
|
|
|
|
|
values.put(DatabaseConstants.FEED_NEUTRAL_COUNT, count);
|
|
|
|
|
values.put(DatabaseConstants.FEED_POSITIVE_COUNT, count);
|
|
|
|
|
dbRW.update(DatabaseConstants.FEED_TABLE, values, whereClause, whereArgs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void setSocialFeedUnreadCount(int count, String whereClause, String[] whereArgs) {
|
|
|
|
|
ContentValues values = new ContentValues();
|
|
|
|
|
values.put(DatabaseConstants.SOCIAL_FEED_NEGATIVE_COUNT, count);
|
|
|
|
|
values.put(DatabaseConstants.SOCIAL_FEED_NEUTRAL_COUNT, count);
|
|
|
|
|
values.put(DatabaseConstants.SOCIAL_FEED_POSITIVE_COUNT, count);
|
|
|
|
|
dbRW.update(DatabaseConstants.SOCIALFEED_TABLE, values, whereClause, whereArgs);
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-25 16:37:37 -07:00
|
|
|
public void enqueueActionStoryRead(String hash, boolean read) {
|
|
|
|
|
ContentValues values = new ContentValues();
|
|
|
|
|
values.put(DatabaseConstants.ACTION_TIME, System.currentTimeMillis());
|
|
|
|
|
values.put(DatabaseConstants.ACTION_STORY_HASH, hash);
|
|
|
|
|
values.put(read ? DatabaseConstants.ACTION_MARK_READ : DatabaseConstants.ACTION_MARK_UNREAD, 1);
|
|
|
|
|
dbRW.insertOrThrow(DatabaseConstants.ACTION_TABLE, null, values);
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-05 03:04:55 -07:00
|
|
|
public void enqueueActionFeedRead(FeedSet fs, Long olderThan, Long newerThan) {
|
|
|
|
|
ContentValues values = new ContentValues();
|
|
|
|
|
values.put(DatabaseConstants.ACTION_TIME, System.currentTimeMillis());
|
|
|
|
|
values.put(DatabaseConstants.ACTION_MARK_READ, 1);
|
|
|
|
|
values.put(DatabaseConstants.ACTION_FEED_ID, TextUtils.join(",", fs.getFeedIds()));
|
|
|
|
|
if (olderThan != null) values.put(DatabaseConstants.ACTION_INCLUDE_OLDER, olderThan);
|
|
|
|
|
if (newerThan != null) values.put(DatabaseConstants.ACTION_INCLUDE_NEWER, newerThan);
|
|
|
|
|
dbRW.insertOrThrow(DatabaseConstants.ACTION_TABLE, null, values);
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-25 16:37:37 -07:00
|
|
|
public Cursor getActions(boolean includeDone) {
|
|
|
|
|
String q = "SELECT * FROM " + DatabaseConstants.ACTION_TABLE +
|
|
|
|
|
" WHERE " + DatabaseConstants.ACTION_DONE_REMOTE + " = " + (includeDone ? 1 : 0);
|
|
|
|
|
return dbRO.rawQuery(q, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setActionDone(String actionId) {
|
|
|
|
|
ContentValues values = new ContentValues();
|
|
|
|
|
values.put(DatabaseConstants.ACTION_DONE_REMOTE, 1);
|
|
|
|
|
dbRW.update(DatabaseConstants.ACTION_TABLE, values, DatabaseConstants.ACTION_ID + " = ?", new String[]{actionId});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void clearAction(String actionId) {
|
|
|
|
|
dbRW.delete(DatabaseConstants.ACTION_TABLE, DatabaseConstants.ACTION_ID + " = ?", new String[]{actionId});
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-10 15:11:43 -07:00
|
|
|
public int getFeedUnreadCount(String feedId, int readingState) {
|
|
|
|
|
// calculate the unread count both from the feeds table and the stories table. If
|
|
|
|
|
// they disagree, use the maximum value seen.
|
|
|
|
|
int countFromFeedsTable = 0;
|
|
|
|
|
int countFromStoriesTable = 0;
|
|
|
|
|
|
|
|
|
|
// note we have to select the whole story object so we can get all they flavours of unread count and do math on them
|
|
|
|
|
String q1 = "SELECT " + TextUtils.join(",", DatabaseConstants.FEED_COLUMNS) +
|
|
|
|
|
" FROM " + DatabaseConstants.FEED_TABLE +
|
|
|
|
|
" WHERE " + DatabaseConstants.FEED_ID + "= ?";
|
|
|
|
|
Cursor c1 = dbRO.rawQuery(q1, new String[]{feedId});
|
|
|
|
|
if (c1.getCount() > 0) {
|
|
|
|
|
Feed feed = Feed.fromCursor(c1);
|
|
|
|
|
countFromFeedsTable = FeedUtils.getFeedUnreadCount(feed, readingState);
|
|
|
|
|
}
|
|
|
|
|
c1.close();
|
|
|
|
|
|
|
|
|
|
// note we can't select count(*) because the actual story state columns are virtual
|
|
|
|
|
String q2 = "SELECT " + TextUtils.join(",", DatabaseConstants.STORY_COLUMNS) + " FROM " + DatabaseConstants.STORY_TABLE +
|
|
|
|
|
" WHERE " + DatabaseConstants.STORY_FEED_ID + "= ?" +
|
|
|
|
|
" AND " + DatabaseConstants.getStorySelectionFromState(readingState) +
|
|
|
|
|
" AND " + DatabaseConstants.STORY_READ + " = 0";
|
|
|
|
|
Cursor c2 = dbRO.rawQuery(q2, new String[]{feedId});
|
|
|
|
|
countFromStoriesTable = c2.getCount();
|
|
|
|
|
c2.close();
|
|
|
|
|
|
|
|
|
|
return Math.max(countFromFeedsTable, countFromStoriesTable);
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-25 16:37:37 -07:00
|
|
|
public Cursor getStory(String hash) {
|
|
|
|
|
String q = "SELECT * FROM " + DatabaseConstants.STORY_TABLE +
|
|
|
|
|
" WHERE " + DatabaseConstants.STORY_HASH + " = ?";
|
|
|
|
|
return dbRO.rawQuery(q, new String[]{hash});
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-14 17:46:16 -07:00
|
|
|
/**
|
|
|
|
|
* Clears the read_this_session flag for all stories so they will be counted as not-unread.
|
|
|
|
|
*/
|
|
|
|
|
public void clearReadingSession() {
|
|
|
|
|
ContentValues values = new ContentValues();
|
|
|
|
|
values.put(DatabaseConstants.STORY_READ_THIS_SESSION, false);
|
|
|
|
|
dbRW.update(DatabaseConstants.STORY_TABLE, values, null, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Loader<Cursor> getStoriesLoader(final FeedSet fs, final int stateFilter) {
|
2014-07-27 00:39:40 -07:00
|
|
|
return new QueryCursorLoader(context) {
|
2014-08-14 17:46:16 -07:00
|
|
|
protected Cursor createCursor() {return getStoriesCursor(fs, stateFilter);}
|
2014-07-27 00:39:40 -07:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-14 17:46:16 -07:00
|
|
|
public Cursor getStoriesCursor(FeedSet fs, int stateFilter) {
|
|
|
|
|
StoryOrder order = PrefsUtils.getStoryOrder(context, fs);
|
|
|
|
|
ReadFilter readFilter = PrefsUtils.getReadFilter(context, fs);
|
|
|
|
|
|
|
|
|
|
if (fs.getSingleFeed() != null) {
|
|
|
|
|
|
|
|
|
|
StringBuilder q = new StringBuilder("SELECT ");
|
|
|
|
|
q.append(TextUtils.join(",", DatabaseConstants.STORY_COLUMNS));
|
|
|
|
|
q.append(" FROM " + DatabaseConstants.STORY_TABLE);
|
|
|
|
|
q.append(" WHERE " + DatabaseConstants.STORY_FEED_ID + " = ?");
|
|
|
|
|
DatabaseConstants.appendStorySelectionGroupOrder(q, readFilter, order, stateFilter, null);
|
|
|
|
|
return dbRO.rawQuery(q.toString(), new String[]{fs.getSingleFeed()});
|
|
|
|
|
|
|
|
|
|
} else if (fs.getMultipleFeeds() != null) {
|
|
|
|
|
|
|
|
|
|
StringBuilder q = new StringBuilder(DatabaseConstants.MULTIFEED_STORIES_QUERY_BASE);
|
|
|
|
|
q.append(" FROM " + DatabaseConstants.STORY_TABLE);
|
|
|
|
|
q.append(DatabaseConstants.JOIN_FEEDS_ON_STORIES);
|
|
|
|
|
q.append(" WHERE " + DatabaseConstants.STORY_TABLE + "." + DatabaseConstants.STORY_FEED_ID + " IN ( ");
|
|
|
|
|
q.append(TextUtils.join(",", fs.getMultipleFeeds()) + ")");
|
|
|
|
|
DatabaseConstants.appendStorySelectionGroupOrder(q, readFilter, order, stateFilter, null);
|
|
|
|
|
return dbRO.rawQuery(q.toString(), null);
|
|
|
|
|
|
|
|
|
|
} else if (fs.getSingleSocialFeed() != null) {
|
|
|
|
|
|
|
|
|
|
StringBuilder q = new StringBuilder(DatabaseConstants.MULTIFEED_STORIES_QUERY_BASE);
|
|
|
|
|
q.append(" FROM " + DatabaseConstants.SOCIALFEED_STORY_MAP_TABLE);
|
|
|
|
|
q.append(DatabaseConstants.JOIN_STORIES_ON_SOCIALFEED_MAP);
|
|
|
|
|
q.append(DatabaseConstants.JOIN_FEEDS_ON_STORIES);
|
|
|
|
|
q.append(" WHERE " + DatabaseConstants.SOCIALFEED_STORY_MAP_TABLE + "." + DatabaseConstants.SOCIALFEED_STORY_USER_ID + " = ? ");
|
|
|
|
|
DatabaseConstants.appendStorySelectionGroupOrder(q, readFilter, order, stateFilter, null);
|
|
|
|
|
return dbRO.rawQuery(q.toString(), new String[]{fs.getSingleSocialFeed().getKey()});
|
|
|
|
|
|
|
|
|
|
} else if (fs.isAllNormal()) {
|
|
|
|
|
|
|
|
|
|
StringBuilder q = new StringBuilder(DatabaseConstants.MULTIFEED_STORIES_QUERY_BASE);
|
|
|
|
|
q.append(" FROM " + DatabaseConstants.STORY_TABLE);
|
|
|
|
|
q.append(DatabaseConstants.JOIN_FEEDS_ON_STORIES);
|
|
|
|
|
q.append(" WHERE 1");
|
|
|
|
|
DatabaseConstants.appendStorySelectionGroupOrder(q, readFilter, order, stateFilter, null);
|
|
|
|
|
return dbRO.rawQuery(q.toString(), null);
|
|
|
|
|
|
|
|
|
|
} else if (fs.isAllSocial()) {
|
|
|
|
|
|
|
|
|
|
StringBuilder q = new StringBuilder(DatabaseConstants.MULTIFEED_STORIES_QUERY_BASE);
|
|
|
|
|
q.append(" FROM " + DatabaseConstants.SOCIALFEED_STORY_MAP_TABLE);
|
|
|
|
|
q.append(DatabaseConstants.JOIN_STORIES_ON_SOCIALFEED_MAP);
|
|
|
|
|
q.append(DatabaseConstants.JOIN_FEEDS_ON_STORIES);
|
|
|
|
|
DatabaseConstants.appendStorySelectionGroupOrder(q, readFilter, order, stateFilter, DatabaseConstants.STORY_TABLE + "." + DatabaseConstants.STORY_ID);
|
|
|
|
|
return dbRO.rawQuery(q.toString(), null);
|
|
|
|
|
|
|
|
|
|
} else if (fs.isAllSaved()) {
|
|
|
|
|
|
|
|
|
|
StringBuilder q = new StringBuilder(DatabaseConstants.MULTIFEED_STORIES_QUERY_BASE);
|
|
|
|
|
q.append(" FROM " + DatabaseConstants.STORY_TABLE);
|
|
|
|
|
q.append(DatabaseConstants.JOIN_FEEDS_ON_STORIES);
|
|
|
|
|
q.append(" WHERE " + DatabaseConstants.STORY_STARRED + " = 1");
|
|
|
|
|
q.append(" ORDER BY " + DatabaseConstants.STARRED_STORY_ORDER);
|
|
|
|
|
return dbRO.rawQuery(q.toString(), null);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
throw new IllegalStateException("Asked to get stories for FeedSet of unknown type.");
|
|
|
|
|
}
|
2014-07-27 00:39:40 -07:00
|
|
|
}
|
|
|
|
|
|
2014-08-25 16:37:37 -07:00
|
|
|
public static void closeQuietly(Cursor c) {
|
|
|
|
|
if (c == null) return;
|
|
|
|
|
try {c.close();} catch (Exception e) {;}
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-04 13:46:10 -07:00
|
|
|
}
|