diff --git a/res/menu/headlines_menu.xml b/res/menu/headlines_menu.xml new file mode 100644 index 00000000..ac614810 --- /dev/null +++ b/res/menu/headlines_menu.xml @@ -0,0 +1,21 @@ + + + + + + + + + \ No newline at end of file diff --git a/res/menu/main_menu.xml b/res/menu/main_menu.xml index a23bcb61..2d2e2998 100644 --- a/res/menu/main_menu.xml +++ b/res/menu/main_menu.xml @@ -37,12 +37,19 @@ android:showAsAction="ifRoom|withText" android:title="@string/load_more_articles"/> + + + @@ -50,30 +57,10 @@ - + - - - - - - - - diff --git a/res/values/strings.xml b/res/values/strings.xml index 8c80ddcf..853f9036 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -22,6 +22,8 @@ Preferences Light Connection + Selection toggle + Article toggle HTTP Authentication Logged in. No unread feeds. @@ -34,7 +36,7 @@ Share article Mark as read Sort feeds by unread count - Load more... + Load more Show all articles Show unread articles Accept any SSL certificate @@ -46,10 +48,10 @@ Toggle published Select all Select none - Select unread - Toggle starred - Toggle published - Toggle unread + Unread + Starred + Published + Unread Mark unread Optional. Fill this if your tt-rss installation is protected by HTTP Basic authentication Your tt-rss login. Not needed for single user mode @@ -63,6 +65,7 @@ No headlines to display Browse categories like feeds You can long-tap on a category to override this setting + Catchup No error Error: Unknown error (see log) diff --git a/src/org/fox/ttrss/FeedCategoriesFragment.java b/src/org/fox/ttrss/FeedCategoriesFragment.java index a607403c..100826c4 100644 --- a/src/org/fox/ttrss/FeedCategoriesFragment.java +++ b/src/org/fox/ttrss/FeedCategoriesFragment.java @@ -75,38 +75,19 @@ public class FeedCategoriesFragment extends Fragment implements OnItemClickListe ContextMenuInfo menuInfo) { getActivity().getMenuInflater().inflate(R.menu.category_menu, menu); + + AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; + FeedCategory cat = m_adapter.getItem(info.position); + + if (cat != null) + menu.setHeaderTitle(cat.title); + super.onCreateContextMenu(menu, v, menuInfo); } - @Override - public boolean onContextItemSelected(MenuItem item) { - AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); - FeedCategory cat = m_adapter.getItem(info.position); - - Log.d(TAG, "onContextItemSelected=" + cat); - - MainActivity activity = (MainActivity)getActivity(); - - if (cat != null) { - switch (item.getItemId()) { - case R.id.browse_articles: - m_selectedCatId = cat.id; - m_adapter.notifyDataSetChanged(); - activity.viewCategory(cat, true); - break; - case R.id.browse_feeds: - m_selectedCatId = cat.id; - m_adapter.notifyDataSetChanged(); - activity.viewCategory(cat, false); - break; - case R.id.catchup_category: - activity.catchupFeed(new Feed(cat.id, cat.title, true)); - break; - } - } - - return true; + public FeedCategory getCategoryAtPosition(int position) { + return m_adapter.getItem(position); } @Override @@ -358,4 +339,9 @@ public class FeedCategoriesFragment extends Fragment implements OnItemClickListe m_adapter.notifyDataSetChanged(); } } + + public void setSelectedCategory(FeedCategory cat) { + m_selectedCatId = cat.id; + m_adapter.notifyDataSetChanged(); + } } diff --git a/src/org/fox/ttrss/FeedsFragment.java b/src/org/fox/ttrss/FeedsFragment.java index cec324ab..f3ace4fa 100644 --- a/src/org/fox/ttrss/FeedsFragment.java +++ b/src/org/fox/ttrss/FeedsFragment.java @@ -101,31 +101,17 @@ public class FeedsFragment extends Fragment implements OnItemClickListener, OnSh ContextMenuInfo menuInfo) { getActivity().getMenuInflater().inflate(R.menu.feed_menu, menu); + + AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; + Feed feed = m_adapter.getItem(info.position); + + if (feed != null) + menu.setHeaderTitle(feed.title); + super.onCreateContextMenu(menu, v, menuInfo); } - @Override - public boolean onContextItemSelected(MenuItem item) { - AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); - Feed feed = m_adapter.getItem(info.position); - - MainActivity activity = (MainActivity)getActivity(); - - Log.d(TAG, "onContextItemSelected=" + feed); - - if (feed != null) { - switch (item.getItemId()) { - case R.id.catchup_feed: - activity.catchupFeed(feed); - break; - } - } - - return true; - } - - @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -141,10 +127,7 @@ public class FeedsFragment extends Fragment implements OnItemClickListener, OnSh list.setAdapter(m_adapter); list.setOnItemClickListener(this); - // http://code.google.com/p/android/issues/detail?id=20065 - // categories fragment is displayed first, so it hogs the context menu events. thanks, google! - if (!m_prefs.getBoolean("enable_cats", false)) - registerForContextMenu(list); + registerForContextMenu(list); m_enableFeedIcons = m_prefs.getBoolean("download_feed_icons", false); @@ -556,4 +539,8 @@ public class FeedsFragment extends Fragment implements OnItemClickListener, OnSh m_enableFeedIcons = m_prefs.getBoolean("download_feed_icons", false); } + + public Feed getFeedAtPosition(int position) { + return m_adapter.getItem(position); + } } diff --git a/src/org/fox/ttrss/HeadlinesFragment.java b/src/org/fox/ttrss/HeadlinesFragment.java index c717dca8..59c0e5f1 100644 --- a/src/org/fox/ttrss/HeadlinesFragment.java +++ b/src/org/fox/ttrss/HeadlinesFragment.java @@ -17,11 +17,14 @@ import android.os.Bundle; import android.support.v4.app.Fragment; import android.text.Html; import android.util.Log; +import android.view.ContextMenu; import android.view.LayoutInflater; import android.view.View; +import android.view.ContextMenu.ContextMenuInfo; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.AdapterView; +import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.CheckBox; @@ -52,6 +55,22 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener { return m_selectedArticles; } + @Override + public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + + getActivity().getMenuInflater().inflate(R.menu.headlines_menu, menu); + + if (m_selectedArticles.size() > 0) { + menu.setHeaderTitle(R.string.headline_context_multiple); + } else { + menu.setHeaderTitle(R.string.headline_context_single); + } + + super.onCreateContextMenu(menu, v, menuInfo); + + } + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -68,6 +87,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener { m_adapter = new ArticleListAdapter(getActivity(), R.layout.headlines_row, (ArrayList
)m_articles); list.setAdapter(m_adapter); list.setOnItemClickListener(this); + registerForContextMenu(list); Log.d(TAG, "onCreateView, feed=" + m_feed); @@ -194,7 +214,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener { ListView list = (ListView)getView().findViewById(R.id.headlines); if (list != null && m_offset != 0) { - list.setSelection(last_position+1); + list.setSelection(last_position-1); } MainActivity activity = (MainActivity)getActivity(); @@ -403,4 +423,16 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener { m_adapter.notifyDataSetChanged(); } + public Article getArticleAtPosition(int position) { + return m_adapter.getItem(position); + } + + public ArticleList getUnreadArticles() { + ArticleList tmp = new ArticleList(); + for (Article a : m_articles) { + if (a.unread) tmp.add(a); + } + return tmp; + } + } diff --git a/src/org/fox/ttrss/MainActivity.java b/src/org/fox/ttrss/MainActivity.java index 929fba41..7aba8cc7 100644 --- a/src/org/fox/ttrss/MainActivity.java +++ b/src/org/fox/ttrss/MainActivity.java @@ -22,6 +22,7 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.animation.AnimationUtils; +import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.LinearLayout; import android.widget.TextView; @@ -524,6 +525,7 @@ public class MainActivity extends FragmentActivity implements FeedsFragment.OnFe refreshCategories(); } + @SuppressWarnings("unchecked") @Override public boolean onOptionsItemSelected(MenuItem item) { HeadlinesFragment hf = (HeadlinesFragment)getSupportFragmentManager().findFragmentById(R.id.headlines_fragment); @@ -560,43 +562,35 @@ public class MainActivity extends FragmentActivity implements FeedsFragment.OnFe case R.id.headlines_select_unread: if (hf != null) hf.setSelection(HeadlinesFragment.ArticlesSelection.UNREAD); return true; - case R.id.selection_toggle_marked: + case R.id.catchup_and_load: if (hf != null) { - ArticleList selected = hf.getSelectedArticles(); - - if (selected.size() > 0) { - for (Article a : selected) - a.marked = !a.marked; - - toggleArticlesMarked(selected); - hf.notifyUpdated(); - } - } - return true; - case R.id.selection_toggle_published: - if (hf != null) { - ArticleList selected = hf.getSelectedArticles(); - - if (selected.size() > 0) { - for (Article a : selected) - a.published = !a.published; - - toggleArticlesPublished(selected); - hf.notifyUpdated(); - } - } - return true; - case R.id.selection_toggle_unread: - if (hf != null) { - ArticleList selected = hf.getSelectedArticles(); + final ArticleList articles = hf.getUnreadArticles(); - if (selected.size() > 0) { - for (Article a : selected) - a.unread = !a.unread; - - toggleArticlesUnread(selected); - hf.notifyUpdated(); - } + ApiRequest req = new ApiRequest(getApplicationContext()) { + @Override + protected void onPostExecute(JsonElement result) { + if (result != null) { + for (Article a : articles) + a.unread = false; + + viewFeed(m_activeFeed, true); + } + } + }; + + @SuppressWarnings("serial") + HashMap map = new HashMap() { + { + put("sid", m_sessionId); + put("op", "updateArticle"); + put("article_ids", articlesToIdString(articles)); + put("mode", "0"); + put("field", "2"); + } + }; + + req.execute(map); + } return true; case R.id.load_more_articles: @@ -650,7 +644,7 @@ public class MainActivity extends FragmentActivity implements FeedsFragment.OnFe return super.onOptionsItemSelected(item); } } - + public void shareArticle(Article article) { if (article != null) { Intent intent = new Intent(Intent.ACTION_SEND); @@ -1070,6 +1064,117 @@ public class MainActivity extends FragmentActivity implements FeedsFragment.OnFe setLoadingStatus(R.string.login_in_progress, true); } } + + @Override + public boolean onContextItemSelected(MenuItem item) { + AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo(); + + Log.d(TAG, "onContextItemSelected=" + item.getItemId()); + + HeadlinesFragment hf = (HeadlinesFragment)getSupportFragmentManager().findFragmentById(R.id.headlines_fragment); + FeedsFragment ff = (FeedsFragment)getSupportFragmentManager().findFragmentById(R.id.feeds_fragment); + FeedCategoriesFragment cf = (FeedCategoriesFragment)getSupportFragmentManager().findFragmentById(R.id.cats_fragment); + + switch (item.getItemId()) { + case R.id.browse_articles: + if (cf != null) { + FeedCategory cat = cf.getCategoryAtPosition(info.position); + if (cat != null) { + viewCategory(cat, true); + cf.setSelectedCategory(cat); + } + } + break; + case R.id.browse_feeds: + if (cf != null) { + FeedCategory cat = cf.getCategoryAtPosition(info.position); + if (cat != null) { + viewCategory(cat, false); + cf.setSelectedCategory(cat); + } + } + break; + case R.id.catchup_category: + if (cf != null) { + FeedCategory cat = cf.getCategoryAtPosition(info.position); + if (cat != null) { + catchupFeed(new Feed(cat.id, cat.title, true)); + } + } + break; + case R.id.catchup_feed: + if (ff != null) { + Feed feed = ff.getFeedAtPosition(info.position); + if (feed != null) { + catchupFeed(feed); + } + } + break; + case R.id.selection_toggle_marked: + if (hf != null) { + ArticleList selected = hf.getSelectedArticles(); + + if (selected.size() > 0) { + for (Article a : selected) + a.marked = !a.marked; + + toggleArticlesMarked(selected); + hf.notifyUpdated(); + } else { + Article article = hf.getArticleAtPosition(info.position); + if (article != null) { + article.marked = !article.marked; + saveArticleMarked(article); + hf.notifyUpdated(); + } + } + } + return true; + case R.id.selection_toggle_published: + if (hf != null) { + ArticleList selected = hf.getSelectedArticles(); + + if (selected.size() > 0) { + for (Article a : selected) + a.published = !a.published; + + toggleArticlesPublished(selected); + hf.notifyUpdated(); + } else { + Article article = hf.getArticleAtPosition(info.position); + if (article != null) { + article.published = !article.published; + saveArticlePublished(article); + hf.notifyUpdated(); + } + } + } + return true; + case R.id.selection_toggle_unread: + if (hf != null) { + ArticleList selected = hf.getSelectedArticles(); + + if (selected.size() > 0) { + for (Article a : selected) + a.unread = !a.unread; + + toggleArticlesUnread(selected); + hf.notifyUpdated(); + } else { + Article article = hf.getArticleAtPosition(info.position); + if (article != null) { + article.unread = !article.unread; + saveArticleUnread(article); + hf.notifyUpdated(); + } + } + } + return true; + } + + return true; + } + @Override public Article getRelativeArticle(Article article, RelativeArticle ra) {