diff --git a/clients/android/NewsBlur/src/com/newsblur/activity/FeedItemsList.java b/clients/android/NewsBlur/src/com/newsblur/activity/FeedItemsList.java index 08842e649..c041833b2 100644 --- a/clients/android/NewsBlur/src/com/newsblur/activity/FeedItemsList.java +++ b/clients/android/NewsBlur/src/com/newsblur/activity/FeedItemsList.java @@ -1,8 +1,5 @@ package com.newsblur.activity; -import android.content.ContentValues; -import android.database.Cursor; -import android.net.Uri; import android.os.Bundle; import android.app.DialogFragment; import android.app.FragmentTransaction; @@ -11,8 +8,6 @@ import android.view.MenuInflater; import android.view.MenuItem; import com.newsblur.R; -import com.newsblur.database.DatabaseConstants; -import com.newsblur.database.FeedProvider; import com.newsblur.domain.Feed; import com.newsblur.fragment.DeleteFeedFragment; import com.newsblur.fragment.FeedItemListFragment; @@ -25,33 +20,23 @@ import com.newsblur.util.StoryOrder; public class FeedItemsList extends ItemsList { - public static final String EXTRA_FEED = "feedId"; - public static final String EXTRA_FEED_TITLE = "feedTitle"; - public static final String EXTRA_FOLDER_NAME = "folderName"; - private String feedId; - private String feedTitle; + public static final String EXTRA_FEED = "feed"; + public static final String EXTRA_FOLDER_NAME = "folderName"; + private Feed feed; private String folderName; @Override protected void onCreate(Bundle bundle) { - super.onCreate(bundle); - - feedId = getIntent().getStringExtra(EXTRA_FEED); - feedTitle = getIntent().getStringExtra(EXTRA_FEED_TITLE); + feed = (Feed) getIntent().getSerializableExtra(EXTRA_FEED); folderName = getIntent().getStringExtra(EXTRA_FOLDER_NAME); - final Uri feedUri = FeedProvider.FEEDS_URI.buildUpon().appendPath(feedId).build(); - Cursor cursor = getContentResolver().query(feedUri, null, DatabaseConstants.getStorySelectionFromState(currentState), null, null); - if (cursor.getCount() > 0) { - cursor.moveToFirst(); - Feed feed = Feed.fromCursor(cursor); - setTitle(feed.title); - } - cursor.close(); + super.onCreate(bundle); + + setTitle(feed.title); itemListFragment = (FeedItemListFragment) fragmentManager.findFragmentByTag(FeedItemListFragment.class.getName()); if (itemListFragment == null) { - itemListFragment = FeedItemListFragment.newInstance(feedId, currentState, getDefaultFeedView()); + itemListFragment = FeedItemListFragment.newInstance(feed, currentState, getDefaultFeedView()); itemListFragment.setRetainInstance(true); FragmentTransaction listTransaction = fragmentManager.beginTransaction(); listTransaction.add(R.id.activity_itemlist_container, itemListFragment, FeedItemListFragment.class.getName()); @@ -61,11 +46,11 @@ public class FeedItemsList extends ItemsList { @Override protected FeedSet createFeedSet() { - return FeedSet.singleFeed(getIntent().getStringExtra(EXTRA_FEED)); + return FeedSet.singleFeed(feed.feedId); } public void deleteFeed() { - DialogFragment deleteFeedFragment = DeleteFeedFragment.newInstance(Long.parseLong(feedId), feedTitle, folderName); + DialogFragment deleteFeedFragment = DeleteFeedFragment.newInstance(feed, folderName); deleteFeedFragment.show(fragmentManager, "dialog"); } @@ -93,32 +78,32 @@ public class FeedItemsList extends ItemsList { @Override protected StoryOrder getStoryOrder() { - return PrefsUtils.getStoryOrderForFeed(this, feedId); + return PrefsUtils.getStoryOrderForFeed(this, feed.feedId); } @Override public void updateStoryOrderPreference(StoryOrder newValue) { - PrefsUtils.setStoryOrderForFeed(this, feedId, newValue); + PrefsUtils.setStoryOrderForFeed(this, feed.feedId, newValue); } @Override protected void updateReadFilterPreference(ReadFilter newValue) { - PrefsUtils.setReadFilterForFeed(this, feedId, newValue); + PrefsUtils.setReadFilterForFeed(this, feed.feedId, newValue); } @Override protected ReadFilter getReadFilter() { - return PrefsUtils.getReadFilterForFeed(this, feedId); + return PrefsUtils.getReadFilterForFeed(this, feed.feedId); } @Override protected DefaultFeedView getDefaultFeedView() { - return PrefsUtils.getDefaultFeedViewForFeed(this, feedId); + return PrefsUtils.getDefaultFeedViewForFeed(this, feed.feedId); } @Override public void defaultFeedViewChanged(DefaultFeedView value) { - PrefsUtils.setDefaultFeedViewForFeed(this, feedId, value); + PrefsUtils.setDefaultFeedViewForFeed(this, feed.feedId, value); if (itemListFragment != null) { itemListFragment.setDefaultFeedView(value); } diff --git a/clients/android/NewsBlur/src/com/newsblur/database/FeedItemsAdapter.java b/clients/android/NewsBlur/src/com/newsblur/database/FeedItemsAdapter.java index 6df91452e..959f9f5aa 100644 --- a/clients/android/NewsBlur/src/com/newsblur/database/FeedItemsAdapter.java +++ b/clients/android/NewsBlur/src/com/newsblur/database/FeedItemsAdapter.java @@ -8,6 +8,7 @@ import android.database.Cursor; import android.graphics.Color; import android.graphics.Typeface; import android.text.TextUtils; +import android.util.Log; import android.view.View; import android.widget.TextView; diff --git a/clients/android/NewsBlur/src/com/newsblur/domain/Feed.java b/clients/android/NewsBlur/src/com/newsblur/domain/Feed.java index e5db994ac..3f30a193e 100644 --- a/clients/android/NewsBlur/src/com/newsblur/domain/Feed.java +++ b/clients/android/NewsBlur/src/com/newsblur/domain/Feed.java @@ -5,10 +5,14 @@ import android.database.Cursor; import android.text.TextUtils; import android.util.Log; +import java.io.Serializable; + import com.google.gson.annotations.SerializedName; import com.newsblur.database.DatabaseConstants; -public class Feed implements Comparable { +public class Feed implements Comparable, Serializable { + + private static final long serialVersionUID = 0L; @SerializedName("id") public String feedId; diff --git a/clients/android/NewsBlur/src/com/newsblur/fragment/DeleteFeedFragment.java b/clients/android/NewsBlur/src/com/newsblur/fragment/DeleteFeedFragment.java index a472736b7..e582f9ce6 100644 --- a/clients/android/NewsBlur/src/com/newsblur/fragment/DeleteFeedFragment.java +++ b/clients/android/NewsBlur/src/com/newsblur/fragment/DeleteFeedFragment.java @@ -2,6 +2,8 @@ package com.newsblur.fragment; import com.newsblur.R; import com.newsblur.activity.Main; +import com.newsblur.domain.Feed; +import com.newsblur.domain.SocialFeed; import com.newsblur.network.APIManager; import com.newsblur.util.FeedUtils; @@ -20,15 +22,25 @@ import android.widget.TextView; import android.widget.Toast; public class DeleteFeedFragment extends DialogFragment { - private static final String FEED_ID = "feed_url"; + private static final String FEED_ID = "feed_id"; private static final String FEED_NAME = "feed_name"; private static final String FOLDER_NAME = "folder_name"; - public static DeleteFeedFragment newInstance(final long feedId, final String feedName, final String folderName) { + public static DeleteFeedFragment newInstance(Feed feed, String folderName) { DeleteFeedFragment frag = new DeleteFeedFragment(); Bundle args = new Bundle(); - args.putLong(FEED_ID, feedId); - args.putString(FEED_NAME, feedName); + args.putString(FEED_ID, feed.feedId); + args.putString(FEED_NAME, feed.title); + args.putString(FOLDER_NAME, folderName); + frag.setArguments(args); + return frag; + } + + public static DeleteFeedFragment newInstance(SocialFeed feed, String folderName) { + DeleteFeedFragment frag = new DeleteFeedFragment(); + Bundle args = new Bundle(); + args.putString(FEED_ID, feed.userId); + args.putString(FEED_NAME, feed.feedTitle); args.putString(FOLDER_NAME, folderName); frag.setArguments(args); return frag; @@ -41,7 +53,7 @@ public class DeleteFeedFragment extends DialogFragment { builder.setPositiveButton(R.string.alert_dialog_ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { - FeedUtils.deleteFeed(getArguments().getLong(FEED_ID), getArguments().getString(FOLDER_NAME), getActivity(), new APIManager(getActivity())); + FeedUtils.deleteFeed(getArguments().getString(FEED_ID), getArguments().getString(FOLDER_NAME), getActivity(), new APIManager(getActivity())); // if called from main view then refresh otherwise it was // called from the feed view so finish Activity activity = DeleteFeedFragment.this.getActivity(); diff --git a/clients/android/NewsBlur/src/com/newsblur/fragment/FeedItemListFragment.java b/clients/android/NewsBlur/src/com/newsblur/fragment/FeedItemListFragment.java index 199315d1d..5a4b092a6 100644 --- a/clients/android/NewsBlur/src/com/newsblur/fragment/FeedItemListFragment.java +++ b/clients/android/NewsBlur/src/com/newsblur/fragment/FeedItemListFragment.java @@ -32,14 +32,15 @@ import com.newsblur.view.FeedItemViewBinder; public class FeedItemListFragment extends ItemListFragment implements OnItemClickListener { - private String feedId; + private Feed feed; + private ListView itemList; - public static FeedItemListFragment newInstance(String feedId, StateFilter currentState, DefaultFeedView defaultFeedView) { + public static FeedItemListFragment newInstance(Feed feed, StateFilter currentState, DefaultFeedView defaultFeedView) { FeedItemListFragment feedItemFragment = new FeedItemListFragment(); Bundle args = new Bundle(); args.putSerializable("currentState", currentState); - args.putString("feedId", feedId); + args.putSerializable("feed", feed); args.putSerializable("defaultFeedView", defaultFeedView); feedItemFragment.setArguments(args); @@ -49,61 +50,50 @@ public class FeedItemListFragment extends ItemListFragment implements OnItemClic @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - feedId = getArguments().getString("feedId"); + feed = (Feed) getArguments().getSerializable("feed"); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.fragment_itemlist, null); - ListView itemList = (ListView) v.findViewById(R.id.itemlistfragment_list); + itemList = (ListView) v.findViewById(R.id.itemlistfragment_list); setupBezelSwipeDetector(itemList); itemList.setEmptyView(v.findViewById(R.id.empty_view)); - - ContentResolver contentResolver = getActivity().getContentResolver(); - // TODO: defer creation of the adapter until the loader's first callback so we don't leak this first stories cursor - Cursor storiesCursor = dbHelper.getStoriesCursor(getFeedSet(), currentState); - Uri feedUri = FeedProvider.FEEDS_URI.buildUpon().appendPath(feedId).build(); - Cursor feedCursor = contentResolver.query(feedUri, null, null, null, null); - - if (feedCursor.getCount() < 1) { - // This shouldn't happen, but crash reports indicate that it does (very rarely). - // If we are told to create an item list for a feed, but then can't find that feed ID in the DB, - // something is very wrong, and we won't be able to recover, so just force the user back to the - // feed list until we have a better understanding of how to prevent this. - Log.w(this.getClass().getName(), "Feed not found in DB, can't create item list."); - getActivity().finish(); - return v; + itemList.setOnScrollListener(this); + if (adapter != null) { + // normally the list gets set up when the adapter is created, but sometimes + // onCreateView gets re-called. + itemList.setAdapter(adapter); + itemList.setOnItemClickListener(this); + itemList.setOnCreateContextMenuListener(this); } - feedCursor.moveToFirst(); - Feed feed = Feed.fromCursor(feedCursor); - feedCursor.close(); - - String[] groupFrom = new String[] { DatabaseConstants.STORY_TITLE, DatabaseConstants.STORY_SHORT_CONTENT, DatabaseConstants.STORY_AUTHORS, DatabaseConstants.STORY_TIMESTAMP, DatabaseConstants.STORY_INTELLIGENCE_AUTHORS }; - int[] groupTo = new int[] { R.id.row_item_title, R.id.row_item_content, R.id.row_item_author, R.id.row_item_date, R.id.row_item_sidebar }; - - // create the adapter before starting the loader, since the callback updates the adapter - adapter = new FeedItemsAdapter(getActivity(), feed, R.layout.row_item, storiesCursor, groupFrom, groupTo, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); - getLoaderManager().initLoader(ITEMLIST_LOADER , null, this); - itemList.setOnScrollListener(this); - - adapter.setViewBinder(new FeedItemViewBinder(getActivity())); - itemList.setAdapter(adapter); - itemList.setOnItemClickListener(this); - itemList.setOnCreateContextMenuListener(this); - return v; } + @Override + public void onLoadFinished(Loader loader, Cursor cursor) { + if ((adapter == null) && (cursor != null)) { + String[] groupFrom = new String[] { DatabaseConstants.STORY_TITLE, DatabaseConstants.STORY_SHORT_CONTENT, DatabaseConstants.STORY_AUTHORS, DatabaseConstants.STORY_TIMESTAMP, DatabaseConstants.STORY_INTELLIGENCE_AUTHORS }; + int[] groupTo = new int[] { R.id.row_item_title, R.id.row_item_content, R.id.row_item_author, R.id.row_item_date, R.id.row_item_sidebar }; + adapter = new FeedItemsAdapter(getActivity(), feed, R.layout.row_item, cursor, groupFrom, groupTo, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); + adapter.setViewBinder(new FeedItemViewBinder(getActivity())); + itemList.setAdapter(adapter); + itemList.setOnItemClickListener(this); + itemList.setOnCreateContextMenuListener(this); + } + super.onLoadFinished(loader, cursor); + } + @Override public void onItemClick(AdapterView parent, View view, int position, long id) { if (getActivity().isFinishing()) return; Intent i = new Intent(getActivity(), FeedReading.class); i.putExtra(Reading.EXTRA_FEEDSET, getFeedSet()); - i.putExtra(Reading.EXTRA_FEED, feedId); + i.putExtra(Reading.EXTRA_FEED, feed.feedId); i.putExtra(FeedReading.EXTRA_POSITION, position); i.putExtra(ItemsList.EXTRA_STATE, currentState); i.putExtra(Reading.EXTRA_DEFAULT_FEED_VIEW, defaultFeedView); diff --git a/clients/android/NewsBlur/src/com/newsblur/fragment/FolderListFragment.java b/clients/android/NewsBlur/src/com/newsblur/fragment/FolderListFragment.java index 3d3a681f3..5d640a106 100644 --- a/clients/android/NewsBlur/src/com/newsblur/fragment/FolderListFragment.java +++ b/clients/android/NewsBlur/src/com/newsblur/fragment/FolderListFragment.java @@ -183,14 +183,13 @@ public class FolderListFragment extends NbFragment implements OnGroupClickListen int groupPosition = ExpandableListView.getPackedPositionGroup(info.packedPosition); if (item.getItemId() == R.id.menu_delete_feed) { - String feedName; - if (groupPosition == 0) { - feedName = adapter.getSocialFeed(adapter.getChild(groupPosition, childPosition)).feedTitle; - } else { - feedName = adapter.getFeed(adapter.getChild(groupPosition, childPosition)).title; - } String folderName = adapter.getGroup(groupPosition); - DialogFragment deleteFeedFragment = DeleteFeedFragment.newInstance(info.id, feedName, folderName); + DialogFragment deleteFeedFragment; + if (groupPosition == 0) { + deleteFeedFragment = DeleteFeedFragment.newInstance(adapter.getSocialFeed(adapter.getChild(groupPosition, childPosition)), folderName); + } else { + deleteFeedFragment = DeleteFeedFragment.newInstance(adapter.getFeed(adapter.getChild(groupPosition, childPosition)), folderName); + } deleteFeedFragment.show(getFragmentManager(), "dialog"); return true; } else if (item.getItemId() == R.id.menu_mark_feed_as_read) { @@ -259,8 +258,7 @@ public class FolderListFragment extends NbFragment implements OnGroupClickListen Feed feed = adapter.getFeed(childName); String folderName = adapter.getGroup(groupPosition); Intent intent = new Intent(getActivity(), FeedItemsList.class); - intent.putExtra(FeedItemsList.EXTRA_FEED, feed.feedId); - intent.putExtra(FeedItemsList.EXTRA_FEED_TITLE, feed.title); + intent.putExtra(FeedItemsList.EXTRA_FEED, feed); intent.putExtra(FeedItemsList.EXTRA_FOLDER_NAME, folderName); intent.putExtra(ItemsList.EXTRA_STATE, currentState); getActivity().startActivity(intent); diff --git a/clients/android/NewsBlur/src/com/newsblur/network/APIManager.java b/clients/android/NewsBlur/src/com/newsblur/network/APIManager.java index 626fd99fc..7c31e2262 100644 --- a/clients/android/NewsBlur/src/com/newsblur/network/APIManager.java +++ b/clients/android/NewsBlur/src/com/newsblur/network/APIManager.java @@ -502,9 +502,9 @@ public class APIManager { } } - public NewsBlurResponse deleteFeed(long feedId, String folderName) { + public NewsBlurResponse deleteFeed(String feedId, String folderName) { ContentValues values = new ContentValues(); - values.put(APIConstants.PARAMETER_FEEDID, Long.toString(feedId)); + values.put(APIConstants.PARAMETER_FEEDID, feedId); if ((!TextUtils.isEmpty(folderName)) && (!folderName.equals(AppConstants.ROOT_FOLDER))) { values.put(APIConstants.PARAMETER_IN_FOLDER, folderName); } diff --git a/clients/android/NewsBlur/src/com/newsblur/util/FeedUtils.java b/clients/android/NewsBlur/src/com/newsblur/util/FeedUtils.java index 6c3f65796..be0f62c13 100644 --- a/clients/android/NewsBlur/src/com/newsblur/util/FeedUtils.java +++ b/clients/android/NewsBlur/src/com/newsblur/util/FeedUtils.java @@ -68,7 +68,7 @@ public class FeedUtils { }.execute(); } - public static void deleteFeed(final long feedId, final String folderName, final Context context, final APIManager apiManager) { + public static void deleteFeed(final String feedId, final String folderName, final Context context, final APIManager apiManager) { new AsyncTask() { @Override protected NewsBlurResponse doInBackground(Void... arg) { @@ -77,7 +77,7 @@ public class FeedUtils { @Override protected void onPostExecute(NewsBlurResponse result) { // TODO: we can't check result.isError() because the delete call sets the .message property on all calls. find a better error check - dbHelper.deleteFeed(Long.toString(feedId)); + dbHelper.deleteFeed(feedId); NbActivity.updateAllActivities(); Toast.makeText(context, R.string.toast_feed_deleted, Toast.LENGTH_SHORT).show(); }