From c8f79f546557bb624740c59ac44b8ed814c944db Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Tue, 29 Nov 2011 14:09:27 +0300 Subject: [PATCH] implement batch actions on selected articles --- res/menu/category_menu.xml | 4 +- res/menu/main_menu.xml | 32 +++++ res/values/strings.xml | 8 ++ src/org/fox/ttrss/FeedCategoriesFragment.java | 1 - src/org/fox/ttrss/FeedsFragment.java | 1 - src/org/fox/ttrss/HeadlinesFragment.java | 34 ++++-- src/org/fox/ttrss/MainActivity.java | 115 ++++++++++++++++++ 7 files changed, 181 insertions(+), 14 deletions(-) diff --git a/res/menu/category_menu.xml b/res/menu/category_menu.xml index d437a0ca..59ff8f8c 100644 --- a/res/menu/category_menu.xml +++ b/res/menu/category_menu.xml @@ -2,10 +2,10 @@ + android:title="@string/category_browse_articles"/> + android:title="@string/category_browse_feeds"/> \ No newline at end of file diff --git a/res/menu/main_menu.xml b/res/menu/main_menu.xml index 76471811..a23bcb61 100644 --- a/res/menu/main_menu.xml +++ b/res/menu/main_menu.xml @@ -42,6 +42,38 @@ android:icon="@android:drawable/ic_menu_agenda" android:showAsAction="" android:title="@string/show_all_articles"/> + + + + + + + + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index 6f2f0a8c..c73be87f 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -37,10 +37,18 @@ Show all articles Show unread articles Accept any SSL certificate + Browse feeds + Browse articles Log sent and received data Toggle starred Toggle published + Select all + Select none + Select unread + Toggle starred + Toggle published + Toggle 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 diff --git a/src/org/fox/ttrss/FeedCategoriesFragment.java b/src/org/fox/ttrss/FeedCategoriesFragment.java index ea9c433a..c2f4f298 100644 --- a/src/org/fox/ttrss/FeedCategoriesFragment.java +++ b/src/org/fox/ttrss/FeedCategoriesFragment.java @@ -14,7 +14,6 @@ import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v4.app.Fragment; -import android.util.Log; import android.view.ContextMenu; import android.view.ContextMenu.ContextMenuInfo; import android.view.LayoutInflater; diff --git a/src/org/fox/ttrss/FeedsFragment.java b/src/org/fox/ttrss/FeedsFragment.java index 4fb7c404..de30ed6e 100644 --- a/src/org/fox/ttrss/FeedsFragment.java +++ b/src/org/fox/ttrss/FeedsFragment.java @@ -45,7 +45,6 @@ import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.ImageView; -import android.widget.ImageView.ScaleType; import android.widget.ListView; import android.widget.TextView; diff --git a/src/org/fox/ttrss/HeadlinesFragment.java b/src/org/fox/ttrss/HeadlinesFragment.java index 63fa52f9..3e183c95 100644 --- a/src/org/fox/ttrss/HeadlinesFragment.java +++ b/src/org/fox/ttrss/HeadlinesFragment.java @@ -25,8 +25,6 @@ import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.CompoundButton.OnCheckedChangeListener; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; @@ -37,6 +35,8 @@ import com.google.gson.JsonElement; import com.google.gson.reflect.TypeToken; public class HeadlinesFragment extends Fragment implements OnItemClickListener { + public static enum ArticlesSelection { ALL, NONE, UNREAD }; + private final String TAG = this.getClass().getSimpleName(); private Feed m_feed; @@ -345,20 +345,20 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener { if (cb != null) { cb.setChecked(m_selectedArticles.contains(article)); - - cb.setOnCheckedChangeListener(new OnCheckedChangeListener() { + cb.setOnClickListener(new OnClickListener() { + @Override - public void onCheckedChanged(CompoundButton buttonView, - boolean isChecked) { - - if (isChecked) { - m_selectedArticles.add(article); + public void onClick(View view) { + CheckBox cb = (CheckBox)view; + + if (cb.isChecked()) { + if (!m_selectedArticles.contains(article)) + m_selectedArticles.add(article); } else { m_selectedArticles.remove(article); } Log.d(TAG, "num selected: " + m_selectedArticles.size()); - } }); } @@ -389,4 +389,18 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener { } } + public void setSelection(ArticlesSelection select) { + m_selectedArticles.clear(); + + if (select != ArticlesSelection.NONE) { + for (Article a : m_articles) { + if (select == ArticlesSelection.ALL || select == ArticlesSelection.UNREAD && a.unread) { + m_selectedArticles.add(a); + } + } + } + + m_adapter.notifyDataSetChanged(); + } + } diff --git a/src/org/fox/ttrss/MainActivity.java b/src/org/fox/ttrss/MainActivity.java index 66066465..50e4805e 100644 --- a/src/org/fox/ttrss/MainActivity.java +++ b/src/org/fox/ttrss/MainActivity.java @@ -110,6 +110,69 @@ public class MainActivity extends FragmentActivity implements FeedsFragment.OnFe req.execute(map); } + public static String articlesToIdString(ArticleList articles) { + String tmp = ""; + + for (Article a : articles) + tmp += String.valueOf(a.id) + ","; + + return tmp.replaceAll(",$", ""); + } + + @SuppressWarnings("unchecked") + public void toggleArticlesMarked(final ArticleList articles) { + ApiRequest req = new ApiRequest(getApplicationContext()); + + @SuppressWarnings("serial") + HashMap map = new HashMap() { + { + put("sid", m_sessionId); + put("op", "updateArticle"); + put("article_ids", articlesToIdString(articles)); + put("mode", "2"); + put("field", "0"); + } + }; + + req.execute(map); + } + + @SuppressWarnings("unchecked") + public void toggleArticlesUnread(final ArticleList articles) { + ApiRequest req = new ApiRequest(getApplicationContext()); + + @SuppressWarnings("serial") + HashMap map = new HashMap() { + { + put("sid", m_sessionId); + put("op", "updateArticle"); + put("article_ids", articlesToIdString(articles)); + put("mode", "2"); + put("field", "2"); + } + }; + + req.execute(map); + } + + @SuppressWarnings("unchecked") + public void toggleArticlesPublished(final ArticleList articles) { + ApiRequest req = new ApiRequest(getApplicationContext()); + + @SuppressWarnings("serial") + HashMap map = new HashMap() { + { + put("sid", m_sessionId); + put("op", "updateArticle"); + put("article_ids", articlesToIdString(articles)); + put("mode", "2"); + put("field", "1"); + } + }; + + req.execute(map); + } + private class RefreshTask extends TimerTask { @Override @@ -436,6 +499,8 @@ public class MainActivity extends FragmentActivity implements FeedsFragment.OnFe @Override public boolean onOptionsItemSelected(MenuItem item) { + HeadlinesFragment hf = (HeadlinesFragment)getSupportFragmentManager().findFragmentById(R.id.headlines_fragment); + switch (item.getItemId()) { case R.id.preferences: Intent intent = new Intent(this, PreferencesActivity.class); @@ -459,6 +524,54 @@ public class MainActivity extends FragmentActivity implements FeedsFragment.OnFe case R.id.back_to_categories: closeCategory(); return true; + case R.id.headlines_select_all: + if (hf != null) hf.setSelection(HeadlinesFragment.ArticlesSelection.ALL); + return true; + case R.id.headlines_select_none: + if (hf != null) hf.setSelection(HeadlinesFragment.ArticlesSelection.NONE); + return true; + case R.id.headlines_select_unread: + if (hf != null) hf.setSelection(HeadlinesFragment.ArticlesSelection.UNREAD); + return true; + 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(); + } + } + 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(); + + if (selected.size() > 0) { + for (Article a : selected) + a.unread = !a.unread; + + toggleArticlesUnread(selected); + hf.notifyUpdated(); + } + } + return true; case R.id.load_more_articles: viewFeed(m_activeFeed, true); return true; @@ -698,6 +811,7 @@ public class MainActivity extends FragmentActivity implements FeedsFragment.OnFe super(context); } + @SuppressWarnings("unchecked") protected void onPostExecute(JsonElement result) { if (result != null) { try { @@ -732,6 +846,7 @@ public class MainActivity extends FragmentActivity implements FeedsFragment.OnFe } }; + @SuppressWarnings("serial") HashMap map = new HashMap() { { put("sid", m_sessionId);