mirror of
https://github.com/viq/NewsBlur.git
synced 2025-09-18 21:43:31 +00:00
Correctly handle folder heirarchies. (INCOMPLETE)
This commit is contained in:
parent
2d6f59a228
commit
bbd9385a3f
11 changed files with 188 additions and 201 deletions
|
@ -54,7 +54,7 @@ public class FolderItemsList extends ItemsList implements MarkAllReadDialogListe
|
|||
|
||||
@Override
|
||||
protected FeedSet createFeedSet() {
|
||||
return FeedSet.folder(this.folderName, FeedUtils.dbHelper.getFeedsForFolder(folderName));
|
||||
return FeedUtils.feedSetFromFolderName(this.folderName);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -24,7 +24,6 @@ public class BlurDatabase extends SQLiteOpenHelper {
|
|||
db.execSQL(DatabaseConstants.COMMENT_SQL);
|
||||
db.execSQL(DatabaseConstants.REPLY_SQL);
|
||||
db.execSQL(DatabaseConstants.CLASSIFIER_SQL);
|
||||
db.execSQL(DatabaseConstants.FEED_FOLDER_SQL);
|
||||
db.execSQL(DatabaseConstants.SOCIALFEED_STORIES_SQL);
|
||||
db.execSQL(DatabaseConstants.STARRED_STORIES_COUNT_SQL);
|
||||
db.execSQL(DatabaseConstants.ACTION_SQL);
|
||||
|
@ -42,7 +41,6 @@ public class BlurDatabase extends SQLiteOpenHelper {
|
|||
db.execSQL(drop + DatabaseConstants.COMMENT_TABLE);
|
||||
db.execSQL(drop + DatabaseConstants.REPLY_TABLE);
|
||||
db.execSQL(drop + DatabaseConstants.CLASSIFIER_TABLE);
|
||||
db.execSQL(drop + DatabaseConstants.FEED_FOLDER_MAP_TABLE);
|
||||
db.execSQL(drop + DatabaseConstants.SOCIALFEED_STORY_MAP_TABLE);
|
||||
db.execSQL(drop + DatabaseConstants.STARRED_STORY_COUNT_TABLE);
|
||||
db.execSQL(drop + DatabaseConstants.ACTION_TABLE);
|
||||
|
|
|
@ -15,7 +15,7 @@ import android.util.Log;
|
|||
import com.newsblur.domain.Classifier;
|
||||
import com.newsblur.domain.Comment;
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.domain.FeedResult;
|
||||
import com.newsblur.domain.Folder;
|
||||
import com.newsblur.domain.Reply;
|
||||
import com.newsblur.domain.SocialFeed;
|
||||
import com.newsblur.domain.Story;
|
||||
|
@ -136,7 +136,6 @@ public class BlurDatabaseHelper {
|
|||
public void cleanupFeedsFolders() {
|
||||
synchronized (RW_MUTEX) {dbRW.delete(DatabaseConstants.FEED_TABLE, null, null);}
|
||||
synchronized (RW_MUTEX) {dbRW.delete(DatabaseConstants.FOLDER_TABLE, null, null);}
|
||||
synchronized (RW_MUTEX) {dbRW.delete(DatabaseConstants.FEED_FOLDER_MAP_TABLE, null, null);}
|
||||
synchronized (RW_MUTEX) {dbRW.delete(DatabaseConstants.SOCIALFEED_TABLE, null, null);}
|
||||
}
|
||||
|
||||
|
@ -147,7 +146,6 @@ public class BlurDatabaseHelper {
|
|||
public void deleteFeed(String feedId) {
|
||||
String[] selArgs = new String[] {feedId};
|
||||
synchronized (RW_MUTEX) {dbRW.delete(DatabaseConstants.FEED_TABLE, DatabaseConstants.FEED_ID + " = ?", selArgs);}
|
||||
synchronized (RW_MUTEX) {dbRW.delete(DatabaseConstants.FEED_FOLDER_MAP_TABLE, DatabaseConstants.FEED_FOLDER_FEED_ID + " = ?", selArgs);}
|
||||
synchronized (RW_MUTEX) {dbRW.delete(DatabaseConstants.STORY_TABLE, DatabaseConstants.STORY_FEED_ID + " = ?", selArgs);}
|
||||
}
|
||||
|
||||
|
@ -166,13 +164,11 @@ public class BlurDatabaseHelper {
|
|||
}
|
||||
}
|
||||
|
||||
public void insertFeedsFolders(List<ContentValues> feedValues,
|
||||
List<ContentValues> folderValues,
|
||||
List<ContentValues> ffmValues,
|
||||
public void insertFeedsFolders(List<ContentValues> folderValues,
|
||||
List<ContentValues> feedValues,
|
||||
List<ContentValues> socialFeedValues) {
|
||||
bulkInsertValues(DatabaseConstants.FEED_TABLE, feedValues);
|
||||
bulkInsertValues(DatabaseConstants.FOLDER_TABLE, folderValues);
|
||||
bulkInsertValues(DatabaseConstants.FEED_FOLDER_MAP_TABLE, ffmValues);
|
||||
bulkInsertValues(DatabaseConstants.FEED_TABLE, feedValues);
|
||||
bulkInsertValues(DatabaseConstants.SOCIALFEED_TABLE, socialFeedValues);
|
||||
}
|
||||
|
||||
|
@ -336,17 +332,13 @@ public class BlurDatabaseHelper {
|
|||
bulkInsertValues(DatabaseConstants.REPLY_TABLE, replyValues);
|
||||
}
|
||||
|
||||
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;
|
||||
public Folder getFolder(String folderName) {
|
||||
String[] selArgs = new String[] {folderName};
|
||||
String selection = DatabaseConstants.FOLDER_NAME + " = ?";
|
||||
Cursor c = dbRO.query(DatabaseConstants.FOLDER_TABLE, null, selection, selArgs, null, null, null);
|
||||
Folder folder = Folder.fromCursor(c);
|
||||
closeQuietly(c);
|
||||
return folder;
|
||||
}
|
||||
|
||||
public void markStoryHashesRead(List<String> hashes) {
|
||||
|
@ -677,14 +669,14 @@ public class BlurDatabaseHelper {
|
|||
return query(false, DatabaseConstants.SOCIALFEED_TABLE, null, DatabaseConstants.getBlogSelectionFromState(stateFilter), null, null, null, "UPPER(" + DatabaseConstants.SOCIAL_FEED_TITLE + ") ASC", null, cancellationSignal);
|
||||
}
|
||||
|
||||
public Loader<Cursor> getFolderFeedMapLoader() {
|
||||
public Loader<Cursor> getFoldersLoader() {
|
||||
return new QueryCursorLoader(context) {
|
||||
protected Cursor createCursor() {return getFolderFeedMapCursor(cancellationSignal);}
|
||||
protected Cursor createCursor() {return getFoldersCursor(cancellationSignal);}
|
||||
};
|
||||
}
|
||||
|
||||
public Cursor getFolderFeedMapCursor(CancellationSignal cancellationSignal) {
|
||||
return query(false, DatabaseConstants.FEED_FOLDER_MAP_TABLE, null, null, null, null, null, null, null, cancellationSignal);
|
||||
public Cursor getFoldersCursor(CancellationSignal cancellationSignal) {
|
||||
return query(false, DatabaseConstants.FOLDER_TABLE, null, null, null, null, null, null, null, cancellationSignal);
|
||||
}
|
||||
|
||||
public Loader<Cursor> getFeedsLoader(final StateFilter stateFilter) {
|
||||
|
|
|
@ -15,8 +15,10 @@ public class DatabaseConstants {
|
|||
private static final String INTEGER = " INTEGER";
|
||||
|
||||
public static final String FOLDER_TABLE = "folders";
|
||||
public static final String FOLDER_ID = BaseColumns._ID;
|
||||
public static final String FOLDER_NAME = "folder_name";
|
||||
public static final String FOLDER_PARENT_NAMES = "folder_parent_names";
|
||||
public static final String FOLDER_CHILDREN_NAMES = "folder_children_names";
|
||||
public static final String FOLDER_FEED_IDS = "folder_feedids";
|
||||
|
||||
public static final String FEED_TABLE = "feeds";
|
||||
public static final String FEED_ID = BaseColumns._ID;
|
||||
|
@ -45,10 +47,6 @@ public class DatabaseConstants {
|
|||
public static final String SOCIAL_FEED_NEUTRAL_COUNT = "nt";
|
||||
public static final String SOCIAL_FEED_NEGATIVE_COUNT = "ng";
|
||||
|
||||
public static final String FEED_FOLDER_MAP_TABLE = "feed_folder_map";
|
||||
public static final String FEED_FOLDER_FEED_ID = "feed_feed_id";
|
||||
public static final String FEED_FOLDER_FOLDER_NAME = "feed_folder_name";
|
||||
|
||||
public static final String SOCIALFEED_STORY_MAP_TABLE = "socialfeed_story_map";
|
||||
public static final String SOCIALFEED_STORY_USER_ID = "socialfeed_story_user_id";
|
||||
public static final String SOCIALFEED_STORY_STORYID = "socialfeed_story_storyid";
|
||||
|
@ -139,8 +137,10 @@ public class DatabaseConstants {
|
|||
public static final String ACTION_INCLUDE_NEWER = "include_newer";
|
||||
|
||||
static final String FOLDER_SQL = "CREATE TABLE " + FOLDER_TABLE + " (" +
|
||||
FOLDER_ID + INTEGER + " PRIMARY KEY AUTOINCREMENT, " +
|
||||
FOLDER_NAME + TEXT + " UNIQUE " +
|
||||
FOLDER_NAME + TEXT + " PRIMARY KEY, " +
|
||||
FOLDER_PARENT_NAMES + TEXT + ", " +
|
||||
FOLDER_CHILDREN_NAMES + TEXT + ", " +
|
||||
FOLDER_FEED_IDS + TEXT +
|
||||
")";
|
||||
|
||||
static final String FEED_SQL = "CREATE TABLE " + FEED_TABLE + " (" +
|
||||
|
@ -245,12 +245,6 @@ public class DatabaseConstants {
|
|||
CLASSIFIER_VALUE + TEXT +
|
||||
")";
|
||||
|
||||
static final String FEED_FOLDER_SQL = "CREATE TABLE " + FEED_FOLDER_MAP_TABLE + " (" +
|
||||
FEED_FOLDER_FOLDER_NAME + TEXT + " NOT NULL, " +
|
||||
FEED_FOLDER_FEED_ID + INTEGER + " NOT NULL, " +
|
||||
"PRIMARY KEY (" + FEED_FOLDER_FOLDER_NAME + ", " + FEED_FOLDER_FEED_ID + ") " +
|
||||
")";
|
||||
|
||||
static final String SOCIALFEED_STORIES_SQL = "CREATE TABLE " + SOCIALFEED_STORY_MAP_TABLE + " (" +
|
||||
SOCIALFEED_STORY_STORYID + TEXT + " NOT NULL, " +
|
||||
SOCIALFEED_STORY_USER_ID + INTEGER + " NOT NULL, " +
|
||||
|
|
|
@ -30,6 +30,7 @@ import com.newsblur.activity.GlobalSharedStoriesItemsList;
|
|||
import com.newsblur.activity.NewsBlurApplication;
|
||||
import static com.newsblur.database.DatabaseConstants.getStr;
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.domain.Folder;
|
||||
import com.newsblur.domain.SocialFeed;
|
||||
import com.newsblur.util.AppConstants;
|
||||
import com.newsblur.util.ImageLoader;
|
||||
|
@ -48,7 +49,7 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
|||
|
||||
private Cursor socialFeedCursor;
|
||||
|
||||
private Map<String,List<String>> folderFeedMap = Collections.emptyMap();
|
||||
private Map<String,Folder> folders = Collections.emptyMap();
|
||||
private List<String> activeFolderNames;
|
||||
private List<List<Feed>> activeFolderChildren;
|
||||
private List<Integer> neutCounts;
|
||||
|
@ -308,18 +309,23 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
|||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public synchronized void setFolderFeedMapCursor(Cursor cursor) {
|
||||
public synchronized void setFoldersCursor(Cursor cursor) {
|
||||
if ((cursor.getCount() < 1) || (!cursor.isBeforeFirst())) return;
|
||||
folderFeedMap = newCustomSortedMap();
|
||||
folders = new LinkedHashMap<String,Folder>(cursor.getCount());
|
||||
while (cursor.moveToNext()) {
|
||||
String folderName = getStr(cursor, DatabaseConstants.FEED_FOLDER_FOLDER_NAME);
|
||||
String feedId = getStr(cursor, DatabaseConstants.FEED_FOLDER_FEED_ID);
|
||||
if (! folderFeedMap.containsKey(folderName)) folderFeedMap.put(folderName, new ArrayList<String>());
|
||||
folderFeedMap.get(folderName).add(feedId);
|
||||
Folder folder = Folder.fromCursor(cursor);
|
||||
folders.put(folder.flatName(), folder);
|
||||
}
|
||||
if (!folderFeedMap.containsKey(AppConstants.ROOT_FOLDER)) {
|
||||
folderFeedMap.put(AppConstants.ROOT_FOLDER, new ArrayList<String>());
|
||||
/*
|
||||
if (!folders.containsKey(AppConstants.ROOT_FOLDER)) {
|
||||
Folder fakeRoot = new Folder();
|
||||
fakeRoot.name = AppConstants.ROOT_FOLDER;
|
||||
fakeRoot.parents = Collections.emptyList();
|
||||
fakeRoot.children = Collections.emptyList();
|
||||
fakeRoot.feedIds = Collections.emptyList();
|
||||
folders.put(AppConstants.ROOT_FOLDER, fakeRoot);
|
||||
}
|
||||
*/
|
||||
recountFeeds();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
@ -344,18 +350,22 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
|||
}
|
||||
|
||||
private void recountFeeds() {
|
||||
if ((folderFeedMap == null) || (feeds == null)) return;
|
||||
int c = folderFeedMap.keySet().size();
|
||||
activeFolderNames = new ArrayList<String>(c);
|
||||
activeFolderChildren = new ArrayList<List<Feed>>(c);
|
||||
neutCounts = new ArrayList<Integer>(c);
|
||||
posCounts = new ArrayList<Integer>(c);
|
||||
for (String folderName : folderFeedMap.keySet()) {
|
||||
if ((folders == null) || (feeds == null)) return;
|
||||
// re-init our local vars
|
||||
activeFolderNames = new ArrayList<String>();
|
||||
activeFolderChildren = new ArrayList<List<Feed>>();
|
||||
neutCounts = new ArrayList<Integer>();
|
||||
posCounts = new ArrayList<Integer>();
|
||||
// create a sorted list of folder display names
|
||||
List<String> sortedFolderNames = new ArrayList<String>(folders.keySet());
|
||||
customSortList(sortedFolderNames);
|
||||
// inspect folders to see if the are active for display
|
||||
for (String folderName : sortedFolderNames) {
|
||||
List<Feed> activeFeeds = new ArrayList<Feed>();
|
||||
int neutCount = 0;
|
||||
int posCount = 0;
|
||||
for (String feedId : folderFeedMap.get(folderName)) {
|
||||
Feed f = feeds.get(feedId);
|
||||
for (Long feedId : folders.get(folderName).feedIds) {
|
||||
Feed f = feeds.get(feedId.toString());
|
||||
if (f != null) {
|
||||
if (((currentState == StateFilter.BEST) && (f.positiveCount > 0)) ||
|
||||
((currentState == StateFilter.SOME) && ((f.positiveCount + f.neutralCount > 0))) ||
|
||||
|
@ -492,18 +502,20 @@ public class FolderListAdapter extends BaseExpandableListAdapter {
|
|||
* folder on top, and also the expectation that *despite locale*, folders
|
||||
* starting with an underscore should show up on top.
|
||||
*/
|
||||
private Map<String,List<String>> newCustomSortedMap() {
|
||||
Comparator<String> c = new Comparator<String>() {
|
||||
@Override
|
||||
public int compare(String s1, String s2) {
|
||||
if (TextUtils.equals(s1, s2)) return 0;
|
||||
if (s1.equals(AppConstants.ROOT_FOLDER)) return -1;
|
||||
if (s2.equals(AppConstants.ROOT_FOLDER)) return 1;
|
||||
if (s1.startsWith("_")) return -1;
|
||||
if (s2.startsWith("_")) return 1;
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(s1, s2);
|
||||
}
|
||||
};
|
||||
return new TreeMap<String,List<String>>(c);
|
||||
private void customSortList(List<String> list) {
|
||||
Collections.sort(list, CustomComparator);
|
||||
}
|
||||
|
||||
private static Comparator<String> CustomComparator = new Comparator<String>() {
|
||||
@Override
|
||||
public int compare(String s1, String s2) {
|
||||
if (TextUtils.equals(s1, s2)) return 0;
|
||||
if (s1.equals(AppConstants.ROOT_FOLDER)) return -1;
|
||||
if (s2.equals(AppConstants.ROOT_FOLDER)) return 1;
|
||||
if (s1.startsWith("_")) return -1;
|
||||
if (s2.startsWith("_")) return 1;
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(s1, s2);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -4,38 +4,67 @@ import android.content.ContentValues;
|
|||
import android.database.Cursor;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.newsblur.database.DatabaseConstants;
|
||||
|
||||
public class Folder {
|
||||
|
||||
public final ContentValues values = new ContentValues();
|
||||
/** Actual unique name of the folder. */
|
||||
public String name;
|
||||
/** List, drilling down from root to this folder of containing folders. NOTE: this is a path! */
|
||||
public List<String> parents;
|
||||
/** Set of any children folders contained in this folder. NOTE: this is a one-to-many set! */
|
||||
public List<String> children;
|
||||
/** Set of any feeds contained in this folder. */
|
||||
public List<Long> feedIds;
|
||||
|
||||
public void setId(final String id) {
|
||||
values.put(DatabaseConstants.FOLDER_ID, id);
|
||||
}
|
||||
|
||||
public void setName(final String name) {
|
||||
values.put(DatabaseConstants.FOLDER_NAME, name);
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return values.getAsString(DatabaseConstants.FOLDER_ID);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return values.getAsString(DatabaseConstants.FOLDER_NAME);
|
||||
}
|
||||
|
||||
public static Folder fromCursor(Cursor folderCursor) {
|
||||
final Folder folder = new Folder();
|
||||
folder.setId(folderCursor.getString(folderCursor.getColumnIndex(DatabaseConstants.FOLDER_ID)));
|
||||
folder.setName(folderCursor.getString(folderCursor.getColumnIndex(DatabaseConstants.FOLDER_NAME)));
|
||||
public static Folder fromCursor(Cursor c) {
|
||||
if (c.isBeforeFirst()) {
|
||||
c.moveToFirst();
|
||||
}
|
||||
Folder folder = new Folder();
|
||||
folder.name = c.getString(c.getColumnIndex(DatabaseConstants.FOLDER_NAME));
|
||||
String parents = c.getString(c.getColumnIndex(DatabaseConstants.FOLDER_PARENT_NAMES));
|
||||
folder.parents = new ArrayList<String>();
|
||||
for (String name : TextUtils.split(parents, ",")) { folder.parents.add(name);}
|
||||
String children = c.getString(c.getColumnIndex(DatabaseConstants.FOLDER_CHILDREN_NAMES));
|
||||
folder.children = new ArrayList<String>();
|
||||
for (String name : TextUtils.split(children, ",")) { folder.children.add(name);}
|
||||
String feeds = c.getString(c.getColumnIndex(DatabaseConstants.FOLDER_FEED_IDS));
|
||||
folder.feedIds = new ArrayList<Long>();
|
||||
for (String id : TextUtils.split(feeds, ",")) { folder.feedIds.add(Long.valueOf(id));}
|
||||
return folder;
|
||||
}
|
||||
|
||||
public ContentValues getValues() {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(DatabaseConstants.FOLDER_NAME, name);
|
||||
values.put(DatabaseConstants.FOLDER_PARENT_NAMES, TextUtils.join(",", parents));
|
||||
values.put(DatabaseConstants.FOLDER_CHILDREN_NAMES, TextUtils.join(",", children));
|
||||
values.put(DatabaseConstants.FOLDER_FEED_IDS, TextUtils.join(",", feedIds));
|
||||
return values;
|
||||
}
|
||||
|
||||
public String flatName() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (String parentName : parents) {
|
||||
builder.append(parentName);
|
||||
builder.append(" - ");
|
||||
}
|
||||
builder.append(name);
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object otherFolder) {
|
||||
return TextUtils.equals(((Folder) otherFolder).getId(), getId());
|
||||
return TextUtils.equals(((Folder) otherFolder).name, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return name.hashCode();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ import com.newsblur.util.UIUtils;
|
|||
public class FolderListFragment extends NbFragment implements OnGroupClickListener, OnChildClickListener, OnCreateContextMenuListener, LoaderManager.LoaderCallbacks<Cursor> {
|
||||
|
||||
private static final int SOCIALFEEDS_LOADER = 1;
|
||||
private static final int FOLDERFEEDMAP_LOADER = 2;
|
||||
private static final int FOLDERS_LOADER = 2;
|
||||
private static final int FEEDS_LOADER = 3;
|
||||
private static final int SAVEDCOUNT_LOADER = 4;
|
||||
|
||||
|
@ -64,9 +64,9 @@ public class FolderListFragment extends NbFragment implements OnGroupClickListen
|
|||
public synchronized void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
sharedPreferences = getActivity().getSharedPreferences(PrefConstants.PREFERENCES, 0);
|
||||
if (getLoaderManager().getLoader(FOLDERFEEDMAP_LOADER) == null) {
|
||||
if (getLoaderManager().getLoader(FOLDERS_LOADER) == null) {
|
||||
getLoaderManager().initLoader(SOCIALFEEDS_LOADER, null, this);
|
||||
getLoaderManager().initLoader(FOLDERFEEDMAP_LOADER, null, this);
|
||||
getLoaderManager().initLoader(FOLDERS_LOADER, null, this);
|
||||
getLoaderManager().initLoader(FEEDS_LOADER, null, this);
|
||||
getLoaderManager().initLoader(SAVEDCOUNT_LOADER, null, this);
|
||||
}
|
||||
|
@ -77,8 +77,8 @@ public class FolderListFragment extends NbFragment implements OnGroupClickListen
|
|||
switch (id) {
|
||||
case SOCIALFEEDS_LOADER:
|
||||
return FeedUtils.dbHelper.getSocialFeedsLoader(currentState);
|
||||
case FOLDERFEEDMAP_LOADER:
|
||||
return FeedUtils.dbHelper.getFolderFeedMapLoader();
|
||||
case FOLDERS_LOADER:
|
||||
return FeedUtils.dbHelper.getFoldersLoader();
|
||||
case FEEDS_LOADER:
|
||||
return FeedUtils.dbHelper.getFeedsLoader(currentState);
|
||||
case SAVEDCOUNT_LOADER:
|
||||
|
@ -96,8 +96,8 @@ public class FolderListFragment extends NbFragment implements OnGroupClickListen
|
|||
case SOCIALFEEDS_LOADER:
|
||||
adapter.setSocialFeedCursor(cursor);
|
||||
break;
|
||||
case FOLDERFEEDMAP_LOADER:
|
||||
adapter.setFolderFeedMapCursor(cursor);
|
||||
case FOLDERS_LOADER:
|
||||
adapter.setFoldersCursor(cursor);
|
||||
break;
|
||||
case FEEDS_LOADER:
|
||||
adapter.setFeedCursor(cursor);
|
||||
|
@ -124,7 +124,7 @@ public class FolderListFragment extends NbFragment implements OnGroupClickListen
|
|||
public void hasUpdated() {
|
||||
if (isAdded()) {
|
||||
getLoaderManager().restartLoader(SOCIALFEEDS_LOADER, null, this);
|
||||
getLoaderManager().restartLoader(FOLDERFEEDMAP_LOADER, null, this);
|
||||
getLoaderManager().restartLoader(FOLDERS_LOADER, null, this);
|
||||
getLoaderManager().restartLoader(FEEDS_LOADER, null, this);
|
||||
getLoaderManager().restartLoader(SAVEDCOUNT_LOADER, null, this);
|
||||
}
|
||||
|
@ -215,7 +215,7 @@ public class FolderListFragment extends NbFragment implements OnGroupClickListen
|
|||
} else if (item.getItemId() == R.id.menu_mark_folder_as_read) {
|
||||
if (!adapter.isFolderRoot(groupPosition)) {
|
||||
String folderName = adapter.getGroup(groupPosition);
|
||||
FeedUtils.markFeedsRead(FeedUtils.feedSetFromFolderName(folderName, getActivity()), null, null, getActivity());
|
||||
FeedUtils.markFeedsRead(FeedUtils.feedSetFromFolderName(folderName), null, null, getActivity());
|
||||
} else {
|
||||
FeedUtils.markFeedsRead(FeedSet.allFeeds(), null, null, getActivity());
|
||||
}
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
package com.newsblur.network.domain;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import android.util.Log;
|
||||
import com.google.gson.Gson;
|
||||
|
@ -17,32 +16,26 @@ import com.google.gson.JsonParser;
|
|||
import com.google.gson.annotations.SerializedName;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.domain.Folder;
|
||||
import com.newsblur.domain.SocialFeed;
|
||||
import com.newsblur.util.AppConstants;
|
||||
|
||||
public class FeedFolderResponse {
|
||||
|
||||
/** Helper variable so users of the parser can pass along how long it took to read the JSON stream, for instrumentation. */
|
||||
public long readTime;
|
||||
|
||||
@SerializedName("starred_count")
|
||||
public int starredCount;
|
||||
public Set<Folder> folders;
|
||||
public Set<Feed> feeds;
|
||||
public Set<SocialFeed> socialFeeds;
|
||||
|
||||
@SerializedName("feeds")
|
||||
public Map<String, Feed> feeds;
|
||||
|
||||
@SerializedName("flat_folders")
|
||||
public Map<String, List<Long>> folders;
|
||||
|
||||
@SerializedName("social_feeds")
|
||||
public SocialFeed[] socialFeeds;
|
||||
|
||||
public boolean isAuthenticated;
|
||||
public boolean isPremium;
|
||||
public boolean isStaff;
|
||||
public int starredCount;
|
||||
|
||||
public FeedFolderResponse(String json, Gson gson) {
|
||||
|
||||
// TODO: is there really any good reason the default GSON parser doesn't work here?
|
||||
JsonParser parser = new JsonParser();
|
||||
JsonObject asJsonObject = parser.parse(json).getAsJsonObject();
|
||||
|
||||
|
@ -55,23 +48,19 @@ public class FeedFolderResponse {
|
|||
this.isPremium = profile.get("is_premium").getAsBoolean();
|
||||
}
|
||||
|
||||
JsonArray jsonFoldersArray = (JsonArray) asJsonObject.get("folders");
|
||||
ArrayList<String> nestedFolderList = new ArrayList<String>();
|
||||
folders = new HashMap<String, List<Long>>();
|
||||
parseFeedArray(nestedFolderList, folders, null, jsonFoldersArray);
|
||||
|
||||
JsonElement starredCountElement = asJsonObject.get("starred_count");
|
||||
if(starredCountElement != null) {
|
||||
starredCount = gson.fromJson(starredCountElement, int.class);
|
||||
}
|
||||
|
||||
folders = new HashSet<Folder>();
|
||||
JsonArray jsonFoldersArray = (JsonArray) asJsonObject.get("folders");
|
||||
// recursively parse folders
|
||||
parseFolderArray(new ArrayList<String>(0), null, jsonFoldersArray);
|
||||
|
||||
// Inconsistent server response here. When user has no feeds we get
|
||||
// "feeds": []
|
||||
// and other times we get
|
||||
// "feeds": {"309667": {
|
||||
// So support both I guess
|
||||
// Inconsistent server response here. When user has no feeds we get an empty array, otherwise an object
|
||||
JsonElement feedsElement = asJsonObject.get("feeds");
|
||||
feeds = new HashMap<String, Feed>();
|
||||
feeds = new HashSet<Feed>();
|
||||
if(feedsElement instanceof JsonObject) {
|
||||
JsonObject feedsObject = (JsonObject) asJsonObject.get("feeds");
|
||||
if(feedsObject != null) {
|
||||
|
@ -80,48 +69,43 @@ public class FeedFolderResponse {
|
|||
while(iterator.hasNext()) {
|
||||
Entry<String, JsonElement> feedElement = iterator.next();
|
||||
Feed feed = gson.fromJson(feedElement.getValue(), Feed.class);
|
||||
feeds.put(feedElement.getKey(), feed);
|
||||
feeds.add(feed);
|
||||
}
|
||||
}
|
||||
} // else server sent back '"feeds": []'
|
||||
|
||||
socialFeeds = new SocialFeed[0];
|
||||
socialFeeds = new HashSet<SocialFeed>();
|
||||
JsonArray socialFeedsArray = (JsonArray) asJsonObject.get("social_feeds");
|
||||
if(socialFeedsArray != null) {
|
||||
List<SocialFeed> socialFeedsList = new ArrayList<SocialFeed>();
|
||||
for(int i=0;i<socialFeedsArray.size();i++) {
|
||||
JsonElement jsonElement = socialFeedsArray.get(i);
|
||||
SocialFeed socialFeed = gson.fromJson(jsonElement, SocialFeed.class);
|
||||
socialFeedsList.add(socialFeed);
|
||||
socialFeeds.add(socialFeed);
|
||||
}
|
||||
socialFeeds = socialFeedsList.toArray(new SocialFeed[socialFeedsArray.size()]);
|
||||
}
|
||||
|
||||
// sometimes the API won't declare the top-level/root folder, but most of the
|
||||
// codebase expects it to exist. Declare it as empty if missing.
|
||||
if (!folders.containsKey(AppConstants.ROOT_FOLDER)) {
|
||||
folders.put(AppConstants.ROOT_FOLDER, new ArrayList<Long>());
|
||||
Folder emptyRootFolder = new Folder();
|
||||
emptyRootFolder.name = AppConstants.ROOT_FOLDER;
|
||||
// equality is based on folder name, so contains() will work
|
||||
if (!folders.contains(emptyRootFolder)) {
|
||||
folders.add(emptyRootFolder);
|
||||
Log.d( this.getClass().getName(), "root folder was missing. added it.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a folder, which is a list of feeds and/or more folders. Nested folders
|
||||
* are flattened into a single list, with names that are heirarchical.
|
||||
* Parses a folder, which is a list of feeds and/or more folders.
|
||||
*
|
||||
* @param nestedFolderList a list of any parent folders that surrounded this folder.
|
||||
* @param folders the sink
|
||||
* @param name the name of this folder.
|
||||
* @param arrayValue the actual contents to be parsed.
|
||||
* @param parentName folder that surrounded this folder.
|
||||
* @param name the name of this folder or null if root.
|
||||
* @param arrayValue the contents to be parsed.
|
||||
*/
|
||||
private void parseFeedArray(List<String> nestedFolderList,
|
||||
Map<String, List<Long>> folders, String name, JsonArray arrayValue) {
|
||||
|
||||
// determine our text name, like "grandparent - parent - me"
|
||||
String fullFolderName = getFolderName(name, nestedFolderList);
|
||||
// sink for any feeds found in this folder
|
||||
ArrayList<Long> feedIds = new ArrayList<Long>();
|
||||
|
||||
private void parseFolderArray(List<String> parentNames, String name, JsonArray arrayValue) {
|
||||
if (name == null) name = AppConstants.ROOT_FOLDER;
|
||||
List<String> children = new ArrayList<String>();
|
||||
List<Long> feedIds = new ArrayList<Long>();
|
||||
for (JsonElement jsonElement : arrayValue) {
|
||||
// a folder array contains either feed IDs or nested folder objects
|
||||
if(jsonElement.isJsonPrimitive()) {
|
||||
|
@ -129,35 +113,23 @@ public class FeedFolderResponse {
|
|||
} else {
|
||||
// if it wasn't a feed ID, it is a nested folder object
|
||||
Set<Entry<String, JsonElement>> entrySet = ((JsonObject) jsonElement).entrySet();
|
||||
List<String> nestedFolderListCopy = new ArrayList<String>(nestedFolderList);
|
||||
if(name != null) {
|
||||
nestedFolderListCopy.add(name);
|
||||
}
|
||||
// recurse - nested folders are just objects with (usually one) field named for the folder
|
||||
// that is a list of contained feeds or additional folders
|
||||
for (Entry<String, JsonElement> next : entrySet) {
|
||||
parseFeedArray( nestedFolderListCopy, folders, next.getKey(), (JsonArray) next.getValue() );
|
||||
children.add(next.getKey());
|
||||
List<String> appendedParentList = new ArrayList<String>(parentNames);
|
||||
appendedParentList.add(name);
|
||||
parseFolderArray(appendedParentList, next.getKey(), (JsonArray) next.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
folders.put(fullFolderName, feedIds);
|
||||
//Log.d( this.getClass().getName(), "parsed folder '" + fullFolderName + "' with " + feedIds.size() + " feeds" );
|
||||
Folder folder = new Folder();
|
||||
folder.name = name;
|
||||
folder.parents = parentNames;
|
||||
folder.children = children;
|
||||
folder.feedIds = feedIds;
|
||||
folders.add(folder);
|
||||
Log.d(this.getClass().getName(), String.format("folder %s has parents %s and children %s and %d feeds", name, parentNames.toString(), children.toString(), feedIds.size()));
|
||||
}
|
||||
|
||||
private String getFolderName(String key, List<String> parentFeedNames) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for(String parentFolder: parentFeedNames) {
|
||||
builder.append(parentFolder);
|
||||
builder.append(" - ");
|
||||
}
|
||||
if(key != null) {
|
||||
builder.append(key);
|
||||
} else {
|
||||
// a null key means we are at the root. give these a pseudo-folder name, since the DB and many
|
||||
// classes would be very unhappy with a null foldername.
|
||||
builder.append(AppConstants.ROOT_FOLDER);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ import com.newsblur.activity.NbActivity;
|
|||
import com.newsblur.database.BlurDatabaseHelper;
|
||||
import static com.newsblur.database.BlurDatabaseHelper.closeQuietly;
|
||||
import com.newsblur.database.DatabaseConstants;
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.domain.Folder;
|
||||
import com.newsblur.domain.SocialFeed;
|
||||
import com.newsblur.domain.Story;
|
||||
import com.newsblur.network.APIConstants;
|
||||
|
@ -385,7 +387,7 @@ public class NBSyncService extends Service {
|
|||
NbActivity.updateAllActivities(false);
|
||||
|
||||
// there is a rare issue with feeds that have no folder. capture them for workarounds.
|
||||
Set<String> debugFeedIds = new HashSet<String>();
|
||||
Set<Long> debugFeedIds = new HashSet<Long>();
|
||||
orphanFeedIds = new HashSet<String>();
|
||||
|
||||
try {
|
||||
|
@ -420,42 +422,27 @@ public class NBSyncService extends Service {
|
|||
|
||||
// data for the folder and folder-feed-mapping tables
|
||||
List<ContentValues> folderValues = new ArrayList<ContentValues>();
|
||||
List<ContentValues> ffmValues = new ArrayList<ContentValues>();
|
||||
for (Entry<String, List<Long>> entry : feedResponse.folders.entrySet()) {
|
||||
if (!TextUtils.isEmpty(entry.getKey())) {
|
||||
String folderName = entry.getKey().trim();
|
||||
if (!TextUtils.isEmpty(folderName)) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(DatabaseConstants.FOLDER_NAME, folderName);
|
||||
folderValues.add(values);
|
||||
}
|
||||
|
||||
for (Long feedId : entry.getValue()) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(DatabaseConstants.FEED_FOLDER_FEED_ID, feedId);
|
||||
values.put(DatabaseConstants.FEED_FOLDER_FOLDER_NAME, folderName);
|
||||
ffmValues.add(values);
|
||||
// note all feeds that belong to some folder
|
||||
debugFeedIds.add(Long.toString(feedId));
|
||||
}
|
||||
}
|
||||
for (Folder folder : feedResponse.folders) {
|
||||
folderValues.add(folder.getValues());
|
||||
// note all feeds that belong to some folder
|
||||
debugFeedIds.addAll(folder.feedIds);
|
||||
}
|
||||
|
||||
// data for the feeds table
|
||||
List<ContentValues> feedValues = new ArrayList<ContentValues>();
|
||||
feedaddloop: for (String feedId : feedResponse.feeds.keySet()) {
|
||||
feedaddloop: for (Feed feed : feedResponse.feeds) {
|
||||
// sanity-check that the returned feeds actually exist in a folder or at the root
|
||||
// if they do not, they should neither display nor count towards unread numbers
|
||||
if (! debugFeedIds.contains(feedId)) {
|
||||
Log.w(this.getClass().getName(), "Found and ignoring un-foldered feed: " + feedId );
|
||||
orphanFeedIds.add(feedId);
|
||||
if (! debugFeedIds.contains(feed.feedId)) {
|
||||
Log.w(this.getClass().getName(), "Found and ignoring un-foldered feed: " + feed.feedId );
|
||||
orphanFeedIds.add(feed.feedId);
|
||||
continue feedaddloop;
|
||||
}
|
||||
if (! feedResponse.feeds.get(feedId).active) {
|
||||
if (! feed.active) {
|
||||
// the feed is disabled/hidden, pretend it doesn't exist
|
||||
continue feedaddloop;
|
||||
}
|
||||
feedValues.add(feedResponse.feeds.get(feedId).getValues());
|
||||
feedValues.add(feed.getValues());
|
||||
}
|
||||
|
||||
// data for the the social feeds table
|
||||
|
@ -464,7 +451,7 @@ public class NBSyncService extends Service {
|
|||
socialFeedValues.add(feed.getValues());
|
||||
}
|
||||
|
||||
dbHelper.insertFeedsFolders(feedValues, folderValues, ffmValues, socialFeedValues);
|
||||
dbHelper.insertFeedsFolders(folderValues, feedValues, socialFeedValues);
|
||||
|
||||
// populate the starred stories count table
|
||||
dbHelper.updateStarredStoriesCount(feedResponse.starredCount);
|
||||
|
|
|
@ -5,7 +5,7 @@ public class AppConstants {
|
|||
// Enables high-volume logging that may be useful for debugging. This should
|
||||
// never be enabled for releases, as it not only slows down the app considerably,
|
||||
// it will log sensitive info such as passwords!
|
||||
public static final boolean VERBOSE_LOG = false;
|
||||
public static final boolean VERBOSE_LOG = true;
|
||||
public static final boolean VERBOSE_LOG_DB = false;
|
||||
public static final boolean VERBOSE_LOG_NET = false;
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ import com.newsblur.activity.NbActivity;
|
|||
import com.newsblur.database.BlurDatabaseHelper;
|
||||
import com.newsblur.domain.Classifier;
|
||||
import com.newsblur.domain.Feed;
|
||||
import com.newsblur.domain.Folder;
|
||||
import com.newsblur.domain.SocialFeed;
|
||||
import com.newsblur.domain.Story;
|
||||
import com.newsblur.network.APIManager;
|
||||
|
@ -200,8 +201,10 @@ public class FeedUtils {
|
|||
context.startActivity(Intent.createChooser(intent, "Share using"));
|
||||
}
|
||||
|
||||
public static FeedSet feedSetFromFolderName(String folderName, Context context) {
|
||||
Set<String> feedIds = dbHelper.getFeedsForFolder(folderName);
|
||||
public static FeedSet feedSetFromFolderName(String folderName) {
|
||||
Folder folder = dbHelper.getFolder(folderName);
|
||||
Set<String> feedIds = new HashSet<String>(folder.feedIds.size());
|
||||
for (Long id : folder.feedIds) feedIds.add(Long.toString(id));
|
||||
return FeedSet.folder(folderName, feedIds);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue