package org.fox.ttrss; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Timer; import java.util.TimerTask; import org.fox.ttrss.offline.OfflineActivity; import org.fox.ttrss.offline.OfflineDownloadService; import org.fox.ttrss.offline.OfflineUploadService; import org.fox.ttrss.types.Article; import org.fox.ttrss.types.ArticleList; import org.fox.ttrss.types.Feed; import org.fox.ttrss.types.FeedCategory; import org.fox.ttrss.types.Label; import org.fox.ttrss.util.AppRater; import android.animation.LayoutTransition; import android.annotation.SuppressLint; import android.app.ActionBar; import android.app.AlertDialog; import android.app.Dialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.DialogInterface.OnMultiChoiceClickListener; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.database.Cursor; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; import android.util.Log; import android.view.ActionMode; import android.view.KeyEvent; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.SearchView; import android.widget.ShareActionProvider; import android.widget.TextView; import android.widget.Toast; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.reflect.TypeToken; public class MainActivity extends CommonActivity implements OnlineServices { private final String TAG = this.getClass().getSimpleName(); private SharedPreferences m_prefs; private String m_themeName = ""; private String m_sessionId; private Article m_selectedArticle; private Feed m_activeFeed; private FeedCategory m_activeCategory; private Timer m_refreshTimer; private RefreshTask m_refreshTask; private Menu m_menu; private boolean m_unreadOnly = true; private boolean m_unreadArticlesOnly = true; private boolean m_enableCats = false; private int m_apiLevel = 0; private boolean m_isLoggingIn = false; private boolean m_isOffline = false; private int m_offlineModeStatus = 0; private int m_selectedProduct = -1; private long m_lastRefresh = 0; private ActionMode m_headlinesActionMode; private HeadlinesActionModeCallback m_headlinesActionModeCallback; private NavigationListener m_navigationListener; private NavigationAdapter m_navigationAdapter; private ArrayList m_navigationEntries = new ArrayList(); private class NavigationListener implements ActionBar.OnNavigationListener { @Override public boolean onNavigationItemSelected(int itemPosition, long itemId) { Log.d(TAG, "onNavigationItemSelected: " + itemPosition); NavigationEntry entry = m_navigationAdapter.getItem(itemPosition); entry._onItemSelected(itemPosition, m_navigationAdapter.getCount()-1); return false; } } private class ArticleNavigationEntry extends NavigationEntry { public ArticleNavigationEntry(Article article) { super(article.title); } @Override public void onItemSelected() { } } private class RootNavigationEntry extends NavigationEntry { public RootNavigationEntry(String title) { super(title); } @Override public void onItemSelected() { FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); m_activeFeed = null; m_selectedArticle = null; m_activeCategory = null; if (isSmallScreen()) { if (m_enableCats) { ft.replace(R.id.fragment_container, new FeedCategoriesFragment(), FRAG_CATS); } else { ft.replace(R.id.fragment_container, new FeedsFragment(), FRAG_FEEDS); } Fragment hf = getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); if (hf != null) ft.remove(hf); Fragment af = getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); if (af != null) ft.remove(af); } else { if (m_enableCats) { ft.replace(R.id.feeds_fragment, new FeedCategoriesFragment(), FRAG_CATS); } else { ft.replace(R.id.feeds_fragment, new FeedsFragment(), FRAG_FEEDS); } findViewById(R.id.article_fragment).setVisibility(View.GONE); findViewById(R.id.feeds_fragment).setVisibility(View.VISIBLE); ft.replace(R.id.headlines_fragment, new DummyFragment(), ""); } ft.commit(); initMainMenu(); } } private class CategoryNavigationEntry extends NavigationEntry { FeedCategory m_category = null; public CategoryNavigationEntry(FeedCategory category) { super(category.title); m_category = category; } @Override public void onItemSelected() { m_selectedArticle = null; FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); if (isSmallScreen()) { Fragment hf = getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); if (hf != null) ft.remove(hf); Fragment af = getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); if (af != null) ft.remove(af); if (m_activeFeed.is_cat) { FeedCategoriesFragment cats = (FeedCategoriesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_CATS); ft.show(cats); cats.setSelectedCategory(null); } else { FeedsFragment feeds = (FeedsFragment) getSupportFragmentManager().findFragmentByTag(FRAG_FEEDS); ft.show(feeds); feeds.setSelectedFeed(null); } } else { findViewById(R.id.article_fragment).setVisibility(View.GONE); findViewById(R.id.feeds_fragment).setVisibility(View.VISIBLE); updateHeadlines(); //ft.replace(R.id.headlines_fragment, new DummyFragment(), ""); } ft.commit(); m_activeFeed = null; refresh(); initMainMenu(); } } private class FeedNavigationEntry extends NavigationEntry { Feed m_feed = null; public FeedNavigationEntry(Feed feed) { super(feed.title); m_feed = feed; } @Override public void onItemSelected() { m_selectedArticle = null; if (!isSmallScreen()) findViewById(R.id.article_fragment).setVisibility(View.GONE); viewFeed(m_feed, false); } } private abstract class NavigationEntry { private String title = null; private int timesCalled = 0; public void _onItemSelected(int position, int size) { Log.d(TAG, "_onItemSelected; TC=" + timesCalled + " P/S=" + position + "/" + size); if (position == size && timesCalled == 0) { ++timesCalled; } else { onItemSelected(); } } public NavigationEntry(String title) { this.title = title; } public String toString() { return title; } public abstract void onItemSelected(); } private class NavigationAdapter extends ArrayAdapter { public NavigationAdapter(Context context, int textViewResourceId, ArrayList items) { super(context, textViewResourceId, items); } } private class HeadlinesActionModeCallback implements ActionMode.Callback { @Override public boolean onPrepareActionMode(ActionMode mode, Menu menu) { return false; } @Override public void onDestroyActionMode(ActionMode mode) { deselectAllArticles(); m_headlinesActionMode = null; } @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.headlines_action_menu, menu); return true; } @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { onOptionsItemSelected(item); return false; } }; private BroadcastReceiver m_broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context content, Intent intent) { if (intent.getAction().equals(OfflineDownloadService.INTENT_ACTION_SUCCESS)) { m_offlineModeStatus = 2; switchOffline(); } else if (intent.getAction().equals(OfflineUploadService.INTENT_ACTION_SUCCESS)) { //Log.d(TAG, "offline upload service reports success"); refresh(); Toast toast = Toast.makeText(MainActivity.this, R.string.offline_sync_success, Toast.LENGTH_SHORT); toast.show(); } } }; public void updateHeadlines() { HeadlinesFragment frag = (HeadlinesFragment) getSupportFragmentManager() .findFragmentByTag(FRAG_HEADLINES); if (frag != null) { frag.setActiveArticle(m_selectedArticle); } } @Override public int getApiLevel() { return m_apiLevel; } private boolean hasPendingOfflineData() { try { Cursor c = getReadableDb().query("articles", new String[] { "COUNT(*)" }, "modified = 1", null, null, null, null); if (c.moveToFirst()) { int modified = c.getInt(0); c.close(); return modified > 0; } } catch (IllegalStateException e) { // db is closed? ugh } return false; } private boolean hasOfflineData() { try { Cursor c = getReadableDb().query("articles", new String[] { "COUNT(*)" }, null, null, null, null, null); if (c.moveToFirst()) { int modified = c.getInt(0); c.close(); return modified > 0; } } catch (IllegalStateException e) { // db is closed? } return false; } @SuppressWarnings({ "unchecked", "serial" }) public void saveArticleUnread(final Article article) { ApiRequest req = new ApiRequest(getApplicationContext()); HashMap map = new HashMap() { { put("sid", m_sessionId); put("op", "updateArticle"); put("article_ids", String.valueOf(article.id)); put("mode", article.unread ? "1" : "0"); put("field", "2"); } }; req.execute(map); } @SuppressWarnings({ "unchecked", "serial" }) public void saveArticleMarked(final Article article) { ApiRequest req = new ApiRequest(getApplicationContext()); HashMap map = new HashMap() { { put("sid", m_sessionId); put("op", "updateArticle"); put("article_ids", String.valueOf(article.id)); put("mode", article.marked ? "1" : "0"); put("field", "0"); } }; req.execute(map); } @SuppressWarnings({ "unchecked", "serial" }) public void saveArticlePublished(final Article article) { ApiRequest req = new ApiRequest(getApplicationContext()); HashMap map = new HashMap() { { put("sid", m_sessionId); put("op", "updateArticle"); put("article_ids", String.valueOf(article.id)); put("mode", article.published ? "1" : "0"); put("field", "1"); } }; req.execute(map); } @SuppressWarnings({ "unchecked", "serial" }) public void saveArticleNote(final Article article, final String note) { ApiRequest req = new ApiRequest(getApplicationContext()); HashMap map = new HashMap() { { put("sid", m_sessionId); put("op", "updateArticle"); put("article_ids", String.valueOf(article.id)); put("mode", "1"); put("data", note); put("field", "3"); } }; 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 catchupFeed(final Feed feed) { Log.d(TAG, "catchupFeed=" + feed); ApiRequest req = new ApiRequest(getApplicationContext()) { protected void onPostExecute(JsonElement result) { refresh(); } }; @SuppressWarnings("serial") HashMap map = new HashMap() { { put("sid", m_sessionId); put("op", "catchupFeed"); put("feed_id", String.valueOf(feed.id)); if (feed.is_cat) put("is_cat", "1"); } }; req.execute(map); } @SuppressWarnings("unchecked") private 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") private 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); refresh(); } @SuppressWarnings("unchecked") private 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 public void run() { ConnectivityManager cm = (ConnectivityManager) getApplicationContext() .getSystemService(Context.CONNECTIVITY_SERVICE); if (cm.getBackgroundDataSetting()) { NetworkInfo networkInfo = cm.getActiveNetworkInfo(); if (networkInfo != null && networkInfo.isAvailable() && networkInfo.isConnected()) { runOnUiThread(new Runnable() { @Override public void run() { refresh(); } }); } } } } private synchronized void refresh() { Date date = new Date(); if (m_sessionId != null && date.getTime() - m_lastRefresh > 5000) { FeedsFragment ff = (FeedsFragment) getSupportFragmentManager() .findFragmentByTag(FRAG_FEEDS); if (ff != null) { Log.d(TAG, "Refreshing feeds/" + m_activeFeed); ff.refresh(true); } FeedCategoriesFragment cf = (FeedCategoriesFragment) getSupportFragmentManager() .findFragmentByTag(FRAG_CATS); if (cf != null) { Log.d(TAG, "Refreshing categories/" + m_activeCategory); cf.refresh(true); } m_lastRefresh = date.getTime(); } } /* private synchronized void refreshHeadlines() { if (m_sessionId != null) { HeadlinesFragment frag = (HeadlinesFragment) getSupportFragmentManager() .findFragmentByTag(FRAG_HEADLINES); Log.d(TAG, "Refreshing headlines..."); if (frag != null) { frag.refresh(true); } } } */ private void setUnreadOnly(boolean unread) { m_unreadOnly = unread; m_lastRefresh = 0; refresh(); } @Override public boolean getUnreadOnly() { return m_unreadOnly; } @Override public boolean getUnreadArticlesOnly() { return m_unreadArticlesOnly; } @Override public String getSessionId() { return m_sessionId; } @Override public void onCreate(Bundle savedInstanceState) { m_prefs = PreferenceManager .getDefaultSharedPreferences(getApplicationContext()); if (m_prefs.getString("theme", "THEME_DARK").equals("THEME_DARK")) { setTheme(R.style.DarkTheme); } else { setTheme(R.style.LightTheme); } super.onCreate(savedInstanceState); if (OfflineDownloadService.INTENT_ACTION_CANCEL.equals(getIntent().getAction())) { cancelOfflineSync(); } //Log.d(TAG, "started with intent action=" + intentAction); requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); m_themeName = m_prefs.getString("theme", "THEME_DARK"); if (savedInstanceState != null) { m_sessionId = savedInstanceState.getString("sessionId"); m_unreadOnly = savedInstanceState.getBoolean("unreadOnly"); m_activeFeed = savedInstanceState.getParcelable("activeFeed"); m_selectedArticle = savedInstanceState .getParcelable("selectedArticle"); m_unreadArticlesOnly = savedInstanceState .getBoolean("unreadArticlesOnly"); m_activeCategory = savedInstanceState .getParcelable("activeCategory"); m_apiLevel = savedInstanceState.getInt("apiLevel"); m_offlineModeStatus = savedInstanceState.getInt("offlineModeStatus"); } m_enableCats = m_prefs.getBoolean("enable_cats", false); setContentView(R.layout.main); setSmallScreen(findViewById(R.id.headlines_fragment) == null); IntentFilter filter = new IntentFilter(); filter.addAction(OfflineDownloadService.INTENT_ACTION_SUCCESS); filter.addAction(OfflineUploadService.INTENT_ACTION_SUCCESS); filter.addCategory(Intent.CATEGORY_DEFAULT); registerReceiver(m_broadcastReceiver, filter); SharedPreferences localPrefs = getSharedPreferences("localprefs", Context.MODE_PRIVATE); m_isOffline = localPrefs.getBoolean("offline_mode_active", false); Log.d(TAG, "m_isOffline=" + m_isOffline); if (!isCompatMode()) { if (!isSmallScreen()) { findViewById(R.id.feeds_fragment).setVisibility(m_selectedArticle != null && (isPortrait() || isSmallTablet()) ? View.GONE : View.VISIBLE); findViewById(R.id.article_fragment).setVisibility(m_selectedArticle != null ? View.VISIBLE : View.GONE); } LayoutTransition transitioner = new LayoutTransition(); ((ViewGroup) findViewById(R.id.fragment_container)).setLayoutTransition(transitioner); m_navigationAdapter = new NavigationAdapter(this, android.R.layout.simple_spinner_dropdown_item, m_navigationEntries); m_headlinesActionModeCallback = new HeadlinesActionModeCallback(); m_navigationListener = new NavigationListener(); getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); getActionBar().setListNavigationCallbacks(m_navigationAdapter, m_navigationListener); } if (isSmallScreen()) { FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); // temporary workaround against viewpager going a bit crazy when restoring after rotation if (m_selectedArticle != null) { ft.remove(getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE)); m_selectedArticle = null; } if (m_activeFeed != null) { if (m_activeFeed.is_cat) { ft.hide(getSupportFragmentManager().findFragmentByTag(FRAG_CATS)); } else { ft.hide(getSupportFragmentManager().findFragmentByTag(FRAG_FEEDS)); } } ft.commit(); } if (m_isOffline) { Intent offline = new Intent(MainActivity.this, OfflineActivity.class); startActivity(offline); finish(); } else { //AppRater.showRateDialog(this, null); AppRater.appLaunched(this); if (m_sessionId != null) { loginSuccess(); } else { //login(); -- handled in onResume() } } } private void switchOffline() { if (m_offlineModeStatus == 2) { AlertDialog.Builder builder = new AlertDialog.Builder( MainActivity.this) .setMessage(R.string.dialog_offline_success) .setPositiveButton(R.string.dialog_offline_go, new Dialog.OnClickListener() { public void onClick(DialogInterface dialog, int which) { m_offlineModeStatus = 0; SharedPreferences localPrefs = getSharedPreferences("localprefs", Context.MODE_PRIVATE); SharedPreferences.Editor editor = localPrefs.edit(); editor.putBoolean("offline_mode_active", true); editor.commit(); Intent refresh = new Intent( MainActivity.this, OfflineActivity.class); startActivity(refresh); finish(); } }) .setNegativeButton(R.string.dialog_cancel, new Dialog.OnClickListener() { public void onClick(DialogInterface dialog, int which) { m_offlineModeStatus = 0; } }); AlertDialog dlg = builder.create(); dlg.show(); } else if (m_offlineModeStatus == 0) { AlertDialog.Builder builder = new AlertDialog.Builder(this) .setMessage(R.string.dialog_offline_switch_prompt) .setPositiveButton(R.string.dialog_offline_go, new Dialog.OnClickListener() { public void onClick(DialogInterface dialog, int which) { if (m_sessionId != null) { Log.d(TAG, "offline: starting"); m_offlineModeStatus = 1; Intent intent = new Intent( MainActivity.this, OfflineDownloadService.class); intent.putExtra("sessionId", m_sessionId); startService(intent); } } }) .setNegativeButton(R.string.dialog_cancel, new Dialog.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // } }); AlertDialog dlg = builder.create(); dlg.show(); } else if (m_offlineModeStatus == 1) { cancelOfflineSync(); } } private void cancelOfflineSync() { AlertDialog.Builder builder = new AlertDialog.Builder(this) .setMessage(R.string.dialog_offline_sync_in_progress) .setNegativeButton(R.string.dialog_offline_sync_stop, new Dialog.OnClickListener() { public void onClick(DialogInterface dialog, int which) { if (m_sessionId != null) { Log.d(TAG, "offline: stopping"); m_offlineModeStatus = 0; Intent intent = new Intent( MainActivity.this, OfflineDownloadService.class); stopService(intent); dialog.dismiss(); restart(); } } }) .setPositiveButton(R.string.dialog_offline_sync_continue, new Dialog.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); restart(); } }); AlertDialog dlg = builder.create(); dlg.show(); } private void switchOfflineSuccess() { logout(); // setLoadingStatus(R.string.blank, false); SharedPreferences.Editor editor = m_prefs.edit(); editor.putBoolean("offline_mode_active", true); editor.commit(); Intent offline = new Intent(MainActivity.this, OfflineActivity.class); startActivity(offline); finish(); } private void setLoadingStatus(int status, boolean showProgress) { TextView tv = (TextView) findViewById(R.id.loading_message); if (tv != null) { tv.setText(status); } setProgressBarIndeterminateVisibility(showProgress); } @Override public void onSaveInstanceState(Bundle out) { super.onSaveInstanceState(out); out.putString("sessionId", m_sessionId); out.putBoolean("unreadOnly", m_unreadOnly); out.putParcelable("activeFeed", m_activeFeed); out.putParcelable("selectedArticle", m_selectedArticle); out.putBoolean("unreadArticlesOnly", m_unreadArticlesOnly); out.putParcelable("activeCategory", m_activeCategory); out.putInt("apiLevel", m_apiLevel); out.putInt("offlineModeStatus", m_offlineModeStatus); } @Override public void onResume() { super.onResume(); boolean needRefresh = !m_prefs.getString("theme", "THEME_DARK").equals( m_themeName) || m_prefs.getBoolean("enable_cats", false) != m_enableCats; if (needRefresh) { restart(); } else if (m_sessionId != null) { m_refreshTask = new RefreshTask(); m_refreshTimer = new Timer("Refresh"); m_refreshTimer.schedule(m_refreshTask, 60 * 1000L, 120 * 1000L); } else { if (!m_isLoggingIn) { login(); } } } @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.main_menu, menu); m_menu = menu; initMainMenu(); MenuItem item = menu.findItem(R.id.show_feeds); if (getUnreadOnly()) { item.setTitle(R.string.menu_all_feeds); } else { item.setTitle(R.string.menu_unread_feeds); } /* * item = menu.findItem(R.id.show_all_articles); * * if (getUnreadArticlesOnly()) { * item.setTitle(R.string.show_all_articles); } else { * item.setTitle(R.string.show_unread_articles); } */ return true; } private void setMenuLabel(int id, int labelId) { MenuItem mi = m_menu.findItem(id); if (mi != null) { mi.setTitle(labelId); } } @Override public void onBackPressed() { goBack(true); } private void closeCategory() { m_activeCategory = null; FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); if (isSmallScreen()) { ft.replace(R.id.fragment_container, new FeedCategoriesFragment(), FRAG_CATS); } else { ft.replace(R.id.feeds_fragment, new FeedCategoriesFragment(), FRAG_CATS); } ft.commit(); initMainMenu(); refresh(); } private void deselectAllArticles() { HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager() .findFragmentByTag(FRAG_HEADLINES); if (hf != null) { ArticleList selected = hf.getSelectedArticles(); if (selected.size() > 0) { selected.clear(); initMainMenu(); updateHeadlines(); } } } private void goBack(boolean allowQuit) { if (isSmallScreen()) { if (m_selectedArticle != null) { closeArticle(); } else if (m_activeFeed != null) { FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); if (m_activeFeed.is_cat) { Fragment headlines = getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); FeedCategoriesFragment cats = (FeedCategoriesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_CATS); ft.show(cats); ft.remove(headlines); } else { Fragment headlines = getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); FeedsFragment feeds = (FeedsFragment) getSupportFragmentManager().findFragmentByTag(FRAG_FEEDS); ft.show(feeds); ft.remove(headlines); } ft.commit(); m_activeFeed = null; refresh(); initMainMenu(); } else if (m_activeCategory != null) { closeCategory(); } else if (allowQuit) { finish(); } } else { if (m_selectedArticle != null) { closeArticle(); refresh(); } else if (m_activeFeed != null) { closeFeed(); } else if (m_activeCategory != null) { closeCategory(); } else if (allowQuit) { finish(); } } } private void closeFeed() { if (m_activeFeed != null) { FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.replace(R.id.headlines_fragment, new DummyFragment(), ""); ft.commit(); if (m_activeFeed.is_cat) { FeedCategoriesFragment cats = (FeedCategoriesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_CATS); cats.setSelectedCategory(null); } else { FeedsFragment feeds = (FeedsFragment) getSupportFragmentManager().findFragmentByTag(FRAG_FEEDS); feeds.setSelectedFeed(null); } m_activeFeed = null; initMainMenu(); } } @SuppressWarnings("unchecked") @Override public boolean onOptionsItemSelected(MenuItem item) { final HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager() .findFragmentByTag(FRAG_HEADLINES); switch (item.getItemId()) { case R.id.close_feed: if (m_activeFeed != null) { FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.replace(R.id.headlines_fragment, new DummyFragment(), ""); ft.commit(); if (m_activeFeed.is_cat) { FeedCategoriesFragment cats = (FeedCategoriesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_CATS); cats.setSelectedCategory(null); } else { FeedsFragment feeds = (FeedsFragment) getSupportFragmentManager().findFragmentByTag(FRAG_FEEDS); feeds.setSelectedFeed(null); } m_activeFeed = null; initMainMenu(); } return true; case R.id.close_article: closeArticle(); return true; case android.R.id.home: goBack(false); return true; case R.id.search: if (hf != null && isCompatMode()) { Dialog dialog = new Dialog(this); final EditText edit = new EditText(this); AlertDialog.Builder builder = new AlertDialog.Builder(this) .setTitle(R.string.search) .setPositiveButton(getString(R.string.search), new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { String query = edit.getText().toString().trim(); hf.setSearchQuery(query); } }) .setNegativeButton(getString(R.string.cancel), new OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // } }).setView(edit); dialog = builder.create(); dialog.show(); } return true; case R.id.preferences: Intent intent = new Intent(MainActivity.this, PreferencesActivity.class); startActivityForResult(intent, 0); return true; case R.id.update_feeds: m_lastRefresh = 0; refresh(); return true; case R.id.logout: logout(); return true; case R.id.login: login(); return true; case R.id.go_offline: switchOffline(); return true; case R.id.article_set_note: if (m_selectedArticle != null) { editArticleNote(m_selectedArticle); } return true; case R.id.headlines_select: if (hf != null) { Dialog dialog = new Dialog(this); AlertDialog.Builder builder = new AlertDialog.Builder(this) .setTitle(R.string.headlines_select_dialog) .setSingleChoiceItems( new String[] { getString(R.string.headlines_select_all), getString(R.string.headlines_select_unread), getString(R.string.headlines_select_none) }, 0, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { switch (which) { case 0: hf.setSelection(HeadlinesFragment.ArticlesSelection.ALL); break; case 1: hf.setSelection(HeadlinesFragment.ArticlesSelection.UNREAD); break; case 2: hf.setSelection(HeadlinesFragment.ArticlesSelection.NONE); break; } dialog.cancel(); initMainMenu(); } }); dialog = builder.create(); dialog.show(); } return true; case R.id.headlines_mark_as_read: if (hf != null) { ArticleList articles = hf.getUnreadArticles(); for (Article a : articles) a.unread = false; updateHeadlines(); ApiRequest req = new ApiRequest(getApplicationContext()); final String articleIds = articlesToIdString(articles); @SuppressWarnings("serial") HashMap map = new HashMap() { { put("sid", m_sessionId); put("op", "updateArticle"); put("article_ids", articleIds); put("mode", "0"); put("field", "2"); } }; req.execute(map); refresh(); } return true; case R.id.share_article: if (android.os.Build.VERSION.SDK_INT < 14) { shareArticle(m_selectedArticle); } return true; case R.id.toggle_marked: if (m_selectedArticle != null) { m_selectedArticle.marked = !m_selectedArticle.marked; saveArticleMarked(m_selectedArticle); updateHeadlines(); } return true; case R.id.selection_select_none: deselectAllArticles(); 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); updateHeadlines(); } refresh(); } 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); updateHeadlines(); } } 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); updateHeadlines(); } } return true; case R.id.toggle_published: if (m_selectedArticle != null) { m_selectedArticle.published = !m_selectedArticle.published; saveArticlePublished(m_selectedArticle); updateHeadlines(); } return true; case R.id.catchup_above: if (hf != null) { if (m_selectedArticle != null) { ArticleList articles = hf.getAllArticles(); ArticleList tmp = new ArticleList(); for (Article a : articles) { a.unread = false; tmp.add(a); if (m_selectedArticle.id == a.id) break; } if (tmp.size() > 0) { toggleArticlesUnread(tmp); updateHeadlines(); } } } return true; case R.id.set_unread: if (m_selectedArticle != null) { m_selectedArticle.unread = true; saveArticleUnread(m_selectedArticle); updateHeadlines(); } return true; case R.id.show_feeds: setUnreadOnly(!getUnreadOnly()); if (getUnreadOnly()) { item.setTitle(R.string.menu_all_feeds); } else { item.setTitle(R.string.menu_unread_feeds); } return true; case R.id.set_labels: if (m_selectedArticle != null) { editArticleLabels(m_selectedArticle); } return true; default: Log.d(TAG, "onOptionsItemSelected, unhandled id=" + item.getItemId()); return super.onOptionsItemSelected(item); } } private void editArticleNote(final Article article) { String note = ""; AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle(article.title); final EditText topicEdit = new EditText(this); topicEdit.setText(note); builder.setView(topicEdit); builder.setPositiveButton(R.string.article_set_note, new Dialog.OnClickListener() { public void onClick(DialogInterface dialog, int which) { saveArticleNote(article, topicEdit.getText().toString().trim()); article.published = true; saveArticlePublished(article); updateHeadlines(); } }); builder.setNegativeButton(R.string.dialog_cancel, new Dialog.OnClickListener() { public void onClick(DialogInterface dialog, int which) { // } }); AlertDialog dialog = builder.create(); dialog.show(); } private void editArticleLabels(Article article) { final int articleId = article.id; ApiRequest req = new ApiRequest(getApplicationContext()) { @Override protected void onPostExecute(JsonElement result) { if (result != null) { Type listType = new TypeToken>() {}.getType(); final List