diff options
| author | Andrew Dolgov <fox@fakecake.org> | 2013-04-21 17:01:26 +0400 |
|---|---|---|
| committer | Andrew Dolgov <fox@fakecake.org> | 2013-04-21 17:01:26 +0400 |
| commit | 0b2345344bb16bdb70470b630008e194e3a0133c (patch) | |
| tree | e0a09ed38e37ef358d67a2c9b0ed81ceb5421d63 /src/org/fox/ttrss/offline | |
| parent | b67e6ff9c54ef7f377ffc9b0b4f7702ff695188f (diff) | |
support actionbarsherlock
Diffstat (limited to 'src/org/fox/ttrss/offline')
| -rw-r--r-- | src/org/fox/ttrss/offline/OfflineActivity.java | 1271 | ||||
| -rw-r--r-- | src/org/fox/ttrss/offline/OfflineArticleFragment.java | 826 | ||||
| -rw-r--r-- | src/org/fox/ttrss/offline/OfflineArticlePager.java | 568 | ||||
| -rw-r--r-- | src/org/fox/ttrss/offline/OfflineDownloadService.java | 972 | ||||
| -rw-r--r-- | src/org/fox/ttrss/offline/OfflineFeedCategoriesFragment.java | 648 | ||||
| -rw-r--r-- | src/org/fox/ttrss/offline/OfflineFeedsActivity.java | 626 | ||||
| -rw-r--r-- | src/org/fox/ttrss/offline/OfflineFeedsFragment.java | 708 | ||||
| -rw-r--r-- | src/org/fox/ttrss/offline/OfflineHeadlinesActivity.java | 286 | ||||
| -rw-r--r-- | src/org/fox/ttrss/offline/OfflineHeadlinesEventListener.java | 14 | ||||
| -rw-r--r-- | src/org/fox/ttrss/offline/OfflineHeadlinesFragment.java | 1298 | ||||
| -rw-r--r-- | src/org/fox/ttrss/offline/OfflineUploadService.java | 546 |
11 files changed, 3882 insertions, 3881 deletions
diff --git a/src/org/fox/ttrss/offline/OfflineActivity.java b/src/org/fox/ttrss/offline/OfflineActivity.java index bca949de..319b76c8 100644 --- a/src/org/fox/ttrss/offline/OfflineActivity.java +++ b/src/org/fox/ttrss/offline/OfflineActivity.java @@ -1,637 +1,634 @@ -package org.fox.ttrss.offline;
-
-import org.fox.ttrss.CommonActivity;
-import org.fox.ttrss.PreferencesActivity;
-import org.fox.ttrss.R;
-
-import android.annotation.SuppressLint;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteStatement;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.provider.BaseColumns;
-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.Window;
-import android.widget.EditText;
-import android.widget.SearchView;
-
-public class OfflineActivity extends CommonActivity {
- private final String TAG = this.getClass().getSimpleName();
-
- protected SharedPreferences m_prefs;
- protected Menu m_menu;
-
- private ActionMode m_headlinesActionMode;
- private HeadlinesActionModeCallback m_headlinesActionModeCallback;
-
- @SuppressLint("NewApi")
- 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;
- initMenu();
- }
-
- @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;
- }
- };
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- m_prefs = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext());
-
- setAppTheme(m_prefs);
-
- super.onCreate(savedInstanceState);
-
- requestWindowFeature(Window.FEATURE_PROGRESS);
-
- setProgressBarVisibility(false);
-
- setContentView(R.layout.login);
-
- setLoadingStatus(R.string.blank, false);
- findViewById(R.id.loading_container).setVisibility(View.GONE);
-
- initMenu();
-
- Intent intent = getIntent();
-
- if (intent.getExtras() != null) {
- if (intent.getBooleanExtra("initial", false)) {
- intent = new Intent(OfflineActivity.this, OfflineFeedsActivity.class);
- intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
-
- startActivityForResult(intent, 0);
- finish();
- }
- }
-
- /* if (savedInstanceState != null) {
-
- } */
-
- if (!isCompatMode()) {
- m_headlinesActionModeCallback = new HeadlinesActionModeCallback();
- }
-
- }
-
- @Override
- public void onSaveInstanceState(Bundle out) {
- super.onSaveInstanceState(out);
- }
-
- protected void selectArticles(int feedId, boolean isCat, int mode) {
- switch (mode) {
- case 0:
- SQLiteStatement stmtSelectAll = null;
-
- if (isCat) {
- stmtSelectAll = getWritableDb().compileStatement(
- "UPDATE articles SET selected = 1 WHERE feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)");
- } else {
- stmtSelectAll = getWritableDb().compileStatement(
- "UPDATE articles SET selected = 1 WHERE feed_id = ?");
- }
-
- stmtSelectAll.bindLong(1, feedId);
- stmtSelectAll.execute();
- stmtSelectAll.close();
-
- break;
- case 1:
-
- SQLiteStatement stmtSelectUnread = null;
-
- if (isCat) {
- stmtSelectUnread = getWritableDb().compileStatement(
- "UPDATE articles SET selected = 1 WHERE feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?) AND unread = 1");
- } else {
- stmtSelectUnread = getWritableDb().compileStatement(
- "UPDATE articles SET selected = 1 WHERE feed_id = ? AND unread = 1");
- }
-
- stmtSelectUnread.bindLong(1, feedId);
- stmtSelectUnread.execute();
- stmtSelectUnread.close();
-
- break;
- case 2:
- deselectAllArticles();
- break;
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- final OfflineHeadlinesFragment ohf = (OfflineHeadlinesFragment) getSupportFragmentManager()
- .findFragmentByTag(FRAG_HEADLINES);
-
- /* final OfflineFeedsFragment off = (OfflineFeedsFragment) getSupportFragmentManager()
- .findFragmentByTag(FRAG_FEEDS); */
-
- /* final OfflineFeedCategoriesFragment ocf = (OfflineFeedCategoriesFragment) getSupportFragmentManager()
- .findFragmentByTag(FRAG_CATS); */
-
- final OfflineArticlePager oap = (OfflineArticlePager) getSupportFragmentManager()
- .findFragmentByTag(FRAG_ARTICLE);
-
- switch (item.getItemId()) {
- case android.R.id.home:
- finish();
- return true;
- case R.id.go_online:
- switchOnline();
- return true;
- case R.id.search:
- if (ohf != 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();
-
- ohf.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(this, PreferencesActivity.class);
- startActivityForResult(intent, 0);
- return true;
- case R.id.headlines_select:
- if (ohf != null) {
- Dialog dialog = new Dialog(this);
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.headlines_select_dialog);
-
- builder.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) {
-
- selectArticles(ohf.getFeedId(), ohf.getFeedIsCat(), which);
- initMenu();
- refresh();
-
- dialog.cancel();
- }
- });
-
- dialog = builder.create();
- dialog.show();
- }
- return true;
- case R.id.headlines_mark_as_read:
- if (ohf != null) {
- int feedId = ohf.getFeedId();
- boolean isCat = ohf.getFeedIsCat();
-
- SQLiteStatement stmt = null;
-
- if (isCat) {
- stmt = getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = 0 WHERE feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)");
- } else {
- stmt = getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = 0 WHERE feed_id = ?");
- }
- stmt.bindLong(1, feedId);
- stmt.execute();
- stmt.close();
-
- refresh();
- }
- return true;
- case R.id.share_article:
- if (true) {
- int articleId = oap.getSelectedArticleId();
-
- shareArticle(articleId);
- }
- return true;
- case R.id.toggle_marked:
- if (oap != null) {
- int articleId = oap.getSelectedArticleId();
-
- SQLiteStatement stmt = getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, marked = NOT marked WHERE "
- + BaseColumns._ID + " = ?");
- stmt.bindLong(1, articleId);
- stmt.execute();
- stmt.close();
-
- refresh();
- }
- return true;
- case R.id.selection_select_none:
- deselectAllArticles();
- return true;
- case R.id.selection_toggle_unread:
- if (getSelectedArticleCount() > 0) {
- SQLiteStatement stmt = getWritableDb()
- .compileStatement(
- "UPDATE articles SET modified = 1, unread = NOT unread WHERE selected = 1");
- stmt.execute();
- stmt.close();
-
- refresh();
- }
- return true;
- case R.id.selection_toggle_marked:
- if (getSelectedArticleCount() > 0) {
- SQLiteStatement stmt = getWritableDb()
- .compileStatement(
- "UPDATE articles SET modified = 1, marked = NOT marked WHERE selected = 1");
- stmt.execute();
- stmt.close();
-
- refresh();
- }
- return true;
- case R.id.selection_toggle_published:
- if (getSelectedArticleCount() > 0) {
- SQLiteStatement stmt = getWritableDb()
- .compileStatement(
- "UPDATE articles SET modified = 1, published = NOT published WHERE selected = 1");
- stmt.execute();
- stmt.close();
-
- refresh();
- }
- return true;
- case R.id.toggle_published:
- if (oap != null) {
- int articleId = oap.getSelectedArticleId();
-
- SQLiteStatement stmt = getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, published = NOT published WHERE "
- + BaseColumns._ID + " = ?");
- stmt.bindLong(1, articleId);
- stmt.execute();
- stmt.close();
-
- refresh();
- }
- return true;
- case R.id.catchup_above:
- if (oap != null) {
- int articleId = oap.getSelectedArticleId();
- int feedId = oap.getFeedId();
- boolean isCat = oap.getFeedIsCat();
-
- SQLiteStatement stmt = null;
-
- if (isCat) {
- stmt = getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = 0 WHERE " +
- "updated >= (SELECT updated FROM articles WHERE " + BaseColumns._ID + " = ?) " +
- "AND feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)");
- } else {
- stmt = getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = 0 WHERE " +
- "updated >= (SELECT updated FROM articles WHERE " + BaseColumns._ID + " = ?) " +
- "AND feed_id = ?");
- }
-
- stmt.bindLong(1, articleId);
- stmt.bindLong(2, feedId);
- stmt.execute();
- stmt.close();
-
- refresh();
- }
- return true;
- case R.id.set_unread:
- if (oap != null) {
- int articleId = oap.getSelectedArticleId();
-
- SQLiteStatement stmt = getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = 1 WHERE "
- + BaseColumns._ID + " = ?");
- stmt.bindLong(1, articleId);
- stmt.execute();
- stmt.close();
-
- refresh();
- }
- return true;
- default:
- Log.d(TAG, "onOptionsItemSelected, unhandled id=" + item.getItemId());
- return super.onOptionsItemSelected(item);
- }
- }
-
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- MenuInflater inflater = getMenuInflater();
- inflater.inflate(R.menu.offline_menu, menu);
-
- m_menu = menu;
-
- initMenu();
-
- return true;
- }
-
- @SuppressLint("NewApi")
- protected void initMenu() {
- if (m_menu != null) {
- m_menu.setGroupVisible(R.id.menu_group_headlines, false);
- m_menu.setGroupVisible(R.id.menu_group_headlines_selection, false);
- m_menu.setGroupVisible(R.id.menu_group_article, false);
- m_menu.setGroupVisible(R.id.menu_group_feeds, false);
-
- if (!isCompatMode()) {
- MenuItem search = m_menu.findItem(R.id.search);
-
- OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
-
- if (hf != null) {
- if (hf.getSelectedArticleCount() > 0 && m_headlinesActionMode == null) {
- m_headlinesActionMode = startActionMode(m_headlinesActionModeCallback);
- } else if (hf.getSelectedArticleCount() == 0 && m_headlinesActionMode != null) {
- m_headlinesActionMode.finish();
- }
- }
-
- OfflineArticlePager ap = (OfflineArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE);
-
- if (ap != null) {
- int articleId = ap.getSelectedArticleId();
-
- Cursor article = getArticleById(articleId);
-
- if (article != null) {
- boolean unread = article.getInt(article.getColumnIndex("unread")) == 1;
- boolean marked = article.getInt(article.getColumnIndex("marked")) == 1;
- boolean published = article.getInt(article.getColumnIndex("published")) == 1;
-
- m_menu.findItem(R.id.toggle_marked).setIcon(marked ? R.drawable.ic_important_light :
- R.drawable.ic_unimportant_light);
-
- m_menu.findItem(R.id.toggle_published).setIcon(published ? R.drawable.ic_menu_published_light :
- R.drawable.ic_menu_unpublished_light);
-
- m_menu.findItem(R.id.set_unread).setIcon(unread ? R.drawable.ic_unread_light :
- R.drawable.ic_read_light);
-
- article.close();
- }
- }
-
- SearchView searchView = (SearchView) search.getActionView();
- searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
- private String query = "";
-
- @Override
- public boolean onQueryTextSubmit(String query) {
- OfflineHeadlinesFragment frag = (OfflineHeadlinesFragment) getSupportFragmentManager()
- .findFragmentByTag(FRAG_HEADLINES);
-
- if (frag != null) {
- frag.setSearchQuery(query);
- this.query = query;
- }
-
- return false;
- }
-
- @Override
- public boolean onQueryTextChange(String newText) {
- if (newText.equals("") && !newText.equals(this.query)) {
- OfflineHeadlinesFragment frag = (OfflineHeadlinesFragment) getSupportFragmentManager()
- .findFragmentByTag(FRAG_HEADLINES);
-
- if (frag != null) {
- frag.setSearchQuery(newText);
- this.query = newText;
- }
- }
-
- return false;
- }
- });
- }
- }
- }
-
- private void switchOnline() {
- SharedPreferences localPrefs = getSharedPreferences("localprefs", Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = localPrefs.edit();
- editor.putBoolean("offline_mode_active", false);
- editor.commit();
-
- Intent refresh = new Intent(this, org.fox.ttrss.OnlineActivity.class);
- startActivity(refresh);
- finish();
- }
-
- protected Cursor getArticleById(int articleId) {
- Cursor c = getReadableDb().query("articles", null,
- BaseColumns._ID + "=?",
- new String[] { String.valueOf(articleId) }, null, null, null);
-
- c.moveToFirst();
-
- return c;
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (m_prefs.getBoolean("use_volume_keys", false)) {
- OfflineArticlePager ap = (OfflineArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE);
-
- if (ap != null && ap.isAdded()) {
- switch (keyCode) {
- case KeyEvent.KEYCODE_VOLUME_UP:
- ap.selectArticle(false);
- return true;
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- ap.selectArticle(true);
- return true;
- }
- }
- }
-
- return super.onKeyDown(keyCode, event);
- }
-
- // Handle onKeyUp too to suppress beep
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- if (m_prefs.getBoolean("use_volume_keys", false)) {
-
- switch (keyCode) {
- case KeyEvent.KEYCODE_VOLUME_UP:
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- return true;
- }
- }
-
- return super.onKeyUp(keyCode, event);
- }
-
- protected Cursor getFeedById(int feedId) {
- Cursor c = getReadableDb().query("feeds", null,
- BaseColumns._ID + "=?",
- new String[] { String.valueOf(feedId) }, null, null, null);
-
- c.moveToFirst();
-
- return c;
- }
-
- protected Cursor getCatById(int catId) {
- Cursor c = getReadableDb().query("categories", null,
- BaseColumns._ID + "=?",
- new String[] { String.valueOf(catId) }, null, null, null);
-
- c.moveToFirst();
-
- return c;
- }
-
- protected Intent getShareIntent(Cursor article) {
- if (article != null) {
- String title = article.getString(article.getColumnIndex("title"));
- String link = article.getString(article.getColumnIndex("link"));
-
- Intent intent = new Intent(Intent.ACTION_SEND);
-
- intent.setType("text/plain");
- intent.putExtra(Intent.EXTRA_SUBJECT, title);
- intent.putExtra(Intent.EXTRA_TEXT, link);
-
- return intent;
- } else {
- return null;
- }
- }
-
- protected void shareArticle(int articleId) {
-
- Cursor article = getArticleById(articleId);
-
- if (article != null) {
- shareArticle(article);
- article.close();
- }
- }
-
- private void shareArticle(Cursor article) {
- if (article != null) {
- Intent intent = getShareIntent(article);
-
- startActivity(Intent.createChooser(intent,
- getString(R.string.share_article)));
- }
- }
-
- protected int getSelectedArticleCount() {
- Cursor c = getReadableDb().query("articles",
- new String[] { "COUNT(*)" }, "selected = 1", null, null, null,
- null);
- c.moveToFirst();
- int selected = c.getInt(0);
- c.close();
-
- return selected;
- }
-
- protected void deselectAllArticles() {
- getWritableDb().execSQL("UPDATE articles SET selected = 0 ");
- refresh();
- }
-
- protected void refresh() {
- OfflineFeedsFragment ff = (OfflineFeedsFragment) getSupportFragmentManager()
- .findFragmentByTag(FRAG_FEEDS);
-
- if (ff != null) {
- ff.refresh();
- }
-
- OfflineFeedCategoriesFragment cf = (OfflineFeedCategoriesFragment) getSupportFragmentManager()
- .findFragmentByTag(FRAG_CATS);
-
- if (cf != null) {
- cf.refresh();
- }
-
- OfflineHeadlinesFragment ohf = (OfflineHeadlinesFragment) getSupportFragmentManager()
- .findFragmentByTag(FRAG_HEADLINES);
-
- if (ohf != null) {
- ohf.refresh();
- }
-
- initMenu();
- }
-
-}
+package org.fox.ttrss.offline; + +import org.fox.ttrss.CommonActivity; +import org.fox.ttrss.PreferencesActivity; +import org.fox.ttrss.R; + +import com.actionbarsherlock.view.ActionMode; +import com.actionbarsherlock.view.Menu; +import com.actionbarsherlock.view.MenuInflater; +import com.actionbarsherlock.view.MenuItem; + +import android.annotation.SuppressLint; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.DialogInterface.OnClickListener; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.database.sqlite.SQLiteStatement; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.provider.BaseColumns; +import android.util.Log; +import android.view.KeyEvent; + +import android.view.View; +import android.view.Window; +import android.widget.EditText; +import android.widget.SearchView; + +public class OfflineActivity extends CommonActivity { + private final String TAG = this.getClass().getSimpleName(); + + protected SharedPreferences m_prefs; + protected Menu m_menu; + + private ActionMode m_headlinesActionMode; + private HeadlinesActionModeCallback m_headlinesActionModeCallback; + + @SuppressLint("NewApi") + private class HeadlinesActionModeCallback implements ActionMode.Callback { + + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + return false; + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + m_headlinesActionMode = null; + deselectAllArticles(); + } + + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + + MenuInflater inflater = getSupportMenuInflater(); + inflater.inflate(R.menu.headlines_action_menu, menu); + + return true; + } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + onOptionsItemSelected(item); + return false; + } + }; + + @Override + public void onCreate(Bundle savedInstanceState) { + m_prefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + setAppTheme(m_prefs); + + super.onCreate(savedInstanceState); + + requestWindowFeature(Window.FEATURE_PROGRESS); + + setProgressBarVisibility(false); + + setContentView(R.layout.login); + + setLoadingStatus(R.string.blank, false); + findViewById(R.id.loading_container).setVisibility(View.GONE); + + initMenu(); + + Intent intent = getIntent(); + + if (intent.getExtras() != null) { + if (intent.getBooleanExtra("initial", false)) { + intent = new Intent(OfflineActivity.this, OfflineFeedsActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); + + startActivityForResult(intent, 0); + finish(); + } + } + + /* if (savedInstanceState != null) { + + } */ + + m_headlinesActionModeCallback = new HeadlinesActionModeCallback(); + } + + @Override + public void onSaveInstanceState(Bundle out) { + super.onSaveInstanceState(out); + } + + protected void selectArticles(int feedId, boolean isCat, int mode) { + switch (mode) { + case 0: + SQLiteStatement stmtSelectAll = null; + + if (isCat) { + stmtSelectAll = getWritableDb().compileStatement( + "UPDATE articles SET selected = 1 WHERE feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)"); + } else { + stmtSelectAll = getWritableDb().compileStatement( + "UPDATE articles SET selected = 1 WHERE feed_id = ?"); + } + + stmtSelectAll.bindLong(1, feedId); + stmtSelectAll.execute(); + stmtSelectAll.close(); + + break; + case 1: + + SQLiteStatement stmtSelectUnread = null; + + if (isCat) { + stmtSelectUnread = getWritableDb().compileStatement( + "UPDATE articles SET selected = 1 WHERE feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?) AND unread = 1"); + } else { + stmtSelectUnread = getWritableDb().compileStatement( + "UPDATE articles SET selected = 1 WHERE feed_id = ? AND unread = 1"); + } + + stmtSelectUnread.bindLong(1, feedId); + stmtSelectUnread.execute(); + stmtSelectUnread.close(); + + break; + case 2: + deselectAllArticles(); + break; + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + final OfflineHeadlinesFragment ohf = (OfflineHeadlinesFragment) getSupportFragmentManager() + .findFragmentByTag(FRAG_HEADLINES); + + /* final OfflineFeedsFragment off = (OfflineFeedsFragment) getSupportFragmentManager() + .findFragmentByTag(FRAG_FEEDS); */ + + /* final OfflineFeedCategoriesFragment ocf = (OfflineFeedCategoriesFragment) getSupportFragmentManager() + .findFragmentByTag(FRAG_CATS); */ + + final OfflineArticlePager oap = (OfflineArticlePager) getSupportFragmentManager() + .findFragmentByTag(FRAG_ARTICLE); + + switch (item.getItemId()) { + case android.R.id.home: + finish(); + return true; + case R.id.go_online: + switchOnline(); + return true; + case R.id.search: + if (ohf != 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(); + + ohf.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(this, PreferencesActivity.class); + startActivityForResult(intent, 0); + return true; + case R.id.headlines_select: + if (ohf != null) { + Dialog dialog = new Dialog(this); + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle(R.string.headlines_select_dialog); + + builder.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) { + + selectArticles(ohf.getFeedId(), ohf.getFeedIsCat(), which); + initMenu(); + refresh(); + + dialog.cancel(); + } + }); + + dialog = builder.create(); + dialog.show(); + } + return true; + case R.id.headlines_mark_as_read: + if (ohf != null) { + int feedId = ohf.getFeedId(); + boolean isCat = ohf.getFeedIsCat(); + + SQLiteStatement stmt = null; + + if (isCat) { + stmt = getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = 0 WHERE feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)"); + } else { + stmt = getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = 0 WHERE feed_id = ?"); + } + stmt.bindLong(1, feedId); + stmt.execute(); + stmt.close(); + + refresh(); + } + return true; + case R.id.share_article: + if (true) { + int articleId = oap.getSelectedArticleId(); + + shareArticle(articleId); + } + return true; + case R.id.toggle_marked: + if (oap != null) { + int articleId = oap.getSelectedArticleId(); + + SQLiteStatement stmt = getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, marked = NOT marked WHERE " + + BaseColumns._ID + " = ?"); + stmt.bindLong(1, articleId); + stmt.execute(); + stmt.close(); + + refresh(); + } + return true; + /* case R.id.selection_select_none: + deselectAllArticles(); + return true; */ + case R.id.selection_toggle_unread: + if (getSelectedArticleCount() > 0) { + SQLiteStatement stmt = getWritableDb() + .compileStatement( + "UPDATE articles SET modified = 1, unread = NOT unread WHERE selected = 1"); + stmt.execute(); + stmt.close(); + + refresh(); + } + return true; + case R.id.selection_toggle_marked: + if (getSelectedArticleCount() > 0) { + SQLiteStatement stmt = getWritableDb() + .compileStatement( + "UPDATE articles SET modified = 1, marked = NOT marked WHERE selected = 1"); + stmt.execute(); + stmt.close(); + + refresh(); + } + return true; + case R.id.selection_toggle_published: + if (getSelectedArticleCount() > 0) { + SQLiteStatement stmt = getWritableDb() + .compileStatement( + "UPDATE articles SET modified = 1, published = NOT published WHERE selected = 1"); + stmt.execute(); + stmt.close(); + + refresh(); + } + return true; + case R.id.toggle_published: + if (oap != null) { + int articleId = oap.getSelectedArticleId(); + + SQLiteStatement stmt = getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, published = NOT published WHERE " + + BaseColumns._ID + " = ?"); + stmt.bindLong(1, articleId); + stmt.execute(); + stmt.close(); + + refresh(); + } + return true; + case R.id.catchup_above: + if (oap != null) { + int articleId = oap.getSelectedArticleId(); + int feedId = oap.getFeedId(); + boolean isCat = oap.getFeedIsCat(); + + SQLiteStatement stmt = null; + + if (isCat) { + stmt = getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = 0 WHERE " + + "updated >= (SELECT updated FROM articles WHERE " + BaseColumns._ID + " = ?) " + + "AND feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)"); + } else { + stmt = getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = 0 WHERE " + + "updated >= (SELECT updated FROM articles WHERE " + BaseColumns._ID + " = ?) " + + "AND feed_id = ?"); + } + + stmt.bindLong(1, articleId); + stmt.bindLong(2, feedId); + stmt.execute(); + stmt.close(); + + refresh(); + } + return true; + case R.id.set_unread: + if (oap != null) { + int articleId = oap.getSelectedArticleId(); + + SQLiteStatement stmt = getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = 1 WHERE " + + BaseColumns._ID + " = ?"); + stmt.bindLong(1, articleId); + stmt.execute(); + stmt.close(); + + refresh(); + } + return true; + default: + Log.d(TAG, "onOptionsItemSelected, unhandled id=" + item.getItemId()); + return super.onOptionsItemSelected(item); + } + } + + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getSupportMenuInflater(); + inflater.inflate(R.menu.offline_menu, menu); + + m_menu = menu; + + initMenu(); + + return true; + } + + @SuppressLint("NewApi") + protected void initMenu() { + if (m_menu != null) { + m_menu.setGroupVisible(R.id.menu_group_headlines, false); + m_menu.setGroupVisible(R.id.menu_group_article, false); + m_menu.setGroupVisible(R.id.menu_group_feeds, false); + + OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + + if (hf != null) { + if (hf.getSelectedArticleCount() > 0 && m_headlinesActionMode == null) { + m_headlinesActionMode = startActionMode(m_headlinesActionModeCallback); + } else if (hf.getSelectedArticleCount() == 0 && m_headlinesActionMode != null) { + m_headlinesActionMode.finish(); + } + } + + OfflineArticlePager ap = (OfflineArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); + + if (ap != null) { + int articleId = ap.getSelectedArticleId(); + + Cursor article = getArticleById(articleId); + + if (article != null) { + boolean unread = article.getInt(article.getColumnIndex("unread")) == 1; + boolean marked = article.getInt(article.getColumnIndex("marked")) == 1; + boolean published = article.getInt(article.getColumnIndex("published")) == 1; + + m_menu.findItem(R.id.toggle_marked).setIcon(marked ? R.drawable.ic_important_light : + R.drawable.ic_unimportant_light); + + m_menu.findItem(R.id.toggle_published).setIcon(published ? R.drawable.ic_menu_published_light : + R.drawable.ic_menu_unpublished_light); + + m_menu.findItem(R.id.set_unread).setIcon(unread ? R.drawable.ic_unread_light : + R.drawable.ic_read_light); + + article.close(); + } + } + + if (!isCompatMode()) { + MenuItem search = m_menu.findItem(R.id.search); + + SearchView searchView = (SearchView) search.getActionView(); + searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + private String query = ""; + + @Override + public boolean onQueryTextSubmit(String query) { + OfflineHeadlinesFragment frag = (OfflineHeadlinesFragment) getSupportFragmentManager() + .findFragmentByTag(FRAG_HEADLINES); + + if (frag != null) { + frag.setSearchQuery(query); + this.query = query; + } + + return false; + } + + @Override + public boolean onQueryTextChange(String newText) { + if (newText.equals("") && !newText.equals(this.query)) { + OfflineHeadlinesFragment frag = (OfflineHeadlinesFragment) getSupportFragmentManager() + .findFragmentByTag(FRAG_HEADLINES); + + if (frag != null) { + frag.setSearchQuery(newText); + this.query = newText; + } + } + + return false; + } + }); + } + } + } + + private void switchOnline() { + SharedPreferences localPrefs = getSharedPreferences("localprefs", Context.MODE_PRIVATE); + SharedPreferences.Editor editor = localPrefs.edit(); + editor.putBoolean("offline_mode_active", false); + editor.commit(); + + Intent refresh = new Intent(this, org.fox.ttrss.OnlineActivity.class); + startActivity(refresh); + finish(); + } + + protected Cursor getArticleById(int articleId) { + Cursor c = getReadableDb().query("articles", null, + BaseColumns._ID + "=?", + new String[] { String.valueOf(articleId) }, null, null, null); + + c.moveToFirst(); + + return c; + } + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + if (m_prefs.getBoolean("use_volume_keys", false)) { + OfflineArticlePager ap = (OfflineArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); + + if (ap != null && ap.isAdded()) { + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + ap.selectArticle(false); + return true; + case KeyEvent.KEYCODE_VOLUME_DOWN: + ap.selectArticle(true); + return true; + } + } + } + + return super.onKeyDown(keyCode, event); + } + + // Handle onKeyUp too to suppress beep + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + if (m_prefs.getBoolean("use_volume_keys", false)) { + + switch (keyCode) { + case KeyEvent.KEYCODE_VOLUME_UP: + case KeyEvent.KEYCODE_VOLUME_DOWN: + return true; + } + } + + return super.onKeyUp(keyCode, event); + } + + protected Cursor getFeedById(int feedId) { + Cursor c = getReadableDb().query("feeds", null, + BaseColumns._ID + "=?", + new String[] { String.valueOf(feedId) }, null, null, null); + + c.moveToFirst(); + + return c; + } + + protected Cursor getCatById(int catId) { + Cursor c = getReadableDb().query("categories", null, + BaseColumns._ID + "=?", + new String[] { String.valueOf(catId) }, null, null, null); + + c.moveToFirst(); + + return c; + } + + protected Intent getShareIntent(Cursor article) { + if (article != null) { + String title = article.getString(article.getColumnIndex("title")); + String link = article.getString(article.getColumnIndex("link")); + + Intent intent = new Intent(Intent.ACTION_SEND); + + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_SUBJECT, title); + intent.putExtra(Intent.EXTRA_TEXT, link); + + return intent; + } else { + return null; + } + } + + protected void shareArticle(int articleId) { + + Cursor article = getArticleById(articleId); + + if (article != null) { + shareArticle(article); + article.close(); + } + } + + private void shareArticle(Cursor article) { + if (article != null) { + Intent intent = getShareIntent(article); + + startActivity(Intent.createChooser(intent, + getString(R.string.share_article))); + } + } + + protected int getSelectedArticleCount() { + Cursor c = getReadableDb().query("articles", + new String[] { "COUNT(*)" }, "selected = 1", null, null, null, + null); + c.moveToFirst(); + int selected = c.getInt(0); + c.close(); + + return selected; + } + + protected void deselectAllArticles() { + getWritableDb().execSQL("UPDATE articles SET selected = 0 "); + refresh(); + } + + protected void refresh() { + OfflineFeedsFragment ff = (OfflineFeedsFragment) getSupportFragmentManager() + .findFragmentByTag(FRAG_FEEDS); + + if (ff != null) { + ff.refresh(); + } + + OfflineFeedCategoriesFragment cf = (OfflineFeedCategoriesFragment) getSupportFragmentManager() + .findFragmentByTag(FRAG_CATS); + + if (cf != null) { + cf.refresh(); + } + + OfflineHeadlinesFragment ohf = (OfflineHeadlinesFragment) getSupportFragmentManager() + .findFragmentByTag(FRAG_HEADLINES); + + if (ohf != null) { + ohf.refresh(); + } + + initMenu(); + } + +} diff --git a/src/org/fox/ttrss/offline/OfflineArticleFragment.java b/src/org/fox/ttrss/offline/OfflineArticleFragment.java index 22d1ae02..d7c97f01 100644 --- a/src/org/fox/ttrss/offline/OfflineArticleFragment.java +++ b/src/org/fox/ttrss/offline/OfflineArticleFragment.java @@ -1,413 +1,413 @@ -package org.fox.ttrss.offline;
-
-import java.text.SimpleDateFormat;
-import java.util.Date;
-
-import org.fox.ttrss.CommonActivity;
-import org.fox.ttrss.R;
-import org.fox.ttrss.util.ImageCacheService;
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
-import org.jsoup.nodes.Element;
-import org.jsoup.select.Elements;
-
-import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.provider.BaseColumns;
-import android.support.v4.app.Fragment;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.GestureDetector;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.webkit.WebChromeClient;
-import android.webkit.WebSettings;
-import android.webkit.WebSettings.LayoutAlgorithm;
-import android.webkit.WebView;
-import android.widget.TextView;
-
-public class OfflineArticleFragment extends Fragment implements GestureDetector.OnDoubleTapListener {
- private final String TAG = this.getClass().getSimpleName();
-
- private SharedPreferences m_prefs;
- private int m_articleId;
- private boolean m_isCat = false; // FIXME use
- private Cursor m_cursor;
- private OfflineActivity m_activity;
- private GestureDetector m_detector;
-
- public OfflineArticleFragment() {
- super();
- }
-
- public OfflineArticleFragment(int articleId) {
- super();
- m_articleId = articleId;
- }
-
-
- @Override
- public boolean onContextItemSelected(MenuItem item) {
- /* AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
- .getMenuInfo(); */
-
- switch (item.getItemId()) {
- case R.id.article_link_share:
- m_activity.shareArticle(m_articleId);
- return true;
- case R.id.article_link_copy:
- if (true) {
- Cursor article = m_activity.getArticleById(m_articleId);
-
- if (article != null) {
- m_activity.copyToClipboard(article.getString(article.getColumnIndex("link")));
- article.close();
- }
- }
- return true;
- default:
- Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId());
- return super.onContextItemSelected(item);
- }
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
-
- getActivity().getMenuInflater().inflate(R.menu.article_link_context_menu, menu);
- menu.setHeaderTitle(m_cursor.getString(m_cursor.getColumnIndex("title")));
-
- super.onCreateContextMenu(menu, v, menuInfo);
-
- }
-
- @SuppressLint("NewApi")
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-
- if (savedInstanceState != null) {
- m_articleId = savedInstanceState.getInt("articleId");
- }
-
- View view = inflater.inflate(R.layout.article_fragment, container, false);
-
- m_cursor = m_activity.getReadableDb().query("articles LEFT JOIN feeds ON (feed_id = feeds."+BaseColumns._ID+")",
- new String[] { "articles.*", "feeds.title AS feed_title" }, "articles." + BaseColumns._ID + "=?",
- new String[] { String.valueOf(m_articleId) }, null, null, null);
-
- m_cursor.moveToFirst();
-
- if (m_cursor.isFirst()) {
-
- TextView title = (TextView)view.findViewById(R.id.title);
-
- if (title != null) {
-
- String titleStr;
-
- if (m_cursor.getString(m_cursor.getColumnIndex("title")).length() > 200)
- titleStr = m_cursor.getString(m_cursor.getColumnIndex("title")).substring(0, 200) + "...";
- else
- titleStr = m_cursor.getString(m_cursor.getColumnIndex("title"));
-
- final String link = m_cursor.getString(m_cursor.getColumnIndex("link"));
-
- title.setText(titleStr);
- //title.setPaintFlags(title.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
- title.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- try {
- Intent intent = new Intent(Intent.ACTION_VIEW,
- Uri.parse(link.trim()));
- startActivity(intent);
- } catch (Exception e) {
- e.printStackTrace();
- m_activity.toast(R.string.error_other_error);
- }
- }
- });
-
- registerForContextMenu(title);
- }
-
- TextView comments = (TextView)view.findViewById(R.id.comments);
-
- if (comments != null) {
- comments.setVisibility(View.GONE);
- }
-
- WebView web = (WebView)view.findViewById(R.id.content);
-
- if (web != null) {
-
- web.setWebChromeClient(new WebChromeClient() {
- @Override
- public void onProgressChanged(WebView view, int progress) {
- m_activity.setProgress(Math.round(((float)progress / 100f) * 10000));
- if (progress == 100) {
- m_activity.setProgressBarVisibility(false);
- }
- }
- });
-
- web.setOnTouchListener(new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- return m_detector.onTouchEvent(event);
- }
- });
-
- String content;
- String cssOverride = "";
-
- WebSettings ws = web.getSettings();
- ws.setSupportZoom(true);
- ws.setBuiltInZoomControls(false);
-
- web.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN);
-
- TypedValue tv = new TypedValue();
- getActivity().getTheme().resolveAttribute(R.attr.linkColor, tv, true);
-
- // prevent flicker in ics
- if (android.os.Build.VERSION.SDK_INT >= 11) {
- web.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
- }
-
- if (m_prefs.getString("theme", "THEME_DARK").equals("THEME_DARK")) {
- cssOverride = "body { background : transparent; color : #e0e0e0}";
- } else if (m_prefs.getString("theme", "THEME_DARK").equals("THEME_DARK_GRAY")) {
- cssOverride = "body { background : transparent; color : #e0e0e0}";
- } else {
- cssOverride = "body { background : transparent; }";
- }
- web.setBackgroundColor(getResources().getColor(android.R.color.transparent));
-
- String hexColor = String.format("#%06X", (0xFFFFFF & tv.data));
- cssOverride += " a:link {color: "+hexColor+";} a:visited { color: "+hexColor+";}";
-
- String articleContent = m_cursor.getString(m_cursor.getColumnIndex("content"));
- Document doc = Jsoup.parse(articleContent);
-
- if (doc != null) {
- if (m_prefs.getBoolean("offline_image_cache_enabled", false)) {
-
- Elements images = doc.select("img");
-
- for (Element img : images) {
- String url = img.attr("src");
-
- if (ImageCacheService.isUrlCached(m_activity, url)) {
- img.attr("src", "file://" + ImageCacheService.getCacheFileName(m_activity, url));
- }
- }
- }
-
- // thanks webview for crashing on <video> tag
- Elements videos = doc.select("video");
-
- for (Element video : videos)
- video.remove();
-
- articleContent = doc.toString();
- }
-
- String align = m_prefs.getBoolean("justify_article_text", true) ? "text-align : justified" : "";
-
- switch (Integer.parseInt(m_prefs.getString("font_size", "0"))) {
- case 0:
- cssOverride += "body { "+align+"; font-size : 14px; } ";
- break;
- case 1:
- cssOverride += "body { "+align+"; font-size : 18px; } ";
- break;
- case 2:
- cssOverride += "body { "+align+"; font-size : 21px; } ";
- break;
- }
-
- content =
- "<html>" +
- "<head>" +
- "<meta content=\"text/html; charset=utf-8\" http-equiv=\"content-type\">" +
- "<style type=\"text/css\">" +
- "body { padding : 0px; margin : 0px; }" +
- cssOverride +
- "</style>" +
- "</head>" +
- "<body>" + articleContent + "<p> </p><p> </p></body></html>";;
-
- try {
- web.loadDataWithBaseURL(null, content, "text/html", "utf-8", null);
- } catch (RuntimeException e) {
- e.printStackTrace();
- }
-
-
- }
-
- TextView dv = (TextView)view.findViewById(R.id.date);
-
- if (dv != null) {
- Date d = new Date(m_cursor.getInt(m_cursor.getColumnIndex("updated")) * 1000L);
- SimpleDateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy, HH:mm");
- dv.setText(df.format(d));
- }
-
- TextView tagv = (TextView)view.findViewById(R.id.tags);
-
- if (tagv != null) {
- int feedTitleIndex = m_cursor.getColumnIndex("feed_title");
-
- if (feedTitleIndex != -1 && m_isCat) {
- tagv.setText(m_cursor.getString(feedTitleIndex));
- } else {
- String tagsStr = m_cursor.getString(m_cursor.getColumnIndex("tags"));
- tagv.setText(tagsStr);
- }
- }
-
- TextView author = (TextView)view.findViewById(R.id.author);
-
- if (author != null) {
- author.setVisibility(View.GONE);
- }
- }
-
- return view;
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- m_cursor.close();
- }
-
- @Override
- public void onSaveInstanceState (Bundle out) {
- super.onSaveInstanceState(out);
-
- out.putInt("articleId", m_articleId);
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
-
- m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
-
- m_activity = (OfflineActivity) activity;
-
- m_detector = new GestureDetector(m_activity, new GestureDetector.OnGestureListener() {
- @Override
- public boolean onSingleTapUp(MotionEvent e) {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public void onShowPress(MotionEvent e) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
- float distanceY) {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public void onLongPress(MotionEvent e) {
- // TODO Auto-generated method stub
-
- }
-
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
- float velocityY) {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean onDown(MotionEvent e) {
- // TODO Auto-generated method stub
- return false;
- }
- });
-
- m_detector.setOnDoubleTapListener(this);
- }
-
- @Override
- public boolean onDoubleTap(MotionEvent arg0) {
- // TODO Auto-generated method stub
- return false;
- }
-
- @Override
- public boolean onDoubleTapEvent(MotionEvent arg0) {
- // TODO Auto-generated method stub
- return false;
- }
-
- private void onLeftSideTapped() {
- OfflineArticlePager ap = (OfflineArticlePager) m_activity.getSupportFragmentManager().findFragmentByTag(CommonActivity.FRAG_ARTICLE);
-
- if (ap != null && ap.isAdded()) {
- ap.selectArticle(false);
- }
- }
-
- private void onRightSideTapped() {
- OfflineArticlePager ap = (OfflineArticlePager) m_activity.getSupportFragmentManager().findFragmentByTag(CommonActivity.FRAG_ARTICLE);
-
- if (ap != null && ap.isAdded()) {
- ap.selectArticle(true);
- }
- }
-
- @Override
- public boolean onSingleTapConfirmed(MotionEvent e) {
-
- int width = getView().getWidth();
- int x = Math.round(e.getX());
-
- if (x <= width/15) {
- onLeftSideTapped();
- return true;
- } else if (x >= width-(width/15)) {
- onRightSideTapped();
- return true;
- } /* else if (!m_activity.isCompatMode()) {
- ActionBar bar = m_activity.getActionBar();
-
- if (bar.isShowing()) {
- bar.hide();
- } else {
- bar.show();
- }
- } */
-
- return false;
- }
-
-
-}
+package org.fox.ttrss.offline; + +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.fox.ttrss.CommonActivity; +import org.fox.ttrss.R; +import org.fox.ttrss.util.ImageCacheService; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.provider.BaseColumns; +import android.support.v4.app.Fragment; +import android.util.Log; +import android.util.TypedValue; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.GestureDetector; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.webkit.WebChromeClient; +import android.webkit.WebSettings; +import android.webkit.WebSettings.LayoutAlgorithm; +import android.webkit.WebView; +import android.widget.TextView; + +public class OfflineArticleFragment extends Fragment implements GestureDetector.OnDoubleTapListener { + private final String TAG = this.getClass().getSimpleName(); + + private SharedPreferences m_prefs; + private int m_articleId; + private boolean m_isCat = false; // FIXME use + private Cursor m_cursor; + private OfflineActivity m_activity; + private GestureDetector m_detector; + + public OfflineArticleFragment() { + super(); + } + + public OfflineArticleFragment(int articleId) { + super(); + m_articleId = articleId; + } + + + @Override + public boolean onContextItemSelected(MenuItem item) { + /* AdapterContextMenuInfo info = (AdapterContextMenuInfo) item + .getMenuInfo(); */ + + switch (item.getItemId()) { + case R.id.article_link_share: + m_activity.shareArticle(m_articleId); + return true; + case R.id.article_link_copy: + if (true) { + Cursor article = m_activity.getArticleById(m_articleId); + + if (article != null) { + m_activity.copyToClipboard(article.getString(article.getColumnIndex("link"))); + article.close(); + } + } + return true; + default: + Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId()); + return super.onContextItemSelected(item); + } + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + + getActivity().getMenuInflater().inflate(R.menu.article_link_context_menu, menu); + menu.setHeaderTitle(m_cursor.getString(m_cursor.getColumnIndex("title"))); + + super.onCreateContextMenu(menu, v, menuInfo); + + } + + @SuppressLint("NewApi") + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + if (savedInstanceState != null) { + m_articleId = savedInstanceState.getInt("articleId"); + } + + View view = inflater.inflate(R.layout.article_fragment, container, false); + + m_cursor = m_activity.getReadableDb().query("articles LEFT JOIN feeds ON (feed_id = feeds."+BaseColumns._ID+")", + new String[] { "articles.*", "feeds.title AS feed_title" }, "articles." + BaseColumns._ID + "=?", + new String[] { String.valueOf(m_articleId) }, null, null, null); + + m_cursor.moveToFirst(); + + if (m_cursor.isFirst()) { + + TextView title = (TextView)view.findViewById(R.id.title); + + if (title != null) { + + String titleStr; + + if (m_cursor.getString(m_cursor.getColumnIndex("title")).length() > 200) + titleStr = m_cursor.getString(m_cursor.getColumnIndex("title")).substring(0, 200) + "..."; + else + titleStr = m_cursor.getString(m_cursor.getColumnIndex("title")); + + final String link = m_cursor.getString(m_cursor.getColumnIndex("link")); + + title.setText(titleStr); + //title.setPaintFlags(title.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG); + title.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + try { + Intent intent = new Intent(Intent.ACTION_VIEW, + Uri.parse(link.trim())); + startActivity(intent); + } catch (Exception e) { + e.printStackTrace(); + m_activity.toast(R.string.error_other_error); + } + } + }); + + registerForContextMenu(title); + } + + TextView comments = (TextView)view.findViewById(R.id.comments); + + if (comments != null) { + comments.setVisibility(View.GONE); + } + + WebView web = (WebView)view.findViewById(R.id.content); + + if (web != null) { + + web.setWebChromeClient(new WebChromeClient() { + @Override + public void onProgressChanged(WebView view, int progress) { + m_activity.setProgress(Math.round(((float)progress / 100f) * 10000)); + if (progress == 100) { + m_activity.setProgressBarVisibility(false); + } + } + }); + + web.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + return m_detector.onTouchEvent(event); + } + }); + + String content; + String cssOverride = ""; + + WebSettings ws = web.getSettings(); + ws.setSupportZoom(true); + ws.setBuiltInZoomControls(false); + + web.getSettings().setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN); + + TypedValue tv = new TypedValue(); + getActivity().getTheme().resolveAttribute(R.attr.linkColor, tv, true); + + // prevent flicker in ics + if (android.os.Build.VERSION.SDK_INT >= 11) { + web.setLayerType(View.LAYER_TYPE_SOFTWARE, null); + } + + if (m_prefs.getString("theme", "THEME_DARK").equals("THEME_DARK")) { + cssOverride = "body { background : transparent; color : #e0e0e0}"; + } else if (m_prefs.getString("theme", "THEME_DARK").equals("THEME_DARK_GRAY")) { + cssOverride = "body { background : transparent; color : #e0e0e0}"; + } else { + cssOverride = "body { background : transparent; }"; + } + web.setBackgroundColor(getResources().getColor(android.R.color.transparent)); + + String hexColor = String.format("#%06X", (0xFFFFFF & tv.data)); + cssOverride += " a:link {color: "+hexColor+";} a:visited { color: "+hexColor+";}"; + + String articleContent = m_cursor.getString(m_cursor.getColumnIndex("content")); + Document doc = Jsoup.parse(articleContent); + + if (doc != null) { + if (m_prefs.getBoolean("offline_image_cache_enabled", false)) { + + Elements images = doc.select("img"); + + for (Element img : images) { + String url = img.attr("src"); + + if (ImageCacheService.isUrlCached(m_activity, url)) { + img.attr("src", "file://" + ImageCacheService.getCacheFileName(m_activity, url)); + } + } + } + + // thanks webview for crashing on <video> tag + Elements videos = doc.select("video"); + + for (Element video : videos) + video.remove(); + + articleContent = doc.toString(); + } + + String align = m_prefs.getBoolean("justify_article_text", true) ? "text-align : justified" : ""; + + switch (Integer.parseInt(m_prefs.getString("font_size", "0"))) { + case 0: + cssOverride += "body { "+align+"; font-size : 14px; } "; + break; + case 1: + cssOverride += "body { "+align+"; font-size : 18px; } "; + break; + case 2: + cssOverride += "body { "+align+"; font-size : 21px; } "; + break; + } + + content = + "<html>" + + "<head>" + + "<meta content=\"text/html; charset=utf-8\" http-equiv=\"content-type\">" + + "<style type=\"text/css\">" + + "body { padding : 0px; margin : 0px; }" + + cssOverride + + "</style>" + + "</head>" + + "<body>" + articleContent + "<p> </p><p> </p></body></html>";; + + try { + web.loadDataWithBaseURL(null, content, "text/html", "utf-8", null); + } catch (RuntimeException e) { + e.printStackTrace(); + } + + + } + + TextView dv = (TextView)view.findViewById(R.id.date); + + if (dv != null) { + Date d = new Date(m_cursor.getInt(m_cursor.getColumnIndex("updated")) * 1000L); + SimpleDateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy, HH:mm"); + dv.setText(df.format(d)); + } + + TextView tagv = (TextView)view.findViewById(R.id.tags); + + if (tagv != null) { + int feedTitleIndex = m_cursor.getColumnIndex("feed_title"); + + if (feedTitleIndex != -1 && m_isCat) { + tagv.setText(m_cursor.getString(feedTitleIndex)); + } else { + String tagsStr = m_cursor.getString(m_cursor.getColumnIndex("tags")); + tagv.setText(tagsStr); + } + } + + TextView author = (TextView)view.findViewById(R.id.author); + + if (author != null) { + author.setVisibility(View.GONE); + } + } + + return view; + } + + @Override + public void onDestroy() { + super.onDestroy(); + + m_cursor.close(); + } + + @Override + public void onSaveInstanceState (Bundle out) { + super.onSaveInstanceState(out); + + out.putInt("articleId", m_articleId); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()); + + m_activity = (OfflineActivity) activity; + + m_detector = new GestureDetector(m_activity, new GestureDetector.OnGestureListener() { + @Override + public boolean onSingleTapUp(MotionEvent e) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void onShowPress(MotionEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, + float distanceY) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void onLongPress(MotionEvent e) { + // TODO Auto-generated method stub + + } + + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, + float velocityY) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean onDown(MotionEvent e) { + // TODO Auto-generated method stub + return false; + } + }); + + m_detector.setOnDoubleTapListener(this); + } + + @Override + public boolean onDoubleTap(MotionEvent arg0) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean onDoubleTapEvent(MotionEvent arg0) { + // TODO Auto-generated method stub + return false; + } + + private void onLeftSideTapped() { + OfflineArticlePager ap = (OfflineArticlePager) m_activity.getSupportFragmentManager().findFragmentByTag(CommonActivity.FRAG_ARTICLE); + + if (ap != null && ap.isAdded()) { + ap.selectArticle(false); + } + } + + private void onRightSideTapped() { + OfflineArticlePager ap = (OfflineArticlePager) m_activity.getSupportFragmentManager().findFragmentByTag(CommonActivity.FRAG_ARTICLE); + + if (ap != null && ap.isAdded()) { + ap.selectArticle(true); + } + } + + @Override + public boolean onSingleTapConfirmed(MotionEvent e) { + + int width = getView().getWidth(); + int x = Math.round(e.getX()); + + if (x <= width/15) { + onLeftSideTapped(); + return true; + } else if (x >= width-(width/15)) { + onRightSideTapped(); + return true; + } /* else if (!m_activity.isCompatMode()) { + ActionBar bar = m_activity.getSupportActionBar(); + + if (bar.isShowing()) { + bar.hide(); + } else { + bar.show(); + } + } */ + + return false; + } + + +} diff --git a/src/org/fox/ttrss/offline/OfflineArticlePager.java b/src/org/fox/ttrss/offline/OfflineArticlePager.java index 48742c12..a4a90031 100644 --- a/src/org/fox/ttrss/offline/OfflineArticlePager.java +++ b/src/org/fox/ttrss/offline/OfflineArticlePager.java @@ -1,284 +1,284 @@ -package org.fox.ttrss.offline;
-
-import org.fox.ttrss.R;
-
-import com.viewpagerindicator.UnderlinePageIndicator;
-
-import android.app.Activity;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.provider.BaseColumns;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.FragmentStatePagerAdapter;
-import android.support.v4.view.ViewPager;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
-
-public class OfflineArticlePager extends Fragment {
- private final String TAG = this.getClass().getSimpleName();
-
- private PagerAdapter m_adapter;
- private OfflineActivity m_activity;
- private OfflineHeadlinesEventListener m_listener;
- private boolean m_isCat;
- private int m_feedId;
- private int m_articleId;
- private String m_searchQuery = "";
- private Cursor m_cursor;
- private SharedPreferences m_prefs;
-
- public int getFeedId() {
- return m_feedId;
- }
-
- public boolean getFeedIsCat() {
- return m_isCat;
- }
-
- public Cursor createCursor() {
- String feedClause = null;
-
- if (m_isCat) {
- feedClause = "feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)";
- } else {
- feedClause = "feed_id = ?";
- }
-
- String orderBy = (m_prefs.getBoolean("offline_oldest_first", false)) ? "updated" : "updated DESC";
-
- if (m_searchQuery == null || m_searchQuery.equals("")) {
- return m_activity.getReadableDb().query("articles LEFT JOIN feeds ON (feed_id = feeds."+BaseColumns._ID+")",
- new String[] { "articles."+BaseColumns._ID, "feeds.title AS feed_title" }, feedClause,
- new String[] { String.valueOf(m_feedId) }, null, null, orderBy);
- } else {
- return m_activity.getReadableDb().query("articles LEFT JOIN feeds ON (feed_id = feeds."+BaseColumns._ID+")",
- new String[] { "articles."+BaseColumns._ID },
- feedClause + " AND (articles.title LIKE '%' || ? || '%' OR content LIKE '%' || ? || '%')",
- new String[] { String.valueOf(m_feedId), m_searchQuery, m_searchQuery }, null, null, orderBy);
- }
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close();
- }
-
- private class PagerAdapter extends FragmentStatePagerAdapter {
- public PagerAdapter(FragmentManager fm) {
- super(fm);
- }
-
- @Override
- public Fragment getItem(int position) {
- Log.d(TAG, "getItem: " + position);
-
- if (m_cursor.moveToPosition(position)) {
-
- if (m_prefs.getBoolean("dim_status_bar", false) && getView() != null && !m_activity.isCompatMode()) {
- getView().setSystemUiVisibility(View.STATUS_BAR_HIDDEN);
- }
-
- return new OfflineArticleFragment(m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID)));
- }
-
- return null;
- }
-
- @Override
- public int getCount() {
- return m_cursor.getCount();
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- if (!m_activity.isCompatMode() && m_prefs.getBoolean("dim_status_bar", false)) {
- getView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE);
- }
-
- if (m_prefs.getBoolean("full_screen_mode", false)) {
- m_activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
- WindowManager.LayoutParams.FLAG_FULLSCREEN);
-
- /* if (!m_activity.isCompatMode()) {
- m_activity.getActionBar().hide();
- } */
- }
- }
-
- public OfflineArticlePager() {
- super();
- }
-
- public OfflineArticlePager(int articleId, int feedId, boolean isCat) {
- super();
-
- m_feedId = feedId;
- m_isCat = isCat;
- m_articleId = articleId;
-
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View view = inflater.inflate(R.layout.article_pager, container, false);
-
- if (savedInstanceState != null) {
- m_articleId = savedInstanceState.getInt("articleId", 0);
- m_feedId = savedInstanceState.getInt("feedId", 0);
- m_isCat = savedInstanceState.getBoolean("isCat", false);
- }
-
- Log.d(TAG, "feed=" + m_feedId + "; iscat=" + m_isCat);
-
- m_cursor = createCursor();
-
- m_adapter = new PagerAdapter(getActivity().getSupportFragmentManager());
-
- int position = 0;
-
- Log.d(TAG, "maId=" + m_articleId);
-
- if (m_articleId != 0) {
- if (m_cursor.moveToFirst()) {
-
- while (!m_cursor.isAfterLast()) {
- if (m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID)) == m_articleId) {
- position = m_cursor.getPosition();
- break;
- }
- m_cursor.moveToNext();
- }
- }
- } else {
- if (m_cursor.moveToFirst()) {
- m_articleId = m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID));
- m_listener.onArticleSelected(m_articleId, false);
-
- Log.d(TAG, "maId=" + m_articleId);
- }
- }
-
-
- ViewPager pager = (ViewPager) view.findViewById(R.id.article_pager);
-
- pager.setAdapter(m_adapter);
-
- UnderlinePageIndicator indicator = (UnderlinePageIndicator)view.findViewById(R.id.article_titles);
- indicator.setViewPager(pager);
-
- pager.setCurrentItem(position);
- indicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
-
- @Override
- public void onPageScrollStateChanged(int arg0) {
- }
-
- @Override
- public void onPageScrolled(int arg0, float arg1, int arg2) {
- }
-
- @Override
- public void onPageSelected(int position) {
- if (m_cursor.moveToPosition(position)) {
- int articleId = m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID));
-
- m_articleId = articleId;
- m_listener.onArticleSelected(articleId, false);
- }
- }
- });
-
- return view;
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
-
- m_activity = (OfflineActivity)activity;
- m_listener = (OfflineHeadlinesEventListener)activity;
-
- m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
-
- }
-
- public void refresh() {
- if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close();
-
- m_cursor = createCursor();
-
- if (m_cursor != null) {
- m_adapter.notifyDataSetChanged();
- }
- }
-
- public int getSelectedArticleId() {
- return m_articleId;
- }
-
- @Override
- public void onSaveInstanceState(Bundle out) {
- super.onSaveInstanceState(out);
-
- out.putInt("articleId", m_articleId);
- out.putInt("feedId", m_feedId);
- out.putBoolean("isCat", m_isCat);
-
- }
-
- public void setSearchQuery(String searchQuery) {
- m_searchQuery = searchQuery;
- }
-
- public void setArticleId(int articleId) {
- m_articleId = articleId;
-
- int position = getArticleIdPosition(articleId);
-
- ViewPager pager = (ViewPager) getView().findViewById(R.id.article_pager);
-
- pager.setCurrentItem(position);
-
- }
-
- public int getArticleIdPosition(int articleId) {
- m_cursor.moveToFirst();
-
- while (!m_cursor.isAfterLast()) {
- if (m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID)) == articleId) {
- return m_cursor.getPosition();
- }
- m_cursor.moveToNext();
- }
-
- return -1;
- }
-
- public void selectArticle(boolean next) {
- int position = getArticleIdPosition(m_articleId);
-
- if (position != -1) {
- if (next)
- position++;
- else
- position--;
-
- Log.d(TAG, "pos=" + position);
-
- if (m_cursor.moveToPosition(position)) {
- setArticleId(m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID)));
- }
- }
- }
-}
+package org.fox.ttrss.offline; + +import org.fox.ttrss.R; + +import com.viewpagerindicator.UnderlinePageIndicator; + +import android.app.Activity; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.provider.BaseColumns; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentStatePagerAdapter; +import android.support.v4.view.ViewPager; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; + +public class OfflineArticlePager extends Fragment { + private final String TAG = this.getClass().getSimpleName(); + + private PagerAdapter m_adapter; + private OfflineActivity m_activity; + private OfflineHeadlinesEventListener m_listener; + private boolean m_isCat; + private int m_feedId; + private int m_articleId; + private String m_searchQuery = ""; + private Cursor m_cursor; + private SharedPreferences m_prefs; + + public int getFeedId() { + return m_feedId; + } + + public boolean getFeedIsCat() { + return m_isCat; + } + + public Cursor createCursor() { + String feedClause = null; + + if (m_isCat) { + feedClause = "feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)"; + } else { + feedClause = "feed_id = ?"; + } + + String orderBy = (m_prefs.getBoolean("offline_oldest_first", false)) ? "updated" : "updated DESC"; + + if (m_searchQuery == null || m_searchQuery.equals("")) { + return m_activity.getReadableDb().query("articles LEFT JOIN feeds ON (feed_id = feeds."+BaseColumns._ID+")", + new String[] { "articles."+BaseColumns._ID, "feeds.title AS feed_title" }, feedClause, + new String[] { String.valueOf(m_feedId) }, null, null, orderBy); + } else { + return m_activity.getReadableDb().query("articles LEFT JOIN feeds ON (feed_id = feeds."+BaseColumns._ID+")", + new String[] { "articles."+BaseColumns._ID }, + feedClause + " AND (articles.title LIKE '%' || ? || '%' OR content LIKE '%' || ? || '%')", + new String[] { String.valueOf(m_feedId), m_searchQuery, m_searchQuery }, null, null, orderBy); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + + if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close(); + } + + private class PagerAdapter extends FragmentStatePagerAdapter { + public PagerAdapter(FragmentManager fm) { + super(fm); + } + + @Override + public Fragment getItem(int position) { + Log.d(TAG, "getItem: " + position); + + if (m_cursor.moveToPosition(position)) { + + if (m_prefs.getBoolean("dim_status_bar", false) && getView() != null && !m_activity.isCompatMode()) { + getView().setSystemUiVisibility(View.STATUS_BAR_HIDDEN); + } + + return new OfflineArticleFragment(m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID))); + } + + return null; + } + + @Override + public int getCount() { + return m_cursor.getCount(); + } + } + + @Override + public void onResume() { + super.onResume(); + + if (!m_activity.isCompatMode() && m_prefs.getBoolean("dim_status_bar", false)) { + getView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE); + } + + if (m_prefs.getBoolean("full_screen_mode", false)) { + m_activity.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, + WindowManager.LayoutParams.FLAG_FULLSCREEN); + + /* if (!m_activity.isCompatMode()) { + m_activity.getSupportActionBar().hide(); + } */ + } + } + + public OfflineArticlePager() { + super(); + } + + public OfflineArticlePager(int articleId, int feedId, boolean isCat) { + super(); + + m_feedId = feedId; + m_isCat = isCat; + m_articleId = articleId; + + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.article_pager, container, false); + + if (savedInstanceState != null) { + m_articleId = savedInstanceState.getInt("articleId", 0); + m_feedId = savedInstanceState.getInt("feedId", 0); + m_isCat = savedInstanceState.getBoolean("isCat", false); + } + + Log.d(TAG, "feed=" + m_feedId + "; iscat=" + m_isCat); + + m_cursor = createCursor(); + + m_adapter = new PagerAdapter(getActivity().getSupportFragmentManager()); + + int position = 0; + + Log.d(TAG, "maId=" + m_articleId); + + if (m_articleId != 0) { + if (m_cursor.moveToFirst()) { + + while (!m_cursor.isAfterLast()) { + if (m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID)) == m_articleId) { + position = m_cursor.getPosition(); + break; + } + m_cursor.moveToNext(); + } + } + } else { + if (m_cursor.moveToFirst()) { + m_articleId = m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID)); + m_listener.onArticleSelected(m_articleId, false); + + Log.d(TAG, "maId=" + m_articleId); + } + } + + + ViewPager pager = (ViewPager) view.findViewById(R.id.article_pager); + + pager.setAdapter(m_adapter); + + UnderlinePageIndicator indicator = (UnderlinePageIndicator)view.findViewById(R.id.article_titles); + indicator.setViewPager(pager); + + pager.setCurrentItem(position); + indicator.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { + + @Override + public void onPageScrollStateChanged(int arg0) { + } + + @Override + public void onPageScrolled(int arg0, float arg1, int arg2) { + } + + @Override + public void onPageSelected(int position) { + if (m_cursor.moveToPosition(position)) { + int articleId = m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID)); + + m_articleId = articleId; + m_listener.onArticleSelected(articleId, false); + } + } + }); + + return view; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + m_activity = (OfflineActivity)activity; + m_listener = (OfflineHeadlinesEventListener)activity; + + m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()); + + } + + public void refresh() { + if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close(); + + m_cursor = createCursor(); + + if (m_cursor != null) { + m_adapter.notifyDataSetChanged(); + } + } + + public int getSelectedArticleId() { + return m_articleId; + } + + @Override + public void onSaveInstanceState(Bundle out) { + super.onSaveInstanceState(out); + + out.putInt("articleId", m_articleId); + out.putInt("feedId", m_feedId); + out.putBoolean("isCat", m_isCat); + + } + + public void setSearchQuery(String searchQuery) { + m_searchQuery = searchQuery; + } + + public void setArticleId(int articleId) { + m_articleId = articleId; + + int position = getArticleIdPosition(articleId); + + ViewPager pager = (ViewPager) getView().findViewById(R.id.article_pager); + + pager.setCurrentItem(position); + + } + + public int getArticleIdPosition(int articleId) { + m_cursor.moveToFirst(); + + while (!m_cursor.isAfterLast()) { + if (m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID)) == articleId) { + return m_cursor.getPosition(); + } + m_cursor.moveToNext(); + } + + return -1; + } + + public void selectArticle(boolean next) { + int position = getArticleIdPosition(m_articleId); + + if (position != -1) { + if (next) + position++; + else + position--; + + Log.d(TAG, "pos=" + position); + + if (m_cursor.moveToPosition(position)) { + setArticleId(m_cursor.getInt(m_cursor.getColumnIndex(BaseColumns._ID))); + } + } + } +} diff --git a/src/org/fox/ttrss/offline/OfflineDownloadService.java b/src/org/fox/ttrss/offline/OfflineDownloadService.java index 992c21f6..2fe87570 100644 --- a/src/org/fox/ttrss/offline/OfflineDownloadService.java +++ b/src/org/fox/ttrss/offline/OfflineDownloadService.java @@ -1,486 +1,486 @@ -package org.fox.ttrss.offline;
-
-import java.lang.reflect.Type;
-import java.util.HashMap;
-import java.util.List;
-
-import org.fox.ttrss.ApiRequest;
-import org.fox.ttrss.OnlineActivity;
-import org.fox.ttrss.R;
-import org.fox.ttrss.types.Article;
-import org.fox.ttrss.types.Feed;
-import org.fox.ttrss.types.FeedCategory;
-import org.fox.ttrss.util.DatabaseHelper;
-import org.fox.ttrss.util.ImageCacheService;
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Document;
-import org.jsoup.nodes.Element;
-import org.jsoup.select.Elements;
-
-import android.app.ActivityManager;
-import android.app.ActivityManager.RunningServiceInfo;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteStatement;
-import android.os.Binder;
-import android.os.IBinder;
-import android.preference.PreferenceManager;
-import android.provider.BaseColumns;
-import android.util.Log;
-
-import com.google.gson.Gson;
-import com.google.gson.JsonElement;
-import com.google.gson.reflect.TypeToken;
-
-public class OfflineDownloadService extends Service {
-
- private final String TAG = this.getClass().getSimpleName();
-
- public static final int NOTIFY_DOWNLOADING = 1;
- public static final String INTENT_ACTION_SUCCESS = "org.fox.ttrss.intent.action.DownloadComplete";
- public static final String INTENT_ACTION_CANCEL = "org.fox.ttrss.intent.action.Cancel";
-
- private static final int OFFLINE_SYNC_SEQ = 50;
- private static final int OFFLINE_SYNC_MAX = OFFLINE_SYNC_SEQ * 10;
-
- private SQLiteDatabase m_writableDb;
- private SQLiteDatabase m_readableDb;
- private int m_articleOffset = 0;
- private String m_sessionId;
- private NotificationManager m_nmgr;
-
- private boolean m_downloadInProgress = false;
- private boolean m_downloadImages = false;
- private int m_syncMax;
- private SharedPreferences m_prefs;
- private boolean m_canProceed = true;
-
- private final IBinder m_binder = new LocalBinder();
-
- public class LocalBinder extends Binder {
- OfflineDownloadService getService() {
- return OfflineDownloadService.this;
- }
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- return m_binder;
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- m_nmgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
- m_prefs = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext());
-
- m_downloadImages = m_prefs.getBoolean("offline_image_cache_enabled", false);
- m_syncMax = Integer.parseInt(m_prefs.getString("offline_sync_max", String.valueOf(OFFLINE_SYNC_MAX)));
-
- initDatabase();
- }
-
- @SuppressWarnings("deprecation")
- private void updateNotification(String msg) {
- Notification notification = new Notification(R.drawable.icon,
- getString(R.string.notify_downloading_title), System.currentTimeMillis());
-
- Intent intent = new Intent(this, OnlineActivity.class);
- intent.setAction(INTENT_ACTION_CANCEL);
-
- PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
- intent, 0);
-
- notification.flags |= Notification.FLAG_ONGOING_EVENT;
- notification.flags |= Notification.FLAG_ONLY_ALERT_ONCE;
-
- notification.setLatestEventInfo(this, getString(R.string.notify_downloading_title), msg, contentIntent);
-
- m_nmgr.notify(NOTIFY_DOWNLOADING, notification);
- }
-
- private void updateNotification(int msgResId) {
- updateNotification(getString(msgResId));
- }
-
- private void downloadFailed() {
- m_readableDb.close();
- m_writableDb.close();
-
- m_nmgr.cancel(NOTIFY_DOWNLOADING);
-
- // TODO send notification to activity?
-
- m_downloadInProgress = false;
- stopSelf();
- }
-
- private boolean isCacheServiceRunning() {
- ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
- for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
- if ("org.fox.ttrss.ImageCacheService".equals(service.service.getClassName())) {
- return true;
- }
- }
- return false;
- }
-
- public void downloadComplete() {
- m_downloadInProgress = false;
-
- // if cache service is running, it will send a finished intent on its own
- if (!isCacheServiceRunning()) {
- m_nmgr.cancel(NOTIFY_DOWNLOADING);
-
- Intent intent = new Intent();
- intent.setAction(INTENT_ACTION_SUCCESS);
- intent.addCategory(Intent.CATEGORY_DEFAULT);
- sendBroadcast(intent);
- } else {
- updateNotification(getString(R.string.notify_downloading_images, 0));
- }
-
- m_readableDb.close();
- m_writableDb.close();
-
- stopSelf();
- }
-
- private void initDatabase() {
- DatabaseHelper dh = new DatabaseHelper(getApplicationContext());
- m_writableDb = dh.getWritableDatabase();
- m_readableDb = dh.getReadableDatabase();
- }
-
- /* private synchronized SQLiteDatabase getReadableDb() {
- return m_readableDb;
- } */
-
- private synchronized SQLiteDatabase getWritableDb() {
- return m_writableDb;
- }
-
- @SuppressWarnings("unchecked")
- private void downloadArticles() {
- Log.d(TAG, "offline: downloading articles... offset=" + m_articleOffset);
-
- updateNotification(getString(R.string.notify_downloading_articles, m_articleOffset));
-
- OfflineArticlesRequest req = new OfflineArticlesRequest(this);
-
- @SuppressWarnings("serial")
- HashMap<String,String> map = new HashMap<String,String>() {
- {
- put("op", "getHeadlines");
- put("sid", m_sessionId);
- put("feed_id", "-4");
- put("view_mode", "unread");
- put("show_content", "true");
- put("skip", String.valueOf(m_articleOffset));
- put("limit", String.valueOf(OFFLINE_SYNC_SEQ));
- }
- };
-
- req.execute(map);
- }
-
- private void downloadFeeds() {
-
- updateNotification(R.string.notify_downloading_feeds);
-
- getWritableDb().execSQL("DELETE FROM feeds;");
-
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- @Override
- protected JsonElement doInBackground(HashMap<String, String>... params) {
- JsonElement content = super.doInBackground(params);
-
- if (content != null) {
-
- try {
- Type listType = new TypeToken<List<Feed>>() {}.getType();
- List<Feed> feeds = new Gson().fromJson(content, listType);
-
- SQLiteStatement stmtInsert = getWritableDb().compileStatement("INSERT INTO feeds " +
- "("+BaseColumns._ID+", title, feed_url, has_icon, cat_id) " +
- "VALUES (?, ?, ?, ?, ?);");
-
- for (Feed feed : feeds) {
- stmtInsert.bindLong(1, feed.id);
- stmtInsert.bindString(2, feed.title);
- stmtInsert.bindString(3, feed.feed_url);
- stmtInsert.bindLong(4, feed.has_icon ? 1 : 0);
- stmtInsert.bindLong(5, feed.cat_id);
-
- stmtInsert.execute();
- }
-
- stmtInsert.close();
-
- Log.d(TAG, "offline: done downloading feeds");
-
- m_articleOffset = 0;
-
- getWritableDb().execSQL("DELETE FROM articles;");
- } catch (Exception e) {
- e.printStackTrace();
- updateNotification(R.string.offline_switch_error);
- downloadFailed();
- }
- }
-
- return content;
- }
-
- @Override
- protected void onPostExecute(JsonElement content) {
- if (content != null) {
- if (m_canProceed) {
- downloadArticles();
- } else {
- downloadFailed();
- }
- } else {
- updateNotification(getErrorMessage());
- downloadFailed();
- }
- }
-
- };
-
- @SuppressWarnings("serial")
- HashMap<String,String> map = new HashMap<String,String>() {
- {
- put("op", "getFeeds");
- put("sid", m_sessionId);
- put("cat_id", "-3");
- put("unread_only", "true");
- }
- };
-
- req.execute(map);
- }
-
- private void downloadCategories() {
-
- updateNotification(R.string.notify_downloading_feeds);
-
- getWritableDb().execSQL("DELETE FROM categories;");
-
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- protected JsonElement doInBackground(HashMap<String, String>... params) {
- JsonElement content = super.doInBackground(params);
-
- if (content != null) {
- try {
- Type listType = new TypeToken<List<FeedCategory>>() {}.getType();
- List<FeedCategory> cats = new Gson().fromJson(content, listType);
-
- SQLiteStatement stmtInsert = getWritableDb().compileStatement("INSERT INTO categories " +
- "("+BaseColumns._ID+", title) " +
- "VALUES (?, ?);");
-
- for (FeedCategory cat : cats) {
- stmtInsert.bindLong(1, cat.id);
- stmtInsert.bindString(2, cat.title);
-
- stmtInsert.execute();
- }
-
- stmtInsert.close();
-
- Log.d(TAG, "offline: done downloading categories");
-
- } catch (Exception e) {
- e.printStackTrace();
- updateNotification(R.string.offline_switch_error);
- downloadFailed();
- }
- }
-
- return content;
- }
- @Override
- protected void onPostExecute(JsonElement content) {
- if (content != null) {
- if (m_canProceed) {
- downloadFeeds();
- } else {
- downloadFailed();
- }
- } else {
- updateNotification(getErrorMessage());
- downloadFailed();
- }
- }
-
- };
-
- @SuppressWarnings("serial")
- HashMap<String,String> map = new HashMap<String,String>() {
- {
- put("op", "getCategories");
- put("sid", m_sessionId);
- //put("cat_id", "-3");
- put("unread_only", "true");
- }
- };
-
- req.execute(map);
- }
-
-
- @Override
- public void onDestroy() {
- super.onDestroy();
- m_nmgr.cancel(NOTIFY_DOWNLOADING);
-
- m_canProceed = false;
- Log.d(TAG, "onDestroy");
-
- //m_readableDb.close();
- //m_writableDb.close();
- }
-
- public class OfflineArticlesRequest extends ApiRequest {
- List<Article> m_articles;
-
- public OfflineArticlesRequest(Context context) {
- super(context);
- }
-
- @Override
- protected JsonElement doInBackground(HashMap<String, String>... params) {
- JsonElement content = super.doInBackground(params);
-
- if (content != null) {
-
- try {
- Type listType = new TypeToken<List<Article>>() {}.getType();
- m_articles = new Gson().fromJson(content, listType);
-
- SQLiteStatement stmtInsert = getWritableDb().compileStatement("INSERT INTO articles " +
- "("+BaseColumns._ID+", unread, marked, published, updated, is_updated, title, link, feed_id, tags, content) " +
- "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);");
-
- for (Article article : m_articles) {
-
- String tagsString = "";
-
- for (String t : article.tags) {
- tagsString += t + ", ";
- }
-
- tagsString = tagsString.replaceAll(", $", "");
-
- stmtInsert.bindLong(1, article.id);
- stmtInsert.bindLong(2, article.unread ? 1 : 0);
- stmtInsert.bindLong(3, article.marked ? 1 : 0);
- stmtInsert.bindLong(4, article.published ? 1 : 0);
- stmtInsert.bindLong(5, article.updated);
- stmtInsert.bindLong(6, article.is_updated ? 1 : 0);
- stmtInsert.bindString(7, article.title);
- stmtInsert.bindString(8, article.link);
- stmtInsert.bindLong(9, article.feed_id);
- stmtInsert.bindString(10, tagsString); // comma-separated tags
- stmtInsert.bindString(11, article.content);
-
- if (m_downloadImages) {
- Document doc = Jsoup.parse(article.content);
-
- if (doc != null) {
- Elements images = doc.select("img");
-
- for (Element img : images) {
- String url = img.attr("src");
-
- if (url.indexOf("://") != -1) {
- if (!ImageCacheService.isUrlCached(OfflineDownloadService.this, url)) {
- Intent intent = new Intent(OfflineDownloadService.this,
- ImageCacheService.class);
-
- intent.putExtra("url", url);
- startService(intent);
- }
- }
- }
- }
- }
-
- try {
- stmtInsert.execute();
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- }
-
- m_articleOffset += m_articles.size();
-
- Log.d(TAG, "offline: received " + m_articles.size() + " articles; canProc=" + m_canProceed);
-
- stmtInsert.close();
-
- } catch (Exception e) {
- updateNotification(R.string.offline_switch_error);
- Log.d(TAG, "offline: failed: exception when loading articles");
- e.printStackTrace();
- downloadFailed();
- }
-
- }
-
- return content;
- }
-
- @Override
- protected void onPostExecute(JsonElement content) {
- if (content != null) {
-
- if (m_canProceed && m_articles != null) {
- if (m_articles.size() == OFFLINE_SYNC_SEQ && m_articleOffset < m_syncMax) {
- downloadArticles();
- } else {
- downloadComplete();
- }
- } else {
- downloadFailed();
- }
-
- } else {
- Log.d(TAG, "offline: failed: " + getErrorMessage());
- updateNotification(getErrorMessage());
- downloadFailed();
- }
- }
- }
-
- @Override
- public void onStart(Intent intent, int startId) {
- try {
- if (getWritableDb().isDbLockedByCurrentThread() || getWritableDb().isDbLockedByOtherThreads()) {
- return;
- }
-
- m_sessionId = intent.getStringExtra("sessionId");
-
- if (!m_downloadInProgress) {
- if (m_downloadImages) ImageCacheService.cleanupCache(this, false);
-
- updateNotification(R.string.notify_downloading_init);
- m_downloadInProgress = true;
-
- downloadCategories();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-}
+package org.fox.ttrss.offline; + +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.List; + +import org.fox.ttrss.ApiRequest; +import org.fox.ttrss.OnlineActivity; +import org.fox.ttrss.R; +import org.fox.ttrss.types.Article; +import org.fox.ttrss.types.Feed; +import org.fox.ttrss.types.FeedCategory; +import org.fox.ttrss.util.DatabaseHelper; +import org.fox.ttrss.util.ImageCacheService; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; +import org.jsoup.select.Elements; + +import android.app.ActivityManager; +import android.app.ActivityManager.RunningServiceInfo; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteStatement; +import android.os.Binder; +import android.os.IBinder; +import android.preference.PreferenceManager; +import android.provider.BaseColumns; +import android.util.Log; + +import com.google.gson.Gson; +import com.google.gson.JsonElement; +import com.google.gson.reflect.TypeToken; + +public class OfflineDownloadService extends Service { + + private final String TAG = this.getClass().getSimpleName(); + + public static final int NOTIFY_DOWNLOADING = 1; + public static final String INTENT_ACTION_SUCCESS = "org.fox.ttrss.intent.action.DownloadComplete"; + public static final String INTENT_ACTION_CANCEL = "org.fox.ttrss.intent.action.Cancel"; + + private static final int OFFLINE_SYNC_SEQ = 50; + private static final int OFFLINE_SYNC_MAX = OFFLINE_SYNC_SEQ * 10; + + private SQLiteDatabase m_writableDb; + private SQLiteDatabase m_readableDb; + private int m_articleOffset = 0; + private String m_sessionId; + private NotificationManager m_nmgr; + + private boolean m_downloadInProgress = false; + private boolean m_downloadImages = false; + private int m_syncMax; + private SharedPreferences m_prefs; + private boolean m_canProceed = true; + + private final IBinder m_binder = new LocalBinder(); + + public class LocalBinder extends Binder { + OfflineDownloadService getService() { + return OfflineDownloadService.this; + } + } + + @Override + public IBinder onBind(Intent intent) { + return m_binder; + } + + @Override + public void onCreate() { + super.onCreate(); + m_nmgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); + m_prefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + m_downloadImages = m_prefs.getBoolean("offline_image_cache_enabled", false); + m_syncMax = Integer.parseInt(m_prefs.getString("offline_sync_max", String.valueOf(OFFLINE_SYNC_MAX))); + + initDatabase(); + } + + @SuppressWarnings("deprecation") + private void updateNotification(String msg) { + Notification notification = new Notification(R.drawable.icon, + getString(R.string.notify_downloading_title), System.currentTimeMillis()); + + Intent intent = new Intent(this, OnlineActivity.class); + intent.setAction(INTENT_ACTION_CANCEL); + + PendingIntent contentIntent = PendingIntent.getActivity(this, 0, + intent, 0); + + notification.flags |= Notification.FLAG_ONGOING_EVENT; + notification.flags |= Notification.FLAG_ONLY_ALERT_ONCE; + + notification.setLatestEventInfo(this, getString(R.string.notify_downloading_title), msg, contentIntent); + + m_nmgr.notify(NOTIFY_DOWNLOADING, notification); + } + + private void updateNotification(int msgResId) { + updateNotification(getString(msgResId)); + } + + private void downloadFailed() { + m_readableDb.close(); + m_writableDb.close(); + + m_nmgr.cancel(NOTIFY_DOWNLOADING); + + // TODO send notification to activity? + + m_downloadInProgress = false; + stopSelf(); + } + + private boolean isCacheServiceRunning() { + ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE); + for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) { + if ("org.fox.ttrss.ImageCacheService".equals(service.service.getClassName())) { + return true; + } + } + return false; + } + + public void downloadComplete() { + m_downloadInProgress = false; + + // if cache service is running, it will send a finished intent on its own + if (!isCacheServiceRunning()) { + m_nmgr.cancel(NOTIFY_DOWNLOADING); + + Intent intent = new Intent(); + intent.setAction(INTENT_ACTION_SUCCESS); + intent.addCategory(Intent.CATEGORY_DEFAULT); + sendBroadcast(intent); + } else { + updateNotification(getString(R.string.notify_downloading_images, 0)); + } + + m_readableDb.close(); + m_writableDb.close(); + + stopSelf(); + } + + private void initDatabase() { + DatabaseHelper dh = new DatabaseHelper(getApplicationContext()); + m_writableDb = dh.getWritableDatabase(); + m_readableDb = dh.getReadableDatabase(); + } + + /* private synchronized SQLiteDatabase getReadableDb() { + return m_readableDb; + } */ + + private synchronized SQLiteDatabase getWritableDb() { + return m_writableDb; + } + + @SuppressWarnings("unchecked") + private void downloadArticles() { + Log.d(TAG, "offline: downloading articles... offset=" + m_articleOffset); + + updateNotification(getString(R.string.notify_downloading_articles, m_articleOffset)); + + OfflineArticlesRequest req = new OfflineArticlesRequest(this); + + @SuppressWarnings("serial") + HashMap<String,String> map = new HashMap<String,String>() { + { + put("op", "getHeadlines"); + put("sid", m_sessionId); + put("feed_id", "-4"); + put("view_mode", "unread"); + put("show_content", "true"); + put("skip", String.valueOf(m_articleOffset)); + put("limit", String.valueOf(OFFLINE_SYNC_SEQ)); + } + }; + + req.execute(map); + } + + private void downloadFeeds() { + + updateNotification(R.string.notify_downloading_feeds); + + getWritableDb().execSQL("DELETE FROM feeds;"); + + ApiRequest req = new ApiRequest(getApplicationContext()) { + @Override + protected JsonElement doInBackground(HashMap<String, String>... params) { + JsonElement content = super.doInBackground(params); + + if (content != null) { + + try { + Type listType = new TypeToken<List<Feed>>() {}.getType(); + List<Feed> feeds = new Gson().fromJson(content, listType); + + SQLiteStatement stmtInsert = getWritableDb().compileStatement("INSERT INTO feeds " + + "("+BaseColumns._ID+", title, feed_url, has_icon, cat_id) " + + "VALUES (?, ?, ?, ?, ?);"); + + for (Feed feed : feeds) { + stmtInsert.bindLong(1, feed.id); + stmtInsert.bindString(2, feed.title); + stmtInsert.bindString(3, feed.feed_url); + stmtInsert.bindLong(4, feed.has_icon ? 1 : 0); + stmtInsert.bindLong(5, feed.cat_id); + + stmtInsert.execute(); + } + + stmtInsert.close(); + + Log.d(TAG, "offline: done downloading feeds"); + + m_articleOffset = 0; + + getWritableDb().execSQL("DELETE FROM articles;"); + } catch (Exception e) { + e.printStackTrace(); + updateNotification(R.string.offline_switch_error); + downloadFailed(); + } + } + + return content; + } + + @Override + protected void onPostExecute(JsonElement content) { + if (content != null) { + if (m_canProceed) { + downloadArticles(); + } else { + downloadFailed(); + } + } else { + updateNotification(getErrorMessage()); + downloadFailed(); + } + } + + }; + + @SuppressWarnings("serial") + HashMap<String,String> map = new HashMap<String,String>() { + { + put("op", "getFeeds"); + put("sid", m_sessionId); + put("cat_id", "-3"); + put("unread_only", "true"); + } + }; + + req.execute(map); + } + + private void downloadCategories() { + + updateNotification(R.string.notify_downloading_feeds); + + getWritableDb().execSQL("DELETE FROM categories;"); + + ApiRequest req = new ApiRequest(getApplicationContext()) { + protected JsonElement doInBackground(HashMap<String, String>... params) { + JsonElement content = super.doInBackground(params); + + if (content != null) { + try { + Type listType = new TypeToken<List<FeedCategory>>() {}.getType(); + List<FeedCategory> cats = new Gson().fromJson(content, listType); + + SQLiteStatement stmtInsert = getWritableDb().compileStatement("INSERT INTO categories " + + "("+BaseColumns._ID+", title) " + + "VALUES (?, ?);"); + + for (FeedCategory cat : cats) { + stmtInsert.bindLong(1, cat.id); + stmtInsert.bindString(2, cat.title); + + stmtInsert.execute(); + } + + stmtInsert.close(); + + Log.d(TAG, "offline: done downloading categories"); + + } catch (Exception e) { + e.printStackTrace(); + updateNotification(R.string.offline_switch_error); + downloadFailed(); + } + } + + return content; + } + @Override + protected void onPostExecute(JsonElement content) { + if (content != null) { + if (m_canProceed) { + downloadFeeds(); + } else { + downloadFailed(); + } + } else { + updateNotification(getErrorMessage()); + downloadFailed(); + } + } + + }; + + @SuppressWarnings("serial") + HashMap<String,String> map = new HashMap<String,String>() { + { + put("op", "getCategories"); + put("sid", m_sessionId); + //put("cat_id", "-3"); + put("unread_only", "true"); + } + }; + + req.execute(map); + } + + + @Override + public void onDestroy() { + super.onDestroy(); + m_nmgr.cancel(NOTIFY_DOWNLOADING); + + m_canProceed = false; + Log.d(TAG, "onDestroy"); + + //m_readableDb.close(); + //m_writableDb.close(); + } + + public class OfflineArticlesRequest extends ApiRequest { + List<Article> m_articles; + + public OfflineArticlesRequest(Context context) { + super(context); + } + + @Override + protected JsonElement doInBackground(HashMap<String, String>... params) { + JsonElement content = super.doInBackground(params); + + if (content != null) { + + try { + Type listType = new TypeToken<List<Article>>() {}.getType(); + m_articles = new Gson().fromJson(content, listType); + + SQLiteStatement stmtInsert = getWritableDb().compileStatement("INSERT INTO articles " + + "("+BaseColumns._ID+", unread, marked, published, updated, is_updated, title, link, feed_id, tags, content) " + + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"); + + for (Article article : m_articles) { + + String tagsString = ""; + + for (String t : article.tags) { + tagsString += t + ", "; + } + + tagsString = tagsString.replaceAll(", $", ""); + + stmtInsert.bindLong(1, article.id); + stmtInsert.bindLong(2, article.unread ? 1 : 0); + stmtInsert.bindLong(3, article.marked ? 1 : 0); + stmtInsert.bindLong(4, article.published ? 1 : 0); + stmtInsert.bindLong(5, article.updated); + stmtInsert.bindLong(6, article.is_updated ? 1 : 0); + stmtInsert.bindString(7, article.title); + stmtInsert.bindString(8, article.link); + stmtInsert.bindLong(9, article.feed_id); + stmtInsert.bindString(10, tagsString); // comma-separated tags + stmtInsert.bindString(11, article.content); + + if (m_downloadImages) { + Document doc = Jsoup.parse(article.content); + + if (doc != null) { + Elements images = doc.select("img"); + + for (Element img : images) { + String url = img.attr("src"); + + if (url.indexOf("://") != -1) { + if (!ImageCacheService.isUrlCached(OfflineDownloadService.this, url)) { + Intent intent = new Intent(OfflineDownloadService.this, + ImageCacheService.class); + + intent.putExtra("url", url); + startService(intent); + } + } + } + } + } + + try { + stmtInsert.execute(); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + m_articleOffset += m_articles.size(); + + Log.d(TAG, "offline: received " + m_articles.size() + " articles; canProc=" + m_canProceed); + + stmtInsert.close(); + + } catch (Exception e) { + updateNotification(R.string.offline_switch_error); + Log.d(TAG, "offline: failed: exception when loading articles"); + e.printStackTrace(); + downloadFailed(); + } + + } + + return content; + } + + @Override + protected void onPostExecute(JsonElement content) { + if (content != null) { + + if (m_canProceed && m_articles != null) { + if (m_articles.size() == OFFLINE_SYNC_SEQ && m_articleOffset < m_syncMax) { + downloadArticles(); + } else { + downloadComplete(); + } + } else { + downloadFailed(); + } + + } else { + Log.d(TAG, "offline: failed: " + getErrorMessage()); + updateNotification(getErrorMessage()); + downloadFailed(); + } + } + } + + @Override + public void onStart(Intent intent, int startId) { + try { + if (getWritableDb().isDbLockedByCurrentThread() || getWritableDb().isDbLockedByOtherThreads()) { + return; + } + + m_sessionId = intent.getStringExtra("sessionId"); + + if (!m_downloadInProgress) { + if (m_downloadImages) ImageCacheService.cleanupCache(this, false); + + updateNotification(R.string.notify_downloading_init); + m_downloadInProgress = true; + + downloadCategories(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/org/fox/ttrss/offline/OfflineFeedCategoriesFragment.java b/src/org/fox/ttrss/offline/OfflineFeedCategoriesFragment.java index e27c6e4b..dbc62f4f 100644 --- a/src/org/fox/ttrss/offline/OfflineFeedCategoriesFragment.java +++ b/src/org/fox/ttrss/offline/OfflineFeedCategoriesFragment.java @@ -1,324 +1,324 @@ -package org.fox.ttrss.offline;
-
-import org.fox.ttrss.R;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import android.database.Cursor;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.provider.BaseColumns;
-import android.support.v4.app.Fragment;
-import android.support.v4.widget.SimpleCursorAdapter;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.AdapterView.AdapterContextMenuInfo;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.TextView;
-
-public class OfflineFeedCategoriesFragment extends Fragment implements OnItemClickListener, OnSharedPreferenceChangeListener {
- private final String TAG = this.getClass().getSimpleName();
- private SharedPreferences m_prefs;
- private FeedCategoryListAdapter m_adapter;
- private int m_selectedCatId;
- private Cursor m_cursor;
- private OfflineFeedsActivity m_activity;
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
-
- getActivity().getMenuInflater().inflate(R.menu.category_menu, menu);
-
- AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
- Cursor cursor = (Cursor)m_adapter.getItem(info.position);
-
- if (cursor != null)
- menu.setHeaderTitle(cursor.getString(cursor.getColumnIndex("title")));
-
- if (!m_activity.isSmallScreen()) {
- menu.findItem(R.id.browse_articles).setVisible(false);
- }
-
- super.onCreateContextMenu(menu, v, menuInfo);
-
- }
-
- public Cursor createCursor() {
- String unreadOnly = BaseColumns._ID + "> 0 AND " + (m_activity.getUnreadOnly() ? "unread > 0" : "1");
-
- String order = m_prefs.getBoolean("sort_feeds_by_unread", false) ? "unread DESC, title" : "title";
-
- return m_activity.getReadableDb().query("cats_unread",
- null, unreadOnly, null, null, null, order);
- }
-
- public void refresh() {
- if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close();
-
- m_cursor = createCursor();
-
- if (m_cursor != null) {
- m_adapter.changeCursor(m_cursor);
- m_adapter.notifyDataSetChanged();
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
- refresh();
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem item) {
- AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
- .getMenuInfo();
-
- switch (item.getItemId()) {
- case R.id.browse_articles:
- if (true) {
- int catId = getCatIdAtPosition(info.position);
- if (catId != -10000) {
- m_activity.openFeedArticles(catId, true);
- }
- }
- return true;
- case R.id.browse_headlines:
- if (true) {
- int catId = getCatIdAtPosition(info.position);
- if (catId != -10000) {
- m_activity.onCatSelected(catId, true);
- }
- }
- return true;
- case R.id.browse_feeds:
- if (true) {
- int catId = getCatIdAtPosition(info.position);
- if (catId != -10000) {
- m_activity.onCatSelected(catId, false);
- }
- }
- return true;
- case R.id.catchup_category:
- if (true) {
- int catId = getCatIdAtPosition(info.position);
- if (catId != -10000) {
- m_activity.catchupFeed(catId, true);
- }
- }
- return true;
- default:
- Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId());
- return super.onContextItemSelected(item);
- }
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-
- if (savedInstanceState != null) {
- m_selectedCatId = savedInstanceState.getInt("selectedFeedId");
- }
-
- View view = inflater.inflate(R.layout.feeds_fragment, container, false);
-
- ListView list = (ListView)view.findViewById(R.id.feeds);
-
- m_cursor = createCursor();
-
- m_adapter = new FeedCategoryListAdapter(getActivity(), R.layout.feeds_row, m_cursor,
- new String[] { "title", "unread" }, new int[] { R.id.title, R.id.unread_counter }, 0);
-
- list.setAdapter(m_adapter);
- list.setOnItemClickListener(this);
- list.setEmptyView(view.findViewById(R.id.no_feeds));
- registerForContextMenu(list);
-
- view.findViewById(R.id.loading_container).setVisibility(View.GONE);
-
- return view;
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close();
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
-
- m_activity = (OfflineFeedsActivity)activity;
-
- m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
- m_prefs.registerOnSharedPreferenceChangeListener(this);
-
- }
-
- @Override
- public void onSaveInstanceState (Bundle out) {
- super.onSaveInstanceState(out);
-
- out.putInt("selectedFeedId", m_selectedCatId);
- }
-
- @Override
- public void onItemClick(AdapterView<?> av, View view, int position, long id) {
- ListView list = (ListView)getActivity().findViewById(R.id.feeds);
-
- if (list != null) {
- Cursor cursor = (Cursor) list.getItemAtPosition(position);
-
- if (cursor != null) {
- int feedId = (int) cursor.getLong(0);
- Log.d(TAG, "clicked on feed " + feedId);
-
- if (m_activity.isSmallScreen() && "ARTICLES".equals(m_prefs.getString("default_view_mode", "HEADLINES")) &&
- m_prefs.getBoolean("browse_cats_like_feeds", false)) {
-
- m_activity.openFeedArticles(feedId, true);
-
- } else {
- m_activity.onCatSelected(feedId);
- }
-
- if (!m_activity.isSmallScreen())
- m_selectedCatId = feedId;
-
- m_adapter.notifyDataSetChanged();
- }
- }
- }
-
- /* public void setLoadingStatus(int status, boolean showProgress) {
- if (getView() != null) {
- TextView tv = (TextView)getView().findViewById(R.id.loading_message);
-
- if (tv != null) {
- tv.setText(status);
- }
- }
-
- getActivity().setProgressBarIndeterminateVisibility(showProgress);
- } */
-
- private class FeedCategoryListAdapter extends SimpleCursorAdapter {
-
-
- public FeedCategoryListAdapter(Context context, int layout, Cursor c,
- String[] from, int[] to, int flags) {
- super(context, layout, c, from, to, flags);
- }
-
- public static final int VIEW_NORMAL = 0;
- public static final int VIEW_SELECTED = 1;
-
- public static final int VIEW_COUNT = VIEW_SELECTED+1;
-
- @Override
- public int getViewTypeCount() {
- return VIEW_COUNT;
- }
-
- @Override
- public int getItemViewType(int position) {
- Cursor cursor = (Cursor) this.getItem(position);
-
- if (!m_activity.isSmallScreen() && cursor.getLong(0) == m_selectedCatId) {
- return VIEW_SELECTED;
- } else {
- return VIEW_NORMAL;
- }
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- View v = convertView;
-
- Cursor cursor = (Cursor)getItem(position);
-
- if (v == null) {
- int layoutId = R.layout.feeds_row;
-
- switch (getItemViewType(position)) {
- case VIEW_SELECTED:
- layoutId = R.layout.feeds_row_selected;
- break;
- }
-
- LayoutInflater vi = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- v = vi.inflate(layoutId, null);
-
- }
-
- TextView tt = (TextView) v.findViewById(R.id.title);
-
- if (tt != null) {
- tt.setText(cursor.getString(cursor.getColumnIndex("title")));
- }
-
- TextView tu = (TextView) v.findViewById(R.id.unread_counter);
-
- if (tu != null) {
- tu.setText(String.valueOf(cursor.getInt(cursor.getColumnIndex("unread"))));
- tu.setVisibility((cursor.getInt(cursor.getColumnIndex("unread")) > 0) ? View.VISIBLE : View.INVISIBLE);
- }
-
- ImageView icon = (ImageView)v.findViewById(R.id.icon);
-
- if (icon != null) {
- icon.setImageResource(cursor.getInt(cursor.getColumnIndex("unread")) > 0 ? R.drawable.ic_rss : R.drawable.ic_rss_bw);
- }
-
- return v;
- }
- }
-
- public void sortCategories() {
- try {
- refresh();
- } catch (NullPointerException e) {
- // activity is gone?
- } catch (IllegalStateException e) {
- // we're probably closing and DB is gone already
- }
- }
-
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
- String key) {
-
- sortCategories();
- }
-
- public int getCatIdAtPosition(int position) {
- Cursor c = (Cursor)m_adapter.getItem(position);
-
- if (c != null) {
- int catId = c.getInt(0);
- c.close();
- return catId;
- }
-
- return -10000;
- }
-
- public void setSelectedFeedId(int feedId) {
- m_selectedCatId = feedId;
- refresh();
- }
-
-}
+package org.fox.ttrss.offline; + +import org.fox.ttrss.R; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.database.Cursor; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.provider.BaseColumns; +import android.support.v4.app.Fragment; +import android.support.v4.widget.SimpleCursorAdapter; +import android.util.Log; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.AdapterContextMenuInfo; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +public class OfflineFeedCategoriesFragment extends Fragment implements OnItemClickListener, OnSharedPreferenceChangeListener { + private final String TAG = this.getClass().getSimpleName(); + private SharedPreferences m_prefs; + private FeedCategoryListAdapter m_adapter; + private int m_selectedCatId; + private Cursor m_cursor; + private OfflineFeedsActivity m_activity; + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + + getActivity().getMenuInflater().inflate(R.menu.category_menu, menu); + + AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; + Cursor cursor = (Cursor)m_adapter.getItem(info.position); + + if (cursor != null) + menu.setHeaderTitle(cursor.getString(cursor.getColumnIndex("title"))); + + if (!m_activity.isSmallScreen()) { + menu.findItem(R.id.browse_articles).setVisible(false); + } + + super.onCreateContextMenu(menu, v, menuInfo); + + } + + public Cursor createCursor() { + String unreadOnly = BaseColumns._ID + "> 0 AND " + (m_activity.getUnreadOnly() ? "unread > 0" : "1"); + + String order = m_prefs.getBoolean("sort_feeds_by_unread", false) ? "unread DESC, title" : "title"; + + return m_activity.getReadableDb().query("cats_unread", + null, unreadOnly, null, null, null, order); + } + + public void refresh() { + if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close(); + + m_cursor = createCursor(); + + if (m_cursor != null) { + m_adapter.changeCursor(m_cursor); + m_adapter.notifyDataSetChanged(); + } + } + + @Override + public void onResume() { + super.onResume(); + refresh(); + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + AdapterContextMenuInfo info = (AdapterContextMenuInfo) item + .getMenuInfo(); + + switch (item.getItemId()) { + case R.id.browse_articles: + if (true) { + int catId = getCatIdAtPosition(info.position); + if (catId != -10000) { + m_activity.openFeedArticles(catId, true); + } + } + return true; + case R.id.browse_headlines: + if (true) { + int catId = getCatIdAtPosition(info.position); + if (catId != -10000) { + m_activity.onCatSelected(catId, true); + } + } + return true; + case R.id.browse_feeds: + if (true) { + int catId = getCatIdAtPosition(info.position); + if (catId != -10000) { + m_activity.onCatSelected(catId, false); + } + } + return true; + case R.id.catchup_category: + if (true) { + int catId = getCatIdAtPosition(info.position); + if (catId != -10000) { + m_activity.catchupFeed(catId, true); + } + } + return true; + default: + Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId()); + return super.onContextItemSelected(item); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + if (savedInstanceState != null) { + m_selectedCatId = savedInstanceState.getInt("selectedFeedId"); + } + + View view = inflater.inflate(R.layout.feeds_fragment, container, false); + + ListView list = (ListView)view.findViewById(R.id.feeds); + + m_cursor = createCursor(); + + m_adapter = new FeedCategoryListAdapter(getActivity(), R.layout.feeds_row, m_cursor, + new String[] { "title", "unread" }, new int[] { R.id.title, R.id.unread_counter }, 0); + + list.setAdapter(m_adapter); + list.setOnItemClickListener(this); + list.setEmptyView(view.findViewById(R.id.no_feeds)); + registerForContextMenu(list); + + view.findViewById(R.id.loading_container).setVisibility(View.GONE); + + return view; + } + + @Override + public void onDestroy() { + super.onDestroy(); + + if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close(); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + m_activity = (OfflineFeedsActivity)activity; + + m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()); + m_prefs.registerOnSharedPreferenceChangeListener(this); + + } + + @Override + public void onSaveInstanceState (Bundle out) { + super.onSaveInstanceState(out); + + out.putInt("selectedFeedId", m_selectedCatId); + } + + @Override + public void onItemClick(AdapterView<?> av, View view, int position, long id) { + ListView list = (ListView)getActivity().findViewById(R.id.feeds); + + if (list != null) { + Cursor cursor = (Cursor) list.getItemAtPosition(position); + + if (cursor != null) { + int feedId = (int) cursor.getLong(0); + Log.d(TAG, "clicked on feed " + feedId); + + if (m_activity.isSmallScreen() && "ARTICLES".equals(m_prefs.getString("default_view_mode", "HEADLINES")) && + m_prefs.getBoolean("browse_cats_like_feeds", false)) { + + m_activity.openFeedArticles(feedId, true); + + } else { + m_activity.onCatSelected(feedId); + } + + if (!m_activity.isSmallScreen()) + m_selectedCatId = feedId; + + m_adapter.notifyDataSetChanged(); + } + } + } + + /* public void setLoadingStatus(int status, boolean showProgress) { + if (getView() != null) { + TextView tv = (TextView)getView().findViewById(R.id.loading_message); + + if (tv != null) { + tv.setText(status); + } + } + + getActivity().setProgressBarIndeterminateVisibility(showProgress); + } */ + + private class FeedCategoryListAdapter extends SimpleCursorAdapter { + + + public FeedCategoryListAdapter(Context context, int layout, Cursor c, + String[] from, int[] to, int flags) { + super(context, layout, c, from, to, flags); + } + + public static final int VIEW_NORMAL = 0; + public static final int VIEW_SELECTED = 1; + + public static final int VIEW_COUNT = VIEW_SELECTED+1; + + @Override + public int getViewTypeCount() { + return VIEW_COUNT; + } + + @Override + public int getItemViewType(int position) { + Cursor cursor = (Cursor) this.getItem(position); + + if (!m_activity.isSmallScreen() && cursor.getLong(0) == m_selectedCatId) { + return VIEW_SELECTED; + } else { + return VIEW_NORMAL; + } + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View v = convertView; + + Cursor cursor = (Cursor)getItem(position); + + if (v == null) { + int layoutId = R.layout.feeds_row; + + switch (getItemViewType(position)) { + case VIEW_SELECTED: + layoutId = R.layout.feeds_row_selected; + break; + } + + LayoutInflater vi = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + v = vi.inflate(layoutId, null); + + } + + TextView tt = (TextView) v.findViewById(R.id.title); + + if (tt != null) { + tt.setText(cursor.getString(cursor.getColumnIndex("title"))); + } + + TextView tu = (TextView) v.findViewById(R.id.unread_counter); + + if (tu != null) { + tu.setText(String.valueOf(cursor.getInt(cursor.getColumnIndex("unread")))); + tu.setVisibility((cursor.getInt(cursor.getColumnIndex("unread")) > 0) ? View.VISIBLE : View.INVISIBLE); + } + + ImageView icon = (ImageView)v.findViewById(R.id.icon); + + if (icon != null) { + icon.setImageResource(cursor.getInt(cursor.getColumnIndex("unread")) > 0 ? R.drawable.ic_rss : R.drawable.ic_rss_bw); + } + + return v; + } + } + + public void sortCategories() { + try { + refresh(); + } catch (NullPointerException e) { + // activity is gone? + } catch (IllegalStateException e) { + // we're probably closing and DB is gone already + } + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, + String key) { + + sortCategories(); + } + + public int getCatIdAtPosition(int position) { + Cursor c = (Cursor)m_adapter.getItem(position); + + if (c != null) { + int catId = c.getInt(0); + c.close(); + return catId; + } + + return -10000; + } + + public void setSelectedFeedId(int feedId) { + m_selectedCatId = feedId; + refresh(); + } + +} diff --git a/src/org/fox/ttrss/offline/OfflineFeedsActivity.java b/src/org/fox/ttrss/offline/OfflineFeedsActivity.java index 920d2865..506cd493 100644 --- a/src/org/fox/ttrss/offline/OfflineFeedsActivity.java +++ b/src/org/fox/ttrss/offline/OfflineFeedsActivity.java @@ -1,312 +1,314 @@ -package org.fox.ttrss.offline;
-
-import org.fox.ttrss.GlobalState;
-import org.fox.ttrss.R;
-
-import android.animation.LayoutTransition;
-import android.annotation.SuppressLint;
-import android.content.Intent;
-import android.database.sqlite.SQLiteStatement;
-import android.os.Bundle;
-import android.os.Handler;
-import android.preference.PreferenceManager;
-import android.provider.BaseColumns;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentTransaction;
-import android.util.Log;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-
-public class OfflineFeedsActivity extends OfflineActivity implements OfflineHeadlinesEventListener {
- private final String TAG = this.getClass().getSimpleName();
-
- private boolean m_actionbarUpEnabled = false;
-
- @SuppressLint("NewApi")
- @Override
- public void onCreate(Bundle savedInstanceState) {
- m_prefs = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext());
-
- setAppTheme(m_prefs);
-
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.feeds);
-
- setSmallScreen(findViewById(R.id.headlines_fragment) == null);
-
- GlobalState.getInstance().load(savedInstanceState);
-
- if (savedInstanceState != null) {
-
- m_actionbarUpEnabled = savedInstanceState.getBoolean("actionbarUpEnabled");
-
- if (!isCompatMode() && m_actionbarUpEnabled) {
- getActionBar().setDisplayHomeAsUpEnabled(true);
- }
-
- } else {
- Intent intent = getIntent();
-
- if (intent.getIntExtra("feed", -10000) != -10000 || intent.getIntExtra("category", -10000) != -10000 ||
- intent.getIntExtra("article", -10000) != -10000) {
-
- if (!isCompatMode()) {
- getActionBar().setDisplayHomeAsUpEnabled(true);
- m_actionbarUpEnabled = true;
- }
-
- FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
-
- int feedId = intent.getIntExtra("feed", -10000);
- int catId = intent.getIntExtra("category", -10000);
- int articleId = intent.getIntExtra("article", -10000);
- boolean isCat = intent.getBooleanExtra("isCat", false);
-
- if (articleId != -10000) {
- ft.replace(R.id.feeds_fragment, new OfflineArticlePager(articleId, feedId, isCat), FRAG_ARTICLE);
- } else {
- if (feedId != -10000) {
- ft.replace(R.id.feeds_fragment, new OfflineHeadlinesFragment(feedId, isCat), FRAG_HEADLINES);
- }
-
- if (catId != -10000) {
- ft.replace(R.id.feeds_fragment, new OfflineFeedsFragment(catId), FRAG_FEEDS);
- }
- }
-
- ft.commit();
- } else {
- FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
-
- if (m_prefs.getBoolean("enable_cats", false)) {
- ft.replace(R.id.feeds_fragment, new OfflineFeedCategoriesFragment(), FRAG_CATS);
- } else {
- ft.replace(R.id.feeds_fragment, new OfflineFeedsFragment(), FRAG_FEEDS);
- }
-
- ft.commit();
- }
- }
-
- setLoadingStatus(R.string.blank, false);
- findViewById(R.id.loading_container).setVisibility(View.GONE);
-
- initMenu();
-
- /* if (!isSmallScreen()) {
- LinearLayout container = (LinearLayout) findViewById(R.id.fragment_container);
- container.setWeightSum(3f);
- } */
-
- if (!isCompatMode() && !isSmallScreen()) {
- ((ViewGroup)findViewById(R.id.headlines_fragment)).setLayoutTransition(new LayoutTransition());
- ((ViewGroup)findViewById(R.id.feeds_fragment)).setLayoutTransition(new LayoutTransition());
- }
- }
-
- public void openFeedArticles(int feedId, boolean isCat) {
- if (isSmallScreen()) {
- Intent intent = new Intent(OfflineFeedsActivity.this, OfflineFeedsActivity.class);
-
- intent.putExtra("feed", feedId);
- intent.putExtra("isCat", isCat);
- intent.putExtra("article", 0);
- startActivityForResult(intent, 0);
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.show_feeds:
- setUnreadOnly(!getUnreadOnly());
- initMenu();
- refresh();
- return true;
- default:
- Log.d(TAG, "onOptionsItemSelected, unhandled id=" + item.getItemId());
- return super.onOptionsItemSelected(item);
- }
- }
-
- @Override
- public void onSaveInstanceState(Bundle out) {
- super.onSaveInstanceState(out);
-
- out.putBoolean("actionbarUpEnabled", m_actionbarUpEnabled);
-
- GlobalState.getInstance().save(out);
- }
-
- public void initMenu() {
- super.initMenu();
-
- if (m_menu != null) {
- Fragment ff = getSupportFragmentManager().findFragmentByTag(FRAG_FEEDS);
- Fragment cf = getSupportFragmentManager().findFragmentByTag(FRAG_CATS);
- OfflineArticlePager af = (OfflineArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE);
- OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment)getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
-
- m_menu.setGroupVisible(R.id.menu_group_feeds, (ff != null && ff.isAdded()) || (cf != null && cf.isAdded()));
-
- m_menu.setGroupVisible(R.id.menu_group_article, af != null && af.isAdded());
-
- m_menu.setGroupVisible(R.id.menu_group_headlines, hf != null && hf.isAdded() && getSelectedArticleCount() == 0);
- m_menu.setGroupVisible(R.id.menu_group_headlines_selection, hf != null && hf.isAdded() && getSelectedArticleCount() != 0);
-
- MenuItem item = m_menu.findItem(R.id.show_feeds);
-
- if (getUnreadOnly()) {
- item.setTitle(R.string.menu_all_feeds);
- } else {
- item.setTitle(R.string.menu_unread_feeds);
- }
- }
- }
-
- public void onCatSelected(int catId) {
- onCatSelected(catId, m_prefs.getBoolean("browse_cats_like_feeds", false));
- }
-
- public void onCatSelected(int catId, boolean openAsFeed) {
- if (openAsFeed) {
- onFeedSelected(catId, true, true);
- } else {
- if (isSmallScreen()) {
- Intent intent = new Intent(OfflineFeedsActivity.this, OfflineFeedsActivity.class);
- intent.putExtra("category", catId);
-
- startActivityForResult(intent, 0);
- } else {
- FragmentTransaction ft = getSupportFragmentManager()
- .beginTransaction();
-
- OfflineFeedsFragment ff = new OfflineFeedsFragment(catId);
-
- ft.replace(R.id.feeds_fragment, ff, FRAG_FEEDS);
- ft.addToBackStack(null);
-
- ft.commit();
- }
- }
- }
-
- public void onFeedSelected(int feedId) {
- onFeedSelected(feedId, false, true);
- }
-
- public void onFeedSelected(final int feedId, final boolean isCat, boolean open) {
-
- if (open) {
- if (isSmallScreen()) {
-
- Intent intent = new Intent(OfflineFeedsActivity.this, OfflineFeedsActivity.class);
- intent.putExtra("feed", feedId);
- intent.putExtra("isCat", isCat);
-
- startActivityForResult(intent, 0);
-
- } else {
- /* if (!isCompatMode()) {
- LinearLayout container = (LinearLayout) findViewById(R.id.fragment_container);
- float wSum = container.getWeightSum();
- if (wSum <= 2.0f) {
- ObjectAnimator anim = ObjectAnimator.ofFloat(container, "weightSum", wSum, 3.0f);
- anim.setDuration(200);
- anim.start();
- }
- } */
-
- // ^ no idea why the animation hangs half the time :(
-
- LinearLayout container = (LinearLayout) findViewById(R.id.fragment_container);
- container.setWeightSum(3f);
-
- new Handler().postDelayed(new Runnable() {
- @Override
- public void run() {
- FragmentTransaction ft = getSupportFragmentManager()
- .beginTransaction();
-
- OfflineHeadlinesFragment hf = new OfflineHeadlinesFragment(feedId, isCat);
- ft.replace(R.id.headlines_fragment, hf, FRAG_HEADLINES);
-
- ft.commit();
- }
- }, 10);
-
- }
- }
- }
-
- public void catchupFeed(int feedId, boolean isCat) {
- if (isCat) {
- SQLiteStatement stmt = getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = 0 WHERE feed_id IN (SELECT "+
- BaseColumns._ID+" FROM feeds WHERE cat_id = ?)");
- stmt.bindLong(1, feedId);
- stmt.execute();
- stmt.close();
- } else {
- SQLiteStatement stmt = getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = 0 WHERE feed_id = ?");
- stmt.bindLong(1, feedId);
- stmt.execute();
- stmt.close();
- }
-
- refresh();
- }
-
- @Override
- public void onArticleSelected(int articleId, boolean open) {
- SQLiteStatement stmt = getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = 0 " + "WHERE " + BaseColumns._ID
- + " = ?");
-
- stmt.bindLong(1, articleId);
- stmt.execute();
- stmt.close();
-
- initMenu();
-
- if (open) {
- if (isSmallScreen()) {
-
- OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
-
- Intent intent = new Intent(OfflineFeedsActivity.this, OfflineFeedsActivity.class);
- intent.putExtra("feed", hf.getFeedId());
- intent.putExtra("isCat", hf.getFeedIsCat());
- intent.putExtra("article", articleId);
-
- startActivityForResult(intent, 0);
-
- } else {
-
- OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
-
- Intent intent = new Intent(OfflineFeedsActivity.this, OfflineHeadlinesActivity.class);
- intent.putExtra("feed", hf.getFeedId());
- intent.putExtra("isCat", hf.getFeedIsCat());
- intent.putExtra("article", articleId);
-
- startActivityForResult(intent, 0);
- }
- } else {
- refresh();
- }
-
- initMenu();
-
- }
-
- @Override
- public void onArticleSelected(int articleId) {
- onArticleSelected(articleId, true);
- }
-}
+package org.fox.ttrss.offline; + +import org.fox.ttrss.GlobalState; +import org.fox.ttrss.R; + +import com.actionbarsherlock.view.MenuItem; + +import android.animation.LayoutTransition; +import android.annotation.SuppressLint; +import android.content.Intent; +import android.database.sqlite.SQLiteStatement; +import android.os.Bundle; +import android.os.Handler; +import android.preference.PreferenceManager; +import android.provider.BaseColumns; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentTransaction; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; + +public class OfflineFeedsActivity extends OfflineActivity implements OfflineHeadlinesEventListener { + private final String TAG = this.getClass().getSimpleName(); + + private boolean m_actionbarUpEnabled = false; + + @SuppressLint("NewApi") + @Override + public void onCreate(Bundle savedInstanceState) { + m_prefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + setAppTheme(m_prefs); + + super.onCreate(savedInstanceState); + + setContentView(R.layout.feeds); + + setSmallScreen(findViewById(R.id.headlines_fragment) == null); + + GlobalState.getInstance().load(savedInstanceState); + + if (savedInstanceState != null) { + + m_actionbarUpEnabled = savedInstanceState.getBoolean("actionbarUpEnabled"); + + if (!isCompatMode() && m_actionbarUpEnabled) { + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + } + + } else { + Intent intent = getIntent(); + + if (intent.getIntExtra("feed", -10000) != -10000 || intent.getIntExtra("category", -10000) != -10000 || + intent.getIntExtra("article", -10000) != -10000) { + + if (!isCompatMode()) { + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + m_actionbarUpEnabled = true; + } + + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + + int feedId = intent.getIntExtra("feed", -10000); + int catId = intent.getIntExtra("category", -10000); + int articleId = intent.getIntExtra("article", -10000); + boolean isCat = intent.getBooleanExtra("isCat", false); + + if (articleId != -10000) { + ft.replace(R.id.feeds_fragment, new OfflineArticlePager(articleId, feedId, isCat), FRAG_ARTICLE); + } else { + if (feedId != -10000) { + ft.replace(R.id.feeds_fragment, new OfflineHeadlinesFragment(feedId, isCat), FRAG_HEADLINES); + } + + if (catId != -10000) { + ft.replace(R.id.feeds_fragment, new OfflineFeedsFragment(catId), FRAG_FEEDS); + } + } + + ft.commit(); + } else { + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + + if (m_prefs.getBoolean("enable_cats", false)) { + ft.replace(R.id.feeds_fragment, new OfflineFeedCategoriesFragment(), FRAG_CATS); + } else { + ft.replace(R.id.feeds_fragment, new OfflineFeedsFragment(), FRAG_FEEDS); + } + + ft.commit(); + } + } + + setLoadingStatus(R.string.blank, false); + findViewById(R.id.loading_container).setVisibility(View.GONE); + + initMenu(); + + /* if (!isSmallScreen()) { + LinearLayout container = (LinearLayout) findViewById(R.id.fragment_container); + container.setWeightSum(3f); + } */ + + if (!isCompatMode() && !isSmallScreen()) { + ((ViewGroup)findViewById(R.id.headlines_fragment)).setLayoutTransition(new LayoutTransition()); + ((ViewGroup)findViewById(R.id.feeds_fragment)).setLayoutTransition(new LayoutTransition()); + } + } + + public void openFeedArticles(int feedId, boolean isCat) { + if (isSmallScreen()) { + Intent intent = new Intent(OfflineFeedsActivity.this, OfflineFeedsActivity.class); + + intent.putExtra("feed", feedId); + intent.putExtra("isCat", isCat); + intent.putExtra("article", 0); + startActivityForResult(intent, 0); + } + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.show_feeds: + setUnreadOnly(!getUnreadOnly()); + initMenu(); + refresh(); + return true; + default: + Log.d(TAG, "onOptionsItemSelected, unhandled id=" + item.getItemId()); + return super.onOptionsItemSelected(item); + } + } + + @Override + public void onSaveInstanceState(Bundle out) { + super.onSaveInstanceState(out); + + out.putBoolean("actionbarUpEnabled", m_actionbarUpEnabled); + + GlobalState.getInstance().save(out); + } + + public void initMenu() { + super.initMenu(); + + if (m_menu != null) { + Fragment ff = getSupportFragmentManager().findFragmentByTag(FRAG_FEEDS); + Fragment cf = getSupportFragmentManager().findFragmentByTag(FRAG_CATS); + OfflineArticlePager af = (OfflineArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); + OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment)getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + + m_menu.setGroupVisible(R.id.menu_group_feeds, (ff != null && ff.isAdded()) || (cf != null && cf.isAdded())); + + m_menu.setGroupVisible(R.id.menu_group_article, af != null && af.isAdded()); + + m_menu.setGroupVisible(R.id.menu_group_headlines, hf != null && hf.isAdded()); + //m_menu.setGroupVisible(R.id.menu_group_headlines, hf != null && hf.isAdded() && getSelectedArticleCount() == 0); + //m_menu.setGroupVisible(R.id.menu_group_headlines_selection, hf != null && hf.isAdded() && getSelectedArticleCount() != 0); + + MenuItem item = m_menu.findItem(R.id.show_feeds); + + if (getUnreadOnly()) { + item.setTitle(R.string.menu_all_feeds); + } else { + item.setTitle(R.string.menu_unread_feeds); + } + } + } + + public void onCatSelected(int catId) { + onCatSelected(catId, m_prefs.getBoolean("browse_cats_like_feeds", false)); + } + + public void onCatSelected(int catId, boolean openAsFeed) { + if (openAsFeed) { + onFeedSelected(catId, true, true); + } else { + if (isSmallScreen()) { + Intent intent = new Intent(OfflineFeedsActivity.this, OfflineFeedsActivity.class); + intent.putExtra("category", catId); + + startActivityForResult(intent, 0); + } else { + FragmentTransaction ft = getSupportFragmentManager() + .beginTransaction(); + + OfflineFeedsFragment ff = new OfflineFeedsFragment(catId); + + ft.replace(R.id.feeds_fragment, ff, FRAG_FEEDS); + ft.addToBackStack(null); + + ft.commit(); + } + } + } + + public void onFeedSelected(int feedId) { + onFeedSelected(feedId, false, true); + } + + public void onFeedSelected(final int feedId, final boolean isCat, boolean open) { + + if (open) { + if (isSmallScreen()) { + + Intent intent = new Intent(OfflineFeedsActivity.this, OfflineFeedsActivity.class); + intent.putExtra("feed", feedId); + intent.putExtra("isCat", isCat); + + startActivityForResult(intent, 0); + + } else { + /* if (!isCompatMode()) { + LinearLayout container = (LinearLayout) findViewById(R.id.fragment_container); + float wSum = container.getWeightSum(); + if (wSum <= 2.0f) { + ObjectAnimator anim = ObjectAnimator.ofFloat(container, "weightSum", wSum, 3.0f); + anim.setDuration(200); + anim.start(); + } + } */ + + // ^ no idea why the animation hangs half the time :( + + LinearLayout container = (LinearLayout) findViewById(R.id.fragment_container); + container.setWeightSum(3f); + + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + FragmentTransaction ft = getSupportFragmentManager() + .beginTransaction(); + + OfflineHeadlinesFragment hf = new OfflineHeadlinesFragment(feedId, isCat); + ft.replace(R.id.headlines_fragment, hf, FRAG_HEADLINES); + + ft.commit(); + } + }, 10); + + } + } + } + + public void catchupFeed(int feedId, boolean isCat) { + if (isCat) { + SQLiteStatement stmt = getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = 0 WHERE feed_id IN (SELECT "+ + BaseColumns._ID+" FROM feeds WHERE cat_id = ?)"); + stmt.bindLong(1, feedId); + stmt.execute(); + stmt.close(); + } else { + SQLiteStatement stmt = getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = 0 WHERE feed_id = ?"); + stmt.bindLong(1, feedId); + stmt.execute(); + stmt.close(); + } + + refresh(); + } + + @Override + public void onArticleSelected(int articleId, boolean open) { + SQLiteStatement stmt = getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = 0 " + "WHERE " + BaseColumns._ID + + " = ?"); + + stmt.bindLong(1, articleId); + stmt.execute(); + stmt.close(); + + initMenu(); + + if (open) { + if (isSmallScreen()) { + + OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + + Intent intent = new Intent(OfflineFeedsActivity.this, OfflineFeedsActivity.class); + intent.putExtra("feed", hf.getFeedId()); + intent.putExtra("isCat", hf.getFeedIsCat()); + intent.putExtra("article", articleId); + + startActivityForResult(intent, 0); + + } else { + + OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + + Intent intent = new Intent(OfflineFeedsActivity.this, OfflineHeadlinesActivity.class); + intent.putExtra("feed", hf.getFeedId()); + intent.putExtra("isCat", hf.getFeedIsCat()); + intent.putExtra("article", articleId); + + startActivityForResult(intent, 0); + } + } else { + refresh(); + } + + initMenu(); + + } + + @Override + public void onArticleSelected(int articleId) { + onArticleSelected(articleId, true); + } +} diff --git a/src/org/fox/ttrss/offline/OfflineFeedsFragment.java b/src/org/fox/ttrss/offline/OfflineFeedsFragment.java index 7de6bbdd..09cb7b63 100644 --- a/src/org/fox/ttrss/offline/OfflineFeedsFragment.java +++ b/src/org/fox/ttrss/offline/OfflineFeedsFragment.java @@ -1,354 +1,354 @@ -package org.fox.ttrss.offline;
-
-import java.io.File;
-
-import org.fox.ttrss.R;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.Bundle;
-import android.os.Environment;
-import android.preference.PreferenceManager;
-import android.provider.BaseColumns;
-import android.support.v4.app.Fragment;
-import android.support.v4.widget.SimpleCursorAdapter;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.AdapterView.AdapterContextMenuInfo;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.TextView;
-
-public class OfflineFeedsFragment extends Fragment implements OnItemClickListener, OnSharedPreferenceChangeListener {
- private final String TAG = this.getClass().getSimpleName();
- private SharedPreferences m_prefs;
- private FeedListAdapter m_adapter;
- private static final String ICON_PATH = "/data/org.fox.ttrss/icons/";
- private int m_selectedFeedId;
- private int m_catId = -1;
- private boolean m_enableFeedIcons;
- private Cursor m_cursor;
- private OfflineFeedsActivity m_activity;
-
- public OfflineFeedsFragment() {
- //
- }
-
- public OfflineFeedsFragment(int catId) {
- m_catId = catId;
- }
-
- @Override
- public void onResume() {
- super.onResume();
- refresh();
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem item) {
- AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
- .getMenuInfo();
- switch (item.getItemId()) {
- case R.id.browse_articles:
- if (true) {
- int feedId = getFeedIdAtPosition(info.position);
- if (feedId != -10000) {
- m_activity.openFeedArticles(feedId, false);
- }
- }
- return true;
- case R.id.browse_headlines:
- if (true) {
- int feedId = getFeedIdAtPosition(info.position);
- if (feedId != -10000) {
- m_activity.onFeedSelected(feedId);
- }
- }
- return true;
- case R.id.catchup_feed:
- int feedId = getFeedIdAtPosition(info.position);
- if (feedId != -10000) {
- m_activity.catchupFeed(feedId, false);
- }
- return true;
- default:
- Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId());
- return super.onContextItemSelected(item);
- }
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
-
- getActivity().getMenuInflater().inflate(R.menu.feed_menu, menu);
-
- AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
- Cursor cursor = (Cursor)m_adapter.getItem(info.position);
-
- if (cursor != null)
- menu.setHeaderTitle(cursor.getString(cursor.getColumnIndex("title")));
-
- if (!m_activity.isSmallScreen()) {
- menu.findItem(R.id.browse_articles).setVisible(false);
- }
-
- super.onCreateContextMenu(menu, v, menuInfo);
-
- }
-
- public Cursor createCursor() {
- String unreadOnly = m_activity.getUnreadOnly() ? "unread > 0" : "1";
- String order = m_prefs.getBoolean("sort_feeds_by_unread", false) ? "unread DESC, title" : "title";
-
- if (m_catId != -1) {
- return m_activity.getReadableDb().query("feeds_unread",
- null, unreadOnly + " AND cat_id = ?", new String[] { String.valueOf(m_catId) }, null, null, order);
- } else {
- return m_activity.getReadableDb().query("feeds_unread",
- null, unreadOnly, null, null, null, order);
- }
- }
-
- public void refresh() {
- if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close();
-
- m_cursor = createCursor();
-
- if (m_cursor != null) {
- m_adapter.changeCursor(m_cursor);
- m_adapter.notifyDataSetChanged();
- }
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-
- if (savedInstanceState != null) {
- m_selectedFeedId = savedInstanceState.getInt("selectedFeedId");
- m_catId = savedInstanceState.getInt("catId");
- }
-
- View view = inflater.inflate(R.layout.feeds_fragment, container, false);
-
- ListView list = (ListView)view.findViewById(R.id.feeds);
-
- m_cursor = createCursor();
-
- m_adapter = new FeedListAdapter(getActivity(), R.layout.feeds_row, m_cursor,
- new String[] { "title", "unread" }, new int[] { R.id.title, R.id.unread_counter }, 0);
-
- list.setAdapter(m_adapter);
- list.setOnItemClickListener(this);
- list.setEmptyView(view.findViewById(R.id.no_feeds));
- registerForContextMenu(list);
-
- view.findViewById(R.id.loading_container).setVisibility(View.GONE);
-
- m_enableFeedIcons = m_prefs.getBoolean("download_feed_icons", false);
-
- return view;
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close();
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
-
- m_activity = (OfflineFeedsActivity)activity;
-
- m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
- m_prefs.registerOnSharedPreferenceChangeListener(this);
-
- }
-
- @Override
- public void onSaveInstanceState (Bundle out) {
- super.onSaveInstanceState(out);
-
- out.putInt("selectedFeedId", m_selectedFeedId);
- out.putInt("catId", m_catId);
- }
-
- @Override
- public void onItemClick(AdapterView<?> av, View view, int position, long id) {
- ListView list = (ListView)getActivity().findViewById(R.id.feeds);
-
- if (list != null) {
- Cursor cursor = (Cursor) list.getItemAtPosition(position);
-
- if (cursor != null) {
- int feedId = (int) cursor.getLong(0);
- Log.d(TAG, "clicked on feed " + feedId);
-
- if (!m_activity.isSmallScreen() && "ARTICLES".equals(m_prefs.getString("default_view_mode", "HEADLINES"))) {
- m_activity.openFeedArticles(feedId, false);
- } else {
- m_activity.onFeedSelected(feedId);
- }
-
- if (!m_activity.isSmallScreen())
- m_selectedFeedId = feedId;
-
- m_adapter.notifyDataSetChanged();
- }
- }
- }
-
- /* public void setLoadingStatus(int status, boolean showProgress) {
- if (getView() != null) {
- TextView tv = (TextView)getView().findViewById(R.id.loading_message);
-
- if (tv != null) {
- tv.setText(status);
- }
- }
-
- getActivity().setProgressBarIndeterminateVisibility(showProgress);
- } */
-
- private class FeedListAdapter extends SimpleCursorAdapter {
-
-
- public FeedListAdapter(Context context, int layout, Cursor c,
- String[] from, int[] to, int flags) {
- super(context, layout, c, from, to, flags);
- }
-
- public static final int VIEW_NORMAL = 0;
- public static final int VIEW_SELECTED = 1;
-
- public static final int VIEW_COUNT = VIEW_SELECTED+1;
-
- @Override
- public int getViewTypeCount() {
- return VIEW_COUNT;
- }
-
- @Override
- public int getItemViewType(int position) {
- Cursor cursor = (Cursor) this.getItem(position);
-
- if (!m_activity.isSmallScreen() && cursor.getLong(0) == m_selectedFeedId) {
- return VIEW_SELECTED;
- } else {
- return VIEW_NORMAL;
- }
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- View v = convertView;
-
- Cursor cursor = (Cursor)getItem(position);
-
- if (v == null) {
- int layoutId = R.layout.feeds_row;
-
- switch (getItemViewType(position)) {
- case VIEW_SELECTED:
- layoutId = R.layout.feeds_row_selected;
- break;
- }
-
- LayoutInflater vi = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- v = vi.inflate(layoutId, null);
-
- }
-
- TextView tt = (TextView) v.findViewById(R.id.title);
-
- if (tt != null) {
- tt.setText(cursor.getString(cursor.getColumnIndex("title")));
- }
-
- TextView tu = (TextView) v.findViewById(R.id.unread_counter);
-
- if (tu != null) {
- tu.setText(String.valueOf(cursor.getInt(cursor.getColumnIndex("unread"))));
- tu.setVisibility((cursor.getInt(cursor.getColumnIndex("unread")) > 0) ? View.VISIBLE : View.INVISIBLE);
- }
-
- ImageView icon = (ImageView)v.findViewById(R.id.icon);
-
- if (icon != null) {
-
- if (m_enableFeedIcons) {
-
- File storage = Environment.getExternalStorageDirectory();
-
- File iconFile = new File(storage.getAbsolutePath() + ICON_PATH + cursor.getInt(cursor.getColumnIndex(BaseColumns._ID)) + ".ico");
- if (iconFile.exists()) {
- Bitmap bmpOrig = BitmapFactory.decodeFile(iconFile.getAbsolutePath());
- if (bmpOrig != null) {
- icon.setImageBitmap(bmpOrig);
- }
- } else {
- icon.setImageResource(cursor.getInt(cursor.getColumnIndex("unread")) > 0 ? R.drawable.ic_rss : R.drawable.ic_rss_bw);
- }
-
- } else {
- icon.setImageResource(cursor.getInt(cursor.getColumnIndex("unread")) > 0 ? R.drawable.ic_rss : R.drawable.ic_rss_bw);
- }
-
- }
-
- return v;
- }
- }
-
- public void sortFeeds() {
- try {
- refresh();
- } catch (NullPointerException e) {
- // activity is gone?
- } catch (IllegalStateException e) {
- // we're probably closing and DB is gone already
- }
- }
-
- @Override
- public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
- String key) {
-
- sortFeeds();
- m_enableFeedIcons = m_prefs.getBoolean("download_feed_icons", false);
-
- }
-
- public int getFeedIdAtPosition(int position) {
- Cursor c = (Cursor)m_adapter.getItem(position);
-
- if (c != null) {
- int feedId = c.getInt(0);
- c.close();
- return feedId;
- }
-
- return -10000;
- }
-
- public void setSelectedFeedId(int feedId) {
- m_selectedFeedId = feedId;
- refresh();
- }
-
-}
+package org.fox.ttrss.offline; + +import java.io.File; + +import org.fox.ttrss.R; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.os.Bundle; +import android.os.Environment; +import android.preference.PreferenceManager; +import android.provider.BaseColumns; +import android.support.v4.app.Fragment; +import android.support.v4.widget.SimpleCursorAdapter; +import android.util.Log; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.AdapterContextMenuInfo; +import android.widget.AdapterView.OnItemClickListener; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +public class OfflineFeedsFragment extends Fragment implements OnItemClickListener, OnSharedPreferenceChangeListener { + private final String TAG = this.getClass().getSimpleName(); + private SharedPreferences m_prefs; + private FeedListAdapter m_adapter; + private static final String ICON_PATH = "/data/org.fox.ttrss/icons/"; + private int m_selectedFeedId; + private int m_catId = -1; + private boolean m_enableFeedIcons; + private Cursor m_cursor; + private OfflineFeedsActivity m_activity; + + public OfflineFeedsFragment() { + // + } + + public OfflineFeedsFragment(int catId) { + m_catId = catId; + } + + @Override + public void onResume() { + super.onResume(); + refresh(); + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + AdapterContextMenuInfo info = (AdapterContextMenuInfo) item + .getMenuInfo(); + switch (item.getItemId()) { + case R.id.browse_articles: + if (true) { + int feedId = getFeedIdAtPosition(info.position); + if (feedId != -10000) { + m_activity.openFeedArticles(feedId, false); + } + } + return true; + case R.id.browse_headlines: + if (true) { + int feedId = getFeedIdAtPosition(info.position); + if (feedId != -10000) { + m_activity.onFeedSelected(feedId); + } + } + return true; + case R.id.catchup_feed: + int feedId = getFeedIdAtPosition(info.position); + if (feedId != -10000) { + m_activity.catchupFeed(feedId, false); + } + return true; + default: + Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId()); + return super.onContextItemSelected(item); + } + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + + getActivity().getMenuInflater().inflate(R.menu.feed_menu, menu); + + AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo; + Cursor cursor = (Cursor)m_adapter.getItem(info.position); + + if (cursor != null) + menu.setHeaderTitle(cursor.getString(cursor.getColumnIndex("title"))); + + if (!m_activity.isSmallScreen()) { + menu.findItem(R.id.browse_articles).setVisible(false); + } + + super.onCreateContextMenu(menu, v, menuInfo); + + } + + public Cursor createCursor() { + String unreadOnly = m_activity.getUnreadOnly() ? "unread > 0" : "1"; + String order = m_prefs.getBoolean("sort_feeds_by_unread", false) ? "unread DESC, title" : "title"; + + if (m_catId != -1) { + return m_activity.getReadableDb().query("feeds_unread", + null, unreadOnly + " AND cat_id = ?", new String[] { String.valueOf(m_catId) }, null, null, order); + } else { + return m_activity.getReadableDb().query("feeds_unread", + null, unreadOnly, null, null, null, order); + } + } + + public void refresh() { + if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close(); + + m_cursor = createCursor(); + + if (m_cursor != null) { + m_adapter.changeCursor(m_cursor); + m_adapter.notifyDataSetChanged(); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + if (savedInstanceState != null) { + m_selectedFeedId = savedInstanceState.getInt("selectedFeedId"); + m_catId = savedInstanceState.getInt("catId"); + } + + View view = inflater.inflate(R.layout.feeds_fragment, container, false); + + ListView list = (ListView)view.findViewById(R.id.feeds); + + m_cursor = createCursor(); + + m_adapter = new FeedListAdapter(getActivity(), R.layout.feeds_row, m_cursor, + new String[] { "title", "unread" }, new int[] { R.id.title, R.id.unread_counter }, 0); + + list.setAdapter(m_adapter); + list.setOnItemClickListener(this); + list.setEmptyView(view.findViewById(R.id.no_feeds)); + registerForContextMenu(list); + + view.findViewById(R.id.loading_container).setVisibility(View.GONE); + + m_enableFeedIcons = m_prefs.getBoolean("download_feed_icons", false); + + return view; + } + + @Override + public void onDestroy() { + super.onDestroy(); + + if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close(); + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + m_activity = (OfflineFeedsActivity)activity; + + m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()); + m_prefs.registerOnSharedPreferenceChangeListener(this); + + } + + @Override + public void onSaveInstanceState (Bundle out) { + super.onSaveInstanceState(out); + + out.putInt("selectedFeedId", m_selectedFeedId); + out.putInt("catId", m_catId); + } + + @Override + public void onItemClick(AdapterView<?> av, View view, int position, long id) { + ListView list = (ListView)getActivity().findViewById(R.id.feeds); + + if (list != null) { + Cursor cursor = (Cursor) list.getItemAtPosition(position); + + if (cursor != null) { + int feedId = (int) cursor.getLong(0); + Log.d(TAG, "clicked on feed " + feedId); + + if (!m_activity.isSmallScreen() && "ARTICLES".equals(m_prefs.getString("default_view_mode", "HEADLINES"))) { + m_activity.openFeedArticles(feedId, false); + } else { + m_activity.onFeedSelected(feedId); + } + + if (!m_activity.isSmallScreen()) + m_selectedFeedId = feedId; + + m_adapter.notifyDataSetChanged(); + } + } + } + + /* public void setLoadingStatus(int status, boolean showProgress) { + if (getView() != null) { + TextView tv = (TextView)getView().findViewById(R.id.loading_message); + + if (tv != null) { + tv.setText(status); + } + } + + getActivity().setProgressBarIndeterminateVisibility(showProgress); + } */ + + private class FeedListAdapter extends SimpleCursorAdapter { + + + public FeedListAdapter(Context context, int layout, Cursor c, + String[] from, int[] to, int flags) { + super(context, layout, c, from, to, flags); + } + + public static final int VIEW_NORMAL = 0; + public static final int VIEW_SELECTED = 1; + + public static final int VIEW_COUNT = VIEW_SELECTED+1; + + @Override + public int getViewTypeCount() { + return VIEW_COUNT; + } + + @Override + public int getItemViewType(int position) { + Cursor cursor = (Cursor) this.getItem(position); + + if (!m_activity.isSmallScreen() && cursor.getLong(0) == m_selectedFeedId) { + return VIEW_SELECTED; + } else { + return VIEW_NORMAL; + } + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View v = convertView; + + Cursor cursor = (Cursor)getItem(position); + + if (v == null) { + int layoutId = R.layout.feeds_row; + + switch (getItemViewType(position)) { + case VIEW_SELECTED: + layoutId = R.layout.feeds_row_selected; + break; + } + + LayoutInflater vi = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + v = vi.inflate(layoutId, null); + + } + + TextView tt = (TextView) v.findViewById(R.id.title); + + if (tt != null) { + tt.setText(cursor.getString(cursor.getColumnIndex("title"))); + } + + TextView tu = (TextView) v.findViewById(R.id.unread_counter); + + if (tu != null) { + tu.setText(String.valueOf(cursor.getInt(cursor.getColumnIndex("unread")))); + tu.setVisibility((cursor.getInt(cursor.getColumnIndex("unread")) > 0) ? View.VISIBLE : View.INVISIBLE); + } + + ImageView icon = (ImageView)v.findViewById(R.id.icon); + + if (icon != null) { + + if (m_enableFeedIcons) { + + File storage = Environment.getExternalStorageDirectory(); + + File iconFile = new File(storage.getAbsolutePath() + ICON_PATH + cursor.getInt(cursor.getColumnIndex(BaseColumns._ID)) + ".ico"); + if (iconFile.exists()) { + Bitmap bmpOrig = BitmapFactory.decodeFile(iconFile.getAbsolutePath()); + if (bmpOrig != null) { + icon.setImageBitmap(bmpOrig); + } + } else { + icon.setImageResource(cursor.getInt(cursor.getColumnIndex("unread")) > 0 ? R.drawable.ic_rss : R.drawable.ic_rss_bw); + } + + } else { + icon.setImageResource(cursor.getInt(cursor.getColumnIndex("unread")) > 0 ? R.drawable.ic_rss : R.drawable.ic_rss_bw); + } + + } + + return v; + } + } + + public void sortFeeds() { + try { + refresh(); + } catch (NullPointerException e) { + // activity is gone? + } catch (IllegalStateException e) { + // we're probably closing and DB is gone already + } + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, + String key) { + + sortFeeds(); + m_enableFeedIcons = m_prefs.getBoolean("download_feed_icons", false); + + } + + public int getFeedIdAtPosition(int position) { + Cursor c = (Cursor)m_adapter.getItem(position); + + if (c != null) { + int feedId = c.getInt(0); + c.close(); + return feedId; + } + + return -10000; + } + + public void setSelectedFeedId(int feedId) { + m_selectedFeedId = feedId; + refresh(); + } + +} diff --git a/src/org/fox/ttrss/offline/OfflineHeadlinesActivity.java b/src/org/fox/ttrss/offline/OfflineHeadlinesActivity.java index 6faa292b..867a2e5d 100644 --- a/src/org/fox/ttrss/offline/OfflineHeadlinesActivity.java +++ b/src/org/fox/ttrss/offline/OfflineHeadlinesActivity.java @@ -1,142 +1,144 @@ -package org.fox.ttrss.offline;
-
-import org.fox.ttrss.GlobalState;
-import org.fox.ttrss.R;
-
-import android.annotation.SuppressLint;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteStatement;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.provider.BaseColumns;
-import android.support.v4.app.Fragment;
-import android.support.v4.app.FragmentTransaction;
-import android.view.View;
-
-public class OfflineHeadlinesActivity extends OfflineActivity implements OfflineHeadlinesEventListener {
- @SuppressWarnings("unused")
- private final String TAG = this.getClass().getSimpleName();
-
- protected SharedPreferences m_prefs;
-
- @SuppressLint("NewApi")
- @Override
- public void onCreate(Bundle savedInstanceState) {
- m_prefs = PreferenceManager
- .getDefaultSharedPreferences(getApplicationContext());
-
- setAppTheme(m_prefs);
-
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.headlines);
-
- if (!isCompatMode()) {
- getActionBar().setDisplayHomeAsUpEnabled(true);
- }
-
- setSmallScreen(findViewById(R.id.headlines_fragment) == null);
-
- if (isPortrait()) {
- findViewById(R.id.headlines_fragment).setVisibility(View.GONE);
- }
-
- if (savedInstanceState == null) {
- Intent i = getIntent();
-
- if (i.getExtras() != null) {
- int feedId = i.getIntExtra("feed", 0);
- boolean isCat = i.getBooleanExtra("isCat", false);
- int articleId = i.getIntExtra("article", 0);
- String searchQuery = i.getStringExtra("searchQuery");
-
- OfflineHeadlinesFragment hf = new OfflineHeadlinesFragment(feedId, isCat);
- OfflineArticlePager af = new OfflineArticlePager(articleId, feedId, isCat);
-
- hf.setActiveArticleId(articleId);
-
- hf.setSearchQuery(searchQuery);
- af.setSearchQuery(searchQuery);
-
- FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
-
- ft.replace(R.id.headlines_fragment, hf, FRAG_HEADLINES);
- ft.replace(R.id.article_fragment, af, FRAG_ARTICLE);
-
- ft.commit();
-
- Cursor c;
-
- if (isCat) {
- c = getCatById(feedId);
- } else {
- c = getFeedById(feedId);
- }
-
- if (c != null) {
- setTitle(c.getString(c.getColumnIndex("title")));
- c.close();
- }
-
- }
- }
-
- setLoadingStatus(R.string.blank, false);
- findViewById(R.id.loading_container).setVisibility(View.GONE);
-
- initMenu();
- }
-
- @Override
- public void onArticleSelected(int articleId, boolean open) {
- SQLiteStatement stmt = getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = 0 " + "WHERE " + BaseColumns._ID
- + " = ?");
-
- stmt.bindLong(1, articleId);
- stmt.execute();
- stmt.close();
-
- if (open) {
- OfflineArticlePager af = (OfflineArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE);
-
- af.setArticleId(articleId);
- } else {
- OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
-
- hf.setActiveArticleId(articleId);
- }
-
- GlobalState.getInstance().m_selectedArticleId = articleId;
-
- initMenu();
- refresh();
- }
-
- @Override
- protected void initMenu() {
- super.initMenu();
-
- if (m_menu != null) {
- m_menu.setGroupVisible(R.id.menu_group_feeds, false);
-
- OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment)getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES);
-
- m_menu.setGroupVisible(R.id.menu_group_headlines, hf != null && hf.getSelectedArticleCount() == 0);
- m_menu.setGroupVisible(R.id.menu_group_headlines_selection, hf != null && hf.getSelectedArticleCount() != 0);
-
- Fragment af = getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE);
-
- m_menu.setGroupVisible(R.id.menu_group_article, af != null);
-
- m_menu.findItem(R.id.search).setVisible(false);
- }
- }
-
- @Override
- public void onArticleSelected(int articleId) {
- onArticleSelected(articleId, true);
- }
-}
+package org.fox.ttrss.offline; + +import org.fox.ttrss.GlobalState; +import org.fox.ttrss.R; + +import android.annotation.SuppressLint; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.database.sqlite.SQLiteStatement; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.provider.BaseColumns; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentTransaction; +import android.view.View; + +public class OfflineHeadlinesActivity extends OfflineActivity implements OfflineHeadlinesEventListener { + @SuppressWarnings("unused") + private final String TAG = this.getClass().getSimpleName(); + + protected SharedPreferences m_prefs; + + @SuppressLint("NewApi") + @Override + public void onCreate(Bundle savedInstanceState) { + m_prefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + setAppTheme(m_prefs); + + super.onCreate(savedInstanceState); + + setContentView(R.layout.headlines); + + if (!isCompatMode()) { + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + } + + setSmallScreen(findViewById(R.id.headlines_fragment) == null); + + if (isPortrait()) { + findViewById(R.id.headlines_fragment).setVisibility(View.GONE); + } + + if (savedInstanceState == null) { + Intent i = getIntent(); + + if (i.getExtras() != null) { + int feedId = i.getIntExtra("feed", 0); + boolean isCat = i.getBooleanExtra("isCat", false); + int articleId = i.getIntExtra("article", 0); + String searchQuery = i.getStringExtra("searchQuery"); + + OfflineHeadlinesFragment hf = new OfflineHeadlinesFragment(feedId, isCat); + OfflineArticlePager af = new OfflineArticlePager(articleId, feedId, isCat); + + hf.setActiveArticleId(articleId); + + hf.setSearchQuery(searchQuery); + af.setSearchQuery(searchQuery); + + FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); + + ft.replace(R.id.headlines_fragment, hf, FRAG_HEADLINES); + ft.replace(R.id.article_fragment, af, FRAG_ARTICLE); + + ft.commit(); + + Cursor c; + + if (isCat) { + c = getCatById(feedId); + } else { + c = getFeedById(feedId); + } + + if (c != null) { + setTitle(c.getString(c.getColumnIndex("title"))); + c.close(); + } + + } + } + + setLoadingStatus(R.string.blank, false); + findViewById(R.id.loading_container).setVisibility(View.GONE); + + initMenu(); + } + + @Override + public void onArticleSelected(int articleId, boolean open) { + SQLiteStatement stmt = getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = 0 " + "WHERE " + BaseColumns._ID + + " = ?"); + + stmt.bindLong(1, articleId); + stmt.execute(); + stmt.close(); + + if (open) { + OfflineArticlePager af = (OfflineArticlePager) getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); + + af.setArticleId(articleId); + } else { + OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + + hf.setActiveArticleId(articleId); + } + + GlobalState.getInstance().m_selectedArticleId = articleId; + + initMenu(); + refresh(); + } + + @Override + protected void initMenu() { + super.initMenu(); + + if (m_menu != null) { + m_menu.setGroupVisible(R.id.menu_group_feeds, false); + + OfflineHeadlinesFragment hf = (OfflineHeadlinesFragment)getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); + + m_menu.setGroupVisible(R.id.menu_group_headlines, hf != null && hf.isAdded()); + + //m_menu.setGroupVisible(R.id.menu_group_headlines, hf != null && hf.getSelectedArticleCount() == 0); + //m_menu.setGroupVisible(R.id.menu_group_headlines_selection, hf != null && hf.getSelectedArticleCount() != 0); + + Fragment af = getSupportFragmentManager().findFragmentByTag(FRAG_ARTICLE); + + m_menu.setGroupVisible(R.id.menu_group_article, af != null); + + m_menu.findItem(R.id.search).setVisible(false); + } + } + + @Override + public void onArticleSelected(int articleId) { + onArticleSelected(articleId, true); + } +} diff --git a/src/org/fox/ttrss/offline/OfflineHeadlinesEventListener.java b/src/org/fox/ttrss/offline/OfflineHeadlinesEventListener.java index cdff5913..0818a66b 100644 --- a/src/org/fox/ttrss/offline/OfflineHeadlinesEventListener.java +++ b/src/org/fox/ttrss/offline/OfflineHeadlinesEventListener.java @@ -1,7 +1,7 @@ -package org.fox.ttrss.offline;
-
-
-public interface OfflineHeadlinesEventListener {
- void onArticleSelected(int articleId, boolean open);
- void onArticleSelected(int articleId);
-}
+package org.fox.ttrss.offline; + + +public interface OfflineHeadlinesEventListener { + void onArticleSelected(int articleId, boolean open); + void onArticleSelected(int articleId); +} diff --git a/src/org/fox/ttrss/offline/OfflineHeadlinesFragment.java b/src/org/fox/ttrss/offline/OfflineHeadlinesFragment.java index 96de96fe..be724eb1 100644 --- a/src/org/fox/ttrss/offline/OfflineHeadlinesFragment.java +++ b/src/org/fox/ttrss/offline/OfflineHeadlinesFragment.java @@ -1,649 +1,649 @@ -package org.fox.ttrss.offline;
-
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.TimeZone;
-
-import org.fox.ttrss.GlobalState;
-import org.fox.ttrss.R;
-import org.jsoup.Jsoup;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteStatement;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.provider.BaseColumns;
-import android.support.v4.app.Fragment;
-import android.support.v4.widget.SimpleCursorAdapter;
-import android.text.Html;
-import android.text.Html.ImageGetter;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.ContextMenu.ContextMenuInfo;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-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.CheckBox;
-import android.widget.ImageView;
-import android.widget.ListView;
-import android.widget.TextView;
-
-public class OfflineHeadlinesFragment extends Fragment implements OnItemClickListener {
- public static enum ArticlesSelection { ALL, NONE, UNREAD };
-
- private final String TAG = this.getClass().getSimpleName();
-
- private int m_feedId;
- private boolean m_feedIsCat = false;
- private int m_activeArticleId;
- private String m_searchQuery = "";
-
- private SharedPreferences m_prefs;
-
- private Cursor m_cursor;
- private ArticleListAdapter m_adapter;
-
- private OfflineHeadlinesEventListener m_listener;
- private OfflineActivity m_activity;
-
- private ImageGetter m_dummyGetter = new ImageGetter() {
-
- @SuppressWarnings("deprecation")
- @Override
- public Drawable getDrawable(String source) {
- return new BitmapDrawable();
- }
-
- };
-
- public OfflineHeadlinesFragment(int feedId, boolean isCat) {
- m_feedId = feedId;
- m_feedIsCat = isCat;
- }
-
- public OfflineHeadlinesFragment() {
- //
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close();
- }
-
- public int getSelectedArticleCount() {
- Cursor c = m_activity.getReadableDb().query("articles",
- new String[] { "COUNT(*)" }, "selected = 1", null, null, null, null);
- c.moveToFirst();
- int selected = c.getInt(0);
- c.close();
-
- return selected;
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem item) {
- AdapterContextMenuInfo info = (AdapterContextMenuInfo) item
- .getMenuInfo();
-
- switch (item.getItemId()) {
- case R.id.article_link_copy:
- if (true) {
- int articleId = getArticleIdAtPosition(info.position);
-
- Cursor article = m_activity.getArticleById(articleId);
-
- if (article != null) {
- m_activity.copyToClipboard(article.getString(article.getColumnIndex("link")));
- article.close();
- }
- }
- return true;
- case R.id.selection_toggle_marked:
- if (getSelectedArticleCount() > 0) {
- SQLiteStatement stmt = m_activity.getWritableDb()
- .compileStatement(
- "UPDATE articles SET modified = 1, marked = NOT marked WHERE selected = 1");
- stmt.execute();
- stmt.close();
- } else {
- int articleId = getArticleIdAtPosition(info.position);
-
- SQLiteStatement stmt = m_activity.getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, marked = NOT marked WHERE "
- + BaseColumns._ID + " = ?");
- stmt.bindLong(1, articleId);
- stmt.execute();
- stmt.close();
- }
- refresh();
- return true;
- case R.id.selection_toggle_published:
- if (getSelectedArticleCount() > 0) {
- SQLiteStatement stmt = m_activity.getWritableDb()
- .compileStatement(
- "UPDATE articles SET modified = 1, published = NOT published WHERE selected = 1");
- stmt.execute();
- stmt.close();
- } else {
- int articleId = getArticleIdAtPosition(info.position);
-
- SQLiteStatement stmt = m_activity.getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, published = NOT published WHERE "
- + BaseColumns._ID + " = ?");
- stmt.bindLong(1, articleId);
- stmt.execute();
- stmt.close();
- }
- refresh();
- return true;
- case R.id.selection_toggle_unread:
- if (getSelectedArticleCount() > 0) {
- SQLiteStatement stmt = m_activity.getWritableDb()
- .compileStatement(
- "UPDATE articles SET modified = 1, unread = NOT unread WHERE selected = 1");
- stmt.execute();
- stmt.close();
- } else {
- int articleId = getArticleIdAtPosition(info.position);
-
- SQLiteStatement stmt = m_activity.getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = NOT unread WHERE "
- + BaseColumns._ID + " = ?");
- stmt.bindLong(1, articleId);
- stmt.execute();
- stmt.close();
- }
- refresh();
- return true;
- case R.id.share_article:
- if (true) {
- int articleId = getArticleIdAtPosition(info.position);
- m_activity.shareArticle(articleId);
- }
- return true;
- case R.id.catchup_above:
- if (true) {
- int articleId = getArticleIdAtPosition(info.position);
-
- SQLiteStatement stmt = null;
-
- String updatedOperator = (m_prefs.getBoolean("offline_oldest_first", false)) ? "<" : ">";
-
- if (m_feedIsCat) {
- stmt = m_activity.getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = 0 WHERE " +
- "updated "+updatedOperator+" (SELECT updated FROM articles WHERE " + BaseColumns._ID + " = ?) " +
- "AND unread = 1 AND feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)");
- } else {
- stmt = m_activity.getWritableDb().compileStatement(
- "UPDATE articles SET modified = 1, unread = 0 WHERE " +
- "updated "+updatedOperator+" (SELECT updated FROM articles WHERE " + BaseColumns._ID + " = ?) " +
- "AND unread = 1 AND feed_id = ?");
- }
-
- stmt.bindLong(1, articleId);
- stmt.bindLong(2, m_feedId);
- stmt.execute();
- stmt.close();
- }
- refresh();
- return true;
- default:
- Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId());
- return super.onContextItemSelected(item);
- }
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View v,
- ContextMenuInfo menuInfo) {
-
- getActivity().getMenuInflater().inflate(R.menu.headlines_context_menu, menu);
-
- if (getSelectedArticleCount() > 0) {
- menu.setHeaderTitle(R.string.headline_context_multiple);
- menu.setGroupVisible(R.id.menu_group_single_article, false);
- } else {
- AdapterContextMenuInfo info = (AdapterContextMenuInfo)menuInfo;
- Cursor c = getArticleAtPosition(info.position);
- menu.setHeaderTitle(c.getString(c.getColumnIndex("title")));
- //c.close();
- menu.setGroupVisible(R.id.menu_group_single_article, true);
-
- menu.findItem(R.id.set_labels).setVisible(false);
- menu.findItem(R.id.article_set_note).setVisible(false);
- }
-
- super.onCreateContextMenu(menu, v, menuInfo);
-
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- if (GlobalState.getInstance().m_selectedArticleId != 0) {
- m_activeArticleId = GlobalState.getInstance().m_selectedArticleId;
- GlobalState.getInstance().m_selectedArticleId = 0;
- }
-
- if (m_activeArticleId != 0) {
- setActiveArticleId(m_activeArticleId);
- }
-
- refresh();
- }
-
- public void refresh() {
- if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close();
-
- m_cursor = createCursor();
-
- if (m_cursor != null) {
- m_adapter.changeCursor(m_cursor);
- m_adapter.notifyDataSetChanged();
- }
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
-
- if (savedInstanceState != null) {
- m_feedId = savedInstanceState.getInt("feedId");
- m_activeArticleId = savedInstanceState.getInt("activeArticleId");
- //m_selectedArticles = savedInstanceState.getParcelableArrayList("selectedArticles");
- m_searchQuery = (String) savedInstanceState.getCharSequence("searchQuery");
- m_feedIsCat = savedInstanceState.getBoolean("feedIsCat");
- } else {
- m_activity.getWritableDb().execSQL("UPDATE articles SET selected = 0 ");
- }
-
- View view = inflater.inflate(R.layout.headlines_fragment, container, false);
-
- m_cursor = createCursor();
-
- ListView list = (ListView)view.findViewById(R.id.headlines);
- m_adapter = new ArticleListAdapter(getActivity(), R.layout.headlines_row, m_cursor,
- new String[] { "title" }, new int[] { R.id.title }, 0);
-
- list.setAdapter(m_adapter);
- list.setOnItemClickListener(this);
- list.setEmptyView(view.findViewById(R.id.no_headlines));
- registerForContextMenu(list);
-
- if (m_activity.isSmallScreen() || m_activity.isPortrait())
- view.findViewById(R.id.headlines_fragment).setPadding(0, 0, 0, 0);
-
- getActivity().setProgressBarIndeterminateVisibility(false);
-
- return view;
- }
-
- public Cursor createCursor() {
- String feedClause = null;
-
- if (m_feedIsCat) {
- feedClause = "feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)";
- } else {
- feedClause = "feed_id = ?";
- }
-
- String orderBy = (m_prefs.getBoolean("offline_oldest_first", false)) ? "updated" : "updated DESC";
-
- if (m_searchQuery == null || m_searchQuery.equals("")) {
- return m_activity.getReadableDb().query("articles LEFT JOIN feeds ON (feed_id = feeds."+BaseColumns._ID+")",
- new String[] { "articles.*", "feeds.title AS feed_title" }, feedClause,
- new String[] { String.valueOf(m_feedId) }, null, null, orderBy);
- } else {
- return m_activity.getReadableDb().query("articles LEFT JOIN feeds ON (feed_id = feeds."+BaseColumns._ID+")",
- new String[] { "articles.*", "feeds.title AS feed_title" },
- feedClause + " AND (articles.title LIKE '%' || ? || '%' OR content LIKE '%' || ? || '%')",
- new String[] { String.valueOf(m_feedId), m_searchQuery, m_searchQuery }, null, null, orderBy);
- }
- }
-
- @Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- m_listener = (OfflineHeadlinesEventListener) activity;
- m_activity = (OfflineActivity) activity;
-
- m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext());
- }
-
- @Override
- public void onItemClick(AdapterView<?> av, View view, int position, long id) {
- ListView list = (ListView)av;
-
- Log.d(TAG, "onItemClick=" + position);
-
- if (list != null) {
- /* Cursor cursor = (Cursor)list.getItemAtPosition(position);
-
- int articleId = cursor.getInt(0); */
-
- int articleId = getArticleIdAtPosition(position);
-
- if (getActivity().findViewById(R.id.article_fragment) != null) {
- m_activeArticleId = articleId;
- }
-
- m_listener.onArticleSelected(articleId);
-
- refresh();
- }
- }
-
- @Override
- public void onSaveInstanceState (Bundle out) {
- super.onSaveInstanceState(out);
-
- out.putInt("feedId", m_feedId);
- out.putInt("activeArticleId", m_activeArticleId);
- //out.putParcelableArrayList("selectedArticles", m_selectedArticles);
- out.putCharSequence("searchQuery", m_searchQuery);
- out.putBoolean("feedIsCat", m_feedIsCat);
- }
-
- /* public void setLoadingStatus(int status, boolean showProgress) {
- if (getView() != null) {
- TextView tv = (TextView)getView().findViewById(R.id.loading_message);
-
- if (tv != null) {
- tv.setText(status);
- }
- }
-
- getActivity().setProgressBarIndeterminateVisibility(showProgress);
- } */
-
- private class ArticleListAdapter extends SimpleCursorAdapter {
- public ArticleListAdapter(Context context, int layout, Cursor c,
- String[] from, int[] to, int flags) {
- super(context, layout, c, from, to, flags);
- // TODO Auto-generated constructor stub
- }
-
- public static final int VIEW_NORMAL = 0;
- public static final int VIEW_UNREAD = 1;
- public static final int VIEW_SELECTED = 2;
- public static final int VIEW_SELECTED_UNREAD = 3;
- public static final int VIEW_LOADMORE = 4;
-
- public static final int VIEW_COUNT = VIEW_LOADMORE+1;
-
-
- public int getViewTypeCount() {
- return VIEW_COUNT;
- }
-
- @Override
- public int getItemViewType(int position) {
- Cursor c = (Cursor) getItem(position);
-
- //Log.d(TAG, "@gIVT " + position + " " + c.getInt(0) + " vs " + m_activeArticleId);
-
- if (c.getInt(0) == m_activeArticleId && c.getInt(c.getColumnIndex("unread")) == 1) {
- return VIEW_SELECTED_UNREAD;
- } else if (c.getInt(0) == m_activeArticleId) {
- return VIEW_SELECTED;
- } else if (c.getInt(c.getColumnIndex("unread")) == 1) {
- return VIEW_UNREAD;
- } else {
- return VIEW_NORMAL;
- }
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
-
- View v = convertView;
-
- Cursor article = (Cursor)getItem(position);
- final int articleId = article.getInt(0);
-
- if (v == null) {
- int layoutId = R.layout.headlines_row;
-
- switch (getItemViewType(position)) {
- case VIEW_LOADMORE:
- layoutId = R.layout.headlines_row_loadmore;
- break;
- case VIEW_UNREAD:
- layoutId = R.layout.headlines_row_unread;
- break;
- case VIEW_SELECTED_UNREAD:
- layoutId = R.layout.headlines_row_selected_unread;
- break;
- case VIEW_SELECTED:
- layoutId = R.layout.headlines_row_selected;
- break;
- }
-
- LayoutInflater vi = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- v = vi.inflate(layoutId, null);
-
- // http://code.google.com/p/android/issues/detail?id=3414
- ((ViewGroup)v).setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
- }
-
- TextView tt = (TextView)v.findViewById(R.id.title);
-
- if (tt != null) {
- tt.setText(Html.fromHtml(article.getString(article.getColumnIndex("title"))));
- }
-
- TextView ft = (TextView)v.findViewById(R.id.feed_title);
-
- int feedTitleIndex = article.getColumnIndex("feed_title");
-
- if (ft != null && feedTitleIndex != -1 && m_feedIsCat) {
- String feedTitle = article.getString(feedTitleIndex);
-
- if (feedTitle.length() > 20)
- feedTitle = feedTitle.substring(0, 20) + "...";
-
- if (feedTitle.length() > 0) {
- ft.setText(feedTitle);
- } else {
- ft.setVisibility(View.GONE);
- }
- } else if (ft != null) {
- ft.setVisibility(View.GONE);
- }
-
- ImageView marked = (ImageView)v.findViewById(R.id.marked);
-
- if (marked != null) {
- marked.setImageResource(article.getInt(article.getColumnIndex("marked")) == 1 ? android.R.drawable.star_on : android.R.drawable.star_off);
-
- marked.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- SQLiteStatement stmtUpdate = m_activity.getWritableDb().compileStatement("UPDATE articles SET modified = 1, marked = NOT marked " +
- "WHERE " + BaseColumns._ID + " = ?");
-
- stmtUpdate.bindLong(1, articleId);
- stmtUpdate.execute();
- stmtUpdate.close();
-
- refresh();
- }
- });
- }
-
- ImageView published = (ImageView)v.findViewById(R.id.published);
-
- if (published != null) {
- published.setImageResource(article.getInt(article.getColumnIndex("published")) == 1 ? R.drawable.ic_rss : R.drawable.ic_rss_bw);
-
- published.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View v) {
- SQLiteStatement stmtUpdate = m_activity.getWritableDb().compileStatement("UPDATE articles SET modified = 1, published = NOT published " +
- "WHERE " + BaseColumns._ID + " = ?");
-
- stmtUpdate.bindLong(1, articleId);
- stmtUpdate.execute();
- stmtUpdate.close();
-
- refresh();
- }
- });
- }
-
- TextView te = (TextView)v.findViewById(R.id.excerpt);
-
- if (te != null) {
- String excerpt = Jsoup.parse(article.getString(article.getColumnIndex("content"))).text();
-
- if (excerpt.length() > 100)
- excerpt = excerpt.substring(0, 100) + "...";
-
- te.setText(excerpt);
- }
-
- /* ImageView separator = (ImageView)v.findViewById(R.id.headlines_separator);
-
- if (separator != null && m_offlineServices.isSmallScreen()) {
- separator.setVisibility(View.GONE);
- } */
-
- TextView dv = (TextView) v.findViewById(R.id.date);
-
- if (dv != null) {
- Date d = new Date((long)article.getInt(article.getColumnIndex("updated")) * 1000);
- DateFormat df = new SimpleDateFormat("MMM dd, HH:mm");
- df.setTimeZone(TimeZone.getDefault());
- dv.setText(df.format(d));
- }
-
- CheckBox cb = (CheckBox) v.findViewById(R.id.selected);
-
- if (cb != null) {
- cb.setChecked(article.getInt(article.getColumnIndex("selected")) == 1);
- cb.setOnClickListener(new OnClickListener() {
-
- @Override
- public void onClick(View view) {
- CheckBox cb = (CheckBox)view;
-
- SQLiteStatement stmtUpdate = m_activity.getWritableDb().compileStatement("UPDATE articles SET selected = ? " +
- "WHERE " + BaseColumns._ID + " = ?");
-
- stmtUpdate.bindLong(1, cb.isChecked() ? 1 : 0);
- stmtUpdate.bindLong(2, articleId);
- stmtUpdate.execute();
- stmtUpdate.close();
-
- refresh();
-
- m_activity.initMenu();
-
- }
- });
- }
-
- /* ImageButton ib = (ImageButton) v.findViewById(R.id.article_menu_button);
-
- if (ib != null) {
- ib.setVisibility(android.os.Build.VERSION.SDK_INT >= 10 ? View.VISIBLE : View.GONE);
- ib.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- getActivity().openContextMenu(v);
- }
- });
- } */
-
- return v;
- }
- }
-
- public void notifyUpdated() {
- m_adapter.notifyDataSetChanged();
- }
-
- public void setActiveArticleId(int articleId) {
- m_activeArticleId = articleId;
- try {
- m_adapter.notifyDataSetChanged();
-
- ListView list = (ListView)getView().findViewById(R.id.headlines);
-
- Log.d(TAG, articleId + " position " + getArticleIdPosition(articleId));
-
- if (list != null) {
- list.setSelection(getArticleIdPosition(articleId));
- }
- } catch (NullPointerException e) {
- // invoked before view is created, nvm
- }
- }
-
- public Cursor getArticleAtPosition(int position) {
- return (Cursor) m_adapter.getItem(position);
- }
-
- public int getArticleIdAtPosition(int position) {
- /*Cursor c = getArticleAtPosition(position);
-
- if (c != null) {
- int id = c.getInt(0);
- return id;
- } */
-
- return (int) m_adapter.getItemId(position);
- }
-
- public int getActiveArticleId() {
- return m_activeArticleId;
- }
-
- public int getArticleIdPosition(int articleId) {
- for (int i = 0; i < m_adapter.getCount(); i++) {
- if (articleId == m_adapter.getItemId(i))
- return i;
- }
-
- return -1;
- }
-
- public int getArticleCount() {
- return m_adapter.getCount();
- }
-
- public void setSearchQuery(String query) {
- if (!m_searchQuery.equals(query)) {
- m_searchQuery = query;
- }
- }
-
- public int getFeedId() {
- return m_feedId;
- }
-
- public boolean getFeedIsCat() {
- return m_feedIsCat;
- }
-
- public String getSearchQuery() {
- return m_searchQuery;
- }
-
-}
+package org.fox.ttrss.offline; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +import org.fox.ttrss.GlobalState; +import org.fox.ttrss.R; +import org.jsoup.Jsoup; + +import android.app.Activity; +import android.content.Context; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.database.sqlite.SQLiteStatement; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.provider.BaseColumns; +import android.support.v4.app.Fragment; +import android.support.v4.widget.SimpleCursorAdapter; +import android.text.Html; +import android.text.Html.ImageGetter; +import android.util.Log; +import android.view.ContextMenu; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +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.CheckBox; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +public class OfflineHeadlinesFragment extends Fragment implements OnItemClickListener { + public static enum ArticlesSelection { ALL, NONE, UNREAD }; + + private final String TAG = this.getClass().getSimpleName(); + + private int m_feedId; + private boolean m_feedIsCat = false; + private int m_activeArticleId; + private String m_searchQuery = ""; + + private SharedPreferences m_prefs; + + private Cursor m_cursor; + private ArticleListAdapter m_adapter; + + private OfflineHeadlinesEventListener m_listener; + private OfflineActivity m_activity; + + private ImageGetter m_dummyGetter = new ImageGetter() { + + @SuppressWarnings("deprecation") + @Override + public Drawable getDrawable(String source) { + return new BitmapDrawable(); + } + + }; + + public OfflineHeadlinesFragment(int feedId, boolean isCat) { + m_feedId = feedId; + m_feedIsCat = isCat; + } + + public OfflineHeadlinesFragment() { + // + } + + @Override + public void onDestroy() { + super.onDestroy(); + + if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close(); + } + + public int getSelectedArticleCount() { + Cursor c = m_activity.getReadableDb().query("articles", + new String[] { "COUNT(*)" }, "selected = 1", null, null, null, null); + c.moveToFirst(); + int selected = c.getInt(0); + c.close(); + + return selected; + } + + @Override + public boolean onContextItemSelected(MenuItem item) { + AdapterContextMenuInfo info = (AdapterContextMenuInfo) item + .getMenuInfo(); + + switch (item.getItemId()) { + case R.id.article_link_copy: + if (true) { + int articleId = getArticleIdAtPosition(info.position); + + Cursor article = m_activity.getArticleById(articleId); + + if (article != null) { + m_activity.copyToClipboard(article.getString(article.getColumnIndex("link"))); + article.close(); + } + } + return true; + case R.id.selection_toggle_marked: + if (getSelectedArticleCount() > 0) { + SQLiteStatement stmt = m_activity.getWritableDb() + .compileStatement( + "UPDATE articles SET modified = 1, marked = NOT marked WHERE selected = 1"); + stmt.execute(); + stmt.close(); + } else { + int articleId = getArticleIdAtPosition(info.position); + + SQLiteStatement stmt = m_activity.getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, marked = NOT marked WHERE " + + BaseColumns._ID + " = ?"); + stmt.bindLong(1, articleId); + stmt.execute(); + stmt.close(); + } + refresh(); + return true; + case R.id.selection_toggle_published: + if (getSelectedArticleCount() > 0) { + SQLiteStatement stmt = m_activity.getWritableDb() + .compileStatement( + "UPDATE articles SET modified = 1, published = NOT published WHERE selected = 1"); + stmt.execute(); + stmt.close(); + } else { + int articleId = getArticleIdAtPosition(info.position); + + SQLiteStatement stmt = m_activity.getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, published = NOT published WHERE " + + BaseColumns._ID + " = ?"); + stmt.bindLong(1, articleId); + stmt.execute(); + stmt.close(); + } + refresh(); + return true; + case R.id.selection_toggle_unread: + if (getSelectedArticleCount() > 0) { + SQLiteStatement stmt = m_activity.getWritableDb() + .compileStatement( + "UPDATE articles SET modified = 1, unread = NOT unread WHERE selected = 1"); + stmt.execute(); + stmt.close(); + } else { + int articleId = getArticleIdAtPosition(info.position); + + SQLiteStatement stmt = m_activity.getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = NOT unread WHERE " + + BaseColumns._ID + " = ?"); + stmt.bindLong(1, articleId); + stmt.execute(); + stmt.close(); + } + refresh(); + return true; + case R.id.share_article: + if (true) { + int articleId = getArticleIdAtPosition(info.position); + m_activity.shareArticle(articleId); + } + return true; + case R.id.catchup_above: + if (true) { + int articleId = getArticleIdAtPosition(info.position); + + SQLiteStatement stmt = null; + + String updatedOperator = (m_prefs.getBoolean("offline_oldest_first", false)) ? "<" : ">"; + + if (m_feedIsCat) { + stmt = m_activity.getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = 0 WHERE " + + "updated "+updatedOperator+" (SELECT updated FROM articles WHERE " + BaseColumns._ID + " = ?) " + + "AND unread = 1 AND feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)"); + } else { + stmt = m_activity.getWritableDb().compileStatement( + "UPDATE articles SET modified = 1, unread = 0 WHERE " + + "updated "+updatedOperator+" (SELECT updated FROM articles WHERE " + BaseColumns._ID + " = ?) " + + "AND unread = 1 AND feed_id = ?"); + } + + stmt.bindLong(1, articleId); + stmt.bindLong(2, m_feedId); + stmt.execute(); + stmt.close(); + } + refresh(); + return true; + default: + Log.d(TAG, "onContextItemSelected, unhandled id=" + item.getItemId()); + return super.onContextItemSelected(item); + } + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, + ContextMenuInfo menuInfo) { + + getActivity().getMenuInflater().inflate(R.menu.headlines_context_menu, menu); + + if (getSelectedArticleCount() > 0) { + menu.setHeaderTitle(R.string.headline_context_multiple); + menu.setGroupVisible(R.id.menu_group_single_article, false); + } else { + AdapterContextMenuInfo info = (AdapterContextMenuInfo)menuInfo; + Cursor c = getArticleAtPosition(info.position); + menu.setHeaderTitle(c.getString(c.getColumnIndex("title"))); + //c.close(); + menu.setGroupVisible(R.id.menu_group_single_article, true); + + menu.findItem(R.id.set_labels).setVisible(false); + menu.findItem(R.id.article_set_note).setVisible(false); + } + + super.onCreateContextMenu(menu, v, menuInfo); + + } + + @Override + public void onResume() { + super.onResume(); + + if (GlobalState.getInstance().m_selectedArticleId != 0) { + m_activeArticleId = GlobalState.getInstance().m_selectedArticleId; + GlobalState.getInstance().m_selectedArticleId = 0; + } + + if (m_activeArticleId != 0) { + setActiveArticleId(m_activeArticleId); + } + + refresh(); + } + + public void refresh() { + if (m_cursor != null && !m_cursor.isClosed()) m_cursor.close(); + + m_cursor = createCursor(); + + if (m_cursor != null) { + m_adapter.changeCursor(m_cursor); + m_adapter.notifyDataSetChanged(); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + if (savedInstanceState != null) { + m_feedId = savedInstanceState.getInt("feedId"); + m_activeArticleId = savedInstanceState.getInt("activeArticleId"); + //m_selectedArticles = savedInstanceState.getParcelableArrayList("selectedArticles"); + m_searchQuery = (String) savedInstanceState.getCharSequence("searchQuery"); + m_feedIsCat = savedInstanceState.getBoolean("feedIsCat"); + } else { + m_activity.getWritableDb().execSQL("UPDATE articles SET selected = 0 "); + } + + View view = inflater.inflate(R.layout.headlines_fragment, container, false); + + m_cursor = createCursor(); + + ListView list = (ListView)view.findViewById(R.id.headlines); + m_adapter = new ArticleListAdapter(getActivity(), R.layout.headlines_row, m_cursor, + new String[] { "title" }, new int[] { R.id.title }, 0); + + list.setAdapter(m_adapter); + list.setOnItemClickListener(this); + list.setEmptyView(view.findViewById(R.id.no_headlines)); + registerForContextMenu(list); + + if (m_activity.isSmallScreen() || m_activity.isPortrait()) + view.findViewById(R.id.headlines_fragment).setPadding(0, 0, 0, 0); + + getActivity().setProgressBarIndeterminateVisibility(false); + + return view; + } + + public Cursor createCursor() { + String feedClause = null; + + if (m_feedIsCat) { + feedClause = "feed_id IN (SELECT "+BaseColumns._ID+" FROM feeds WHERE cat_id = ?)"; + } else { + feedClause = "feed_id = ?"; + } + + String orderBy = (m_prefs.getBoolean("offline_oldest_first", false)) ? "updated" : "updated DESC"; + + if (m_searchQuery == null || m_searchQuery.equals("")) { + return m_activity.getReadableDb().query("articles LEFT JOIN feeds ON (feed_id = feeds."+BaseColumns._ID+")", + new String[] { "articles.*", "feeds.title AS feed_title" }, feedClause, + new String[] { String.valueOf(m_feedId) }, null, null, orderBy); + } else { + return m_activity.getReadableDb().query("articles LEFT JOIN feeds ON (feed_id = feeds."+BaseColumns._ID+")", + new String[] { "articles.*", "feeds.title AS feed_title" }, + feedClause + " AND (articles.title LIKE '%' || ? || '%' OR content LIKE '%' || ? || '%')", + new String[] { String.valueOf(m_feedId), m_searchQuery, m_searchQuery }, null, null, orderBy); + } + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + m_listener = (OfflineHeadlinesEventListener) activity; + m_activity = (OfflineActivity) activity; + + m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()); + } + + @Override + public void onItemClick(AdapterView<?> av, View view, int position, long id) { + ListView list = (ListView)av; + + Log.d(TAG, "onItemClick=" + position); + + if (list != null) { + /* Cursor cursor = (Cursor)list.getItemAtPosition(position); + + int articleId = cursor.getInt(0); */ + + int articleId = getArticleIdAtPosition(position); + + if (getActivity().findViewById(R.id.article_fragment) != null) { + m_activeArticleId = articleId; + } + + m_listener.onArticleSelected(articleId); + + refresh(); + } + } + + @Override + public void onSaveInstanceState (Bundle out) { + super.onSaveInstanceState(out); + + out.putInt("feedId", m_feedId); + out.putInt("activeArticleId", m_activeArticleId); + //out.putParcelableArrayList("selectedArticles", m_selectedArticles); + out.putCharSequence("searchQuery", m_searchQuery); + out.putBoolean("feedIsCat", m_feedIsCat); + } + + /* public void setLoadingStatus(int status, boolean showProgress) { + if (getView() != null) { + TextView tv = (TextView)getView().findViewById(R.id.loading_message); + + if (tv != null) { + tv.setText(status); + } + } + + getActivity().setProgressBarIndeterminateVisibility(showProgress); + } */ + + private class ArticleListAdapter extends SimpleCursorAdapter { + public ArticleListAdapter(Context context, int layout, Cursor c, + String[] from, int[] to, int flags) { + super(context, layout, c, from, to, flags); + // TODO Auto-generated constructor stub + } + + public static final int VIEW_NORMAL = 0; + public static final int VIEW_UNREAD = 1; + public static final int VIEW_SELECTED = 2; + public static final int VIEW_SELECTED_UNREAD = 3; + public static final int VIEW_LOADMORE = 4; + + public static final int VIEW_COUNT = VIEW_LOADMORE+1; + + + public int getViewTypeCount() { + return VIEW_COUNT; + } + + @Override + public int getItemViewType(int position) { + Cursor c = (Cursor) getItem(position); + + //Log.d(TAG, "@gIVT " + position + " " + c.getInt(0) + " vs " + m_activeArticleId); + + if (c.getInt(0) == m_activeArticleId && c.getInt(c.getColumnIndex("unread")) == 1) { + return VIEW_SELECTED_UNREAD; + } else if (c.getInt(0) == m_activeArticleId) { + return VIEW_SELECTED; + } else if (c.getInt(c.getColumnIndex("unread")) == 1) { + return VIEW_UNREAD; + } else { + return VIEW_NORMAL; + } + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + + View v = convertView; + + Cursor article = (Cursor)getItem(position); + final int articleId = article.getInt(0); + + if (v == null) { + int layoutId = R.layout.headlines_row; + + switch (getItemViewType(position)) { + case VIEW_LOADMORE: + layoutId = R.layout.headlines_row_loadmore; + break; + case VIEW_UNREAD: + layoutId = R.layout.headlines_row_unread; + break; + case VIEW_SELECTED_UNREAD: + layoutId = R.layout.headlines_row_selected_unread; + break; + case VIEW_SELECTED: + layoutId = R.layout.headlines_row_selected; + break; + } + + LayoutInflater vi = (LayoutInflater)getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + v = vi.inflate(layoutId, null); + + // http://code.google.com/p/android/issues/detail?id=3414 + ((ViewGroup)v).setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS); + } + + TextView tt = (TextView)v.findViewById(R.id.title); + + if (tt != null) { + tt.setText(Html.fromHtml(article.getString(article.getColumnIndex("title")))); + } + + TextView ft = (TextView)v.findViewById(R.id.feed_title); + + int feedTitleIndex = article.getColumnIndex("feed_title"); + + if (ft != null && feedTitleIndex != -1 && m_feedIsCat) { + String feedTitle = article.getString(feedTitleIndex); + + if (feedTitle.length() > 20) + feedTitle = feedTitle.substring(0, 20) + "..."; + + if (feedTitle.length() > 0) { + ft.setText(feedTitle); + } else { + ft.setVisibility(View.GONE); + } + } else if (ft != null) { + ft.setVisibility(View.GONE); + } + + ImageView marked = (ImageView)v.findViewById(R.id.marked); + + if (marked != null) { + marked.setImageResource(article.getInt(article.getColumnIndex("marked")) == 1 ? android.R.drawable.star_on : android.R.drawable.star_off); + + marked.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + SQLiteStatement stmtUpdate = m_activity.getWritableDb().compileStatement("UPDATE articles SET modified = 1, marked = NOT marked " + + "WHERE " + BaseColumns._ID + " = ?"); + + stmtUpdate.bindLong(1, articleId); + stmtUpdate.execute(); + stmtUpdate.close(); + + refresh(); + } + }); + } + + ImageView published = (ImageView)v.findViewById(R.id.published); + + if (published != null) { + published.setImageResource(article.getInt(article.getColumnIndex("published")) == 1 ? R.drawable.ic_rss : R.drawable.ic_rss_bw); + + published.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + SQLiteStatement stmtUpdate = m_activity.getWritableDb().compileStatement("UPDATE articles SET modified = 1, published = NOT published " + + "WHERE " + BaseColumns._ID + " = ?"); + + stmtUpdate.bindLong(1, articleId); + stmtUpdate.execute(); + stmtUpdate.close(); + + refresh(); + } + }); + } + + TextView te = (TextView)v.findViewById(R.id.excerpt); + + if (te != null) { + String excerpt = Jsoup.parse(article.getString(article.getColumnIndex("content"))).text(); + + if (excerpt.length() > 100) + excerpt = excerpt.substring(0, 100) + "..."; + + te.setText(excerpt); + } + + /* ImageView separator = (ImageView)v.findViewById(R.id.headlines_separator); + + if (separator != null && m_offlineServices.isSmallScreen()) { + separator.setVisibility(View.GONE); + } */ + + TextView dv = (TextView) v.findViewById(R.id.date); + + if (dv != null) { + Date d = new Date((long)article.getInt(article.getColumnIndex("updated")) * 1000); + DateFormat df = new SimpleDateFormat("MMM dd, HH:mm"); + df.setTimeZone(TimeZone.getDefault()); + dv.setText(df.format(d)); + } + + CheckBox cb = (CheckBox) v.findViewById(R.id.selected); + + if (cb != null) { + cb.setChecked(article.getInt(article.getColumnIndex("selected")) == 1); + cb.setOnClickListener(new OnClickListener() { + + @Override + public void onClick(View view) { + CheckBox cb = (CheckBox)view; + + SQLiteStatement stmtUpdate = m_activity.getWritableDb().compileStatement("UPDATE articles SET selected = ? " + + "WHERE " + BaseColumns._ID + " = ?"); + + stmtUpdate.bindLong(1, cb.isChecked() ? 1 : 0); + stmtUpdate.bindLong(2, articleId); + stmtUpdate.execute(); + stmtUpdate.close(); + + refresh(); + + m_activity.initMenu(); + + } + }); + } + + /* ImageButton ib = (ImageButton) v.findViewById(R.id.article_menu_button); + + if (ib != null) { + ib.setVisibility(android.os.Build.VERSION.SDK_INT >= 10 ? View.VISIBLE : View.GONE); + ib.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + getActivity().openContextMenu(v); + } + }); + } */ + + return v; + } + } + + public void notifyUpdated() { + m_adapter.notifyDataSetChanged(); + } + + public void setActiveArticleId(int articleId) { + m_activeArticleId = articleId; + try { + m_adapter.notifyDataSetChanged(); + + ListView list = (ListView)getView().findViewById(R.id.headlines); + + Log.d(TAG, articleId + " position " + getArticleIdPosition(articleId)); + + if (list != null) { + list.setSelection(getArticleIdPosition(articleId)); + } + } catch (NullPointerException e) { + // invoked before view is created, nvm + } + } + + public Cursor getArticleAtPosition(int position) { + return (Cursor) m_adapter.getItem(position); + } + + public int getArticleIdAtPosition(int position) { + /*Cursor c = getArticleAtPosition(position); + + if (c != null) { + int id = c.getInt(0); + return id; + } */ + + return (int) m_adapter.getItemId(position); + } + + public int getActiveArticleId() { + return m_activeArticleId; + } + + public int getArticleIdPosition(int articleId) { + for (int i = 0; i < m_adapter.getCount(); i++) { + if (articleId == m_adapter.getItemId(i)) + return i; + } + + return -1; + } + + public int getArticleCount() { + return m_adapter.getCount(); + } + + public void setSearchQuery(String query) { + if (!m_searchQuery.equals(query)) { + m_searchQuery = query; + } + } + + public int getFeedId() { + return m_feedId; + } + + public boolean getFeedIsCat() { + return m_feedIsCat; + } + + public String getSearchQuery() { + return m_searchQuery; + } + +} diff --git a/src/org/fox/ttrss/offline/OfflineUploadService.java b/src/org/fox/ttrss/offline/OfflineUploadService.java index 3624bdf7..55ed4467 100644 --- a/src/org/fox/ttrss/offline/OfflineUploadService.java +++ b/src/org/fox/ttrss/offline/OfflineUploadService.java @@ -1,273 +1,273 @@ -package org.fox.ttrss.offline;
-
-import java.util.HashMap;
-
-import org.fox.ttrss.ApiRequest;
-import org.fox.ttrss.OnlineActivity;
-import org.fox.ttrss.R;
-import org.fox.ttrss.util.DatabaseHelper;
-
-import android.app.IntentService;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.Intent;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.util.Log;
-
-import com.google.gson.JsonElement;
-
-public class OfflineUploadService extends IntentService {
- private final String TAG = this.getClass().getSimpleName();
-
- public static final int NOTIFY_UPLOADING = 2;
- public static final String INTENT_ACTION_SUCCESS = "org.fox.ttrss.intent.action.UploadComplete";
-
- private SQLiteDatabase m_writableDb;
- private SQLiteDatabase m_readableDb;
- private String m_sessionId;
- private NotificationManager m_nmgr;
- private boolean m_uploadInProgress = false;
-
- public OfflineUploadService() {
- super("OfflineUploadService");
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- m_nmgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
- initDatabase();
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- m_nmgr.cancel(NOTIFY_UPLOADING);
- }
-
- @SuppressWarnings("deprecation")
- private void updateNotification(String msg) {
- Notification notification = new Notification(R.drawable.icon,
- getString(R.string.notify_uploading_title), System.currentTimeMillis());
-
- PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
- new Intent(this, OnlineActivity.class), 0);
-
- notification.flags |= Notification.FLAG_ONGOING_EVENT;
- notification.flags |= Notification.FLAG_ONLY_ALERT_ONCE;
-
- notification.setLatestEventInfo(this, getString(R.string.notify_uploading_title), msg, contentIntent);
-
- m_nmgr.notify(NOTIFY_UPLOADING, notification);
- }
-
- private void updateNotification(int msgResId) {
- updateNotification(getString(msgResId));
- }
-
- private void initDatabase() {
- DatabaseHelper dh = new DatabaseHelper(getApplicationContext());
- m_writableDb = dh.getWritableDatabase();
- m_readableDb = dh.getReadableDatabase();
- }
-
- private synchronized SQLiteDatabase getReadableDb() {
- return m_readableDb;
- }
-
- private synchronized SQLiteDatabase getWritableDb() {
- return m_writableDb;
- }
-
- private void uploadRead() {
- Log.d(TAG, "syncing modified offline data... (read)");
-
- final String ids = getModifiedIds(ModifiedCriteria.READ);
-
- if (ids.length() > 0) {
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- @Override
- protected void onPostExecute(JsonElement result) {
- if (result != null) {
- uploadMarked();
- } else {
- updateNotification(getErrorMessage());
- uploadFailed();
- }
- }
- };
-
- @SuppressWarnings("serial")
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", m_sessionId);
- put("op", "updateArticle");
- put("article_ids", ids);
- put("mode", "0");
- put("field", "2");
- }
- };
-
- req.execute(map);
- } else {
- uploadMarked();
- }
- }
-
- private enum ModifiedCriteria {
- READ, MARKED, PUBLISHED
- };
-
- private String getModifiedIds(ModifiedCriteria criteria) {
-
- String criteriaStr = "";
-
- switch (criteria) {
- case READ:
- criteriaStr = "unread = 0";
- break;
- case MARKED:
- criteriaStr = "marked = 1";
- break;
- case PUBLISHED:
- criteriaStr = "published = 1";
- break;
- }
-
- Cursor c = getReadableDb().query("articles", null,
- "modified = 1 AND " + criteriaStr, null, null, null, null);
-
- String tmp = "";
-
- while (c.moveToNext()) {
- tmp += c.getInt(0) + ",";
- }
-
- tmp = tmp.replaceAll(",$", "");
-
- c.close();
-
- return tmp;
- }
-
- private void uploadMarked() {
- Log.d(TAG, "syncing modified offline data... (marked)");
-
- final String ids = getModifiedIds(ModifiedCriteria.MARKED);
-
- if (ids.length() > 0) {
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- @Override
- protected void onPostExecute(JsonElement result) {
- if (result != null) {
- uploadPublished();
- } else {
- updateNotification(getErrorMessage());
- uploadFailed();
- }
- }
- };
-
- @SuppressWarnings("serial")
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", m_sessionId);
- put("op", "updateArticle");
- put("article_ids", ids);
- put("mode", "1");
- put("field", "0");
- }
- };
-
- req.execute(map);
- } else {
- uploadPublished();
- }
- }
-
- private void uploadFailed() {
- m_readableDb.close();
- m_writableDb.close();
-
- // TODO send notification to activity?
-
- m_uploadInProgress = false;
- }
-
- private void uploadSuccess() {
- getWritableDb().execSQL("UPDATE articles SET modified = 0");
-
- Intent intent = new Intent();
- intent.setAction(INTENT_ACTION_SUCCESS);
- intent.addCategory(Intent.CATEGORY_DEFAULT);
- sendBroadcast(intent);
-
- m_readableDb.close();
- m_writableDb.close();
-
- m_uploadInProgress = false;
-
- m_nmgr.cancel(NOTIFY_UPLOADING);
- }
-
- private void uploadPublished() {
- Log.d(TAG, "syncing modified offline data... (published)");
-
- final String ids = getModifiedIds(ModifiedCriteria.MARKED);
-
- if (ids.length() > 0) {
- ApiRequest req = new ApiRequest(getApplicationContext()) {
- @Override
- protected void onPostExecute(JsonElement result) {
- if (result != null) {
- uploadSuccess();
- } else {
- updateNotification(getErrorMessage());
- uploadFailed();
- }
- }
- };
-
- @SuppressWarnings("serial")
- HashMap<String, String> map = new HashMap<String, String>() {
- {
- put("sid", m_sessionId);
- put("op", "updateArticle");
- put("article_ids", ids);
- put("mode", "1");
- put("field", "1");
- }
- };
-
- req.execute(map);
- } else {
- uploadSuccess();
- }
- }
-
-
- @Override
- protected void onHandleIntent(Intent intent) {
- try {
- if (getWritableDb().isDbLockedByCurrentThread() || getWritableDb().isDbLockedByOtherThreads()) {
- return;
- }
-
- m_sessionId = intent.getStringExtra("sessionId");
-
- if (!m_uploadInProgress) {
- m_uploadInProgress = true;
-
- updateNotification(R.string.notify_uploading_sending_data);
-
- uploadRead();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
-}
+package org.fox.ttrss.offline; + +import java.util.HashMap; + +import org.fox.ttrss.ApiRequest; +import org.fox.ttrss.OnlineActivity; +import org.fox.ttrss.R; +import org.fox.ttrss.util.DatabaseHelper; + +import android.app.IntentService; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.Intent; +import android.database.Cursor; +import android.database.sqlite.SQLiteDatabase; +import android.util.Log; + +import com.google.gson.JsonElement; + +public class OfflineUploadService extends IntentService { + private final String TAG = this.getClass().getSimpleName(); + + public static final int NOTIFY_UPLOADING = 2; + public static final String INTENT_ACTION_SUCCESS = "org.fox.ttrss.intent.action.UploadComplete"; + + private SQLiteDatabase m_writableDb; + private SQLiteDatabase m_readableDb; + private String m_sessionId; + private NotificationManager m_nmgr; + private boolean m_uploadInProgress = false; + + public OfflineUploadService() { + super("OfflineUploadService"); + } + + @Override + public void onCreate() { + super.onCreate(); + m_nmgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); + initDatabase(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + + m_nmgr.cancel(NOTIFY_UPLOADING); + } + + @SuppressWarnings("deprecation") + private void updateNotification(String msg) { + Notification notification = new Notification(R.drawable.icon, + getString(R.string.notify_uploading_title), System.currentTimeMillis()); + + PendingIntent contentIntent = PendingIntent.getActivity(this, 0, + new Intent(this, OnlineActivity.class), 0); + + notification.flags |= Notification.FLAG_ONGOING_EVENT; + notification.flags |= Notification.FLAG_ONLY_ALERT_ONCE; + + notification.setLatestEventInfo(this, getString(R.string.notify_uploading_title), msg, contentIntent); + + m_nmgr.notify(NOTIFY_UPLOADING, notification); + } + + private void updateNotification(int msgResId) { + updateNotification(getString(msgResId)); + } + + private void initDatabase() { + DatabaseHelper dh = new DatabaseHelper(getApplicationContext()); + m_writableDb = dh.getWritableDatabase(); + m_readableDb = dh.getReadableDatabase(); + } + + private synchronized SQLiteDatabase getReadableDb() { + return m_readableDb; + } + + private synchronized SQLiteDatabase getWritableDb() { + return m_writableDb; + } + + private void uploadRead() { + Log.d(TAG, "syncing modified offline data... (read)"); + + final String ids = getModifiedIds(ModifiedCriteria.READ); + + if (ids.length() > 0) { + ApiRequest req = new ApiRequest(getApplicationContext()) { + @Override + protected void onPostExecute(JsonElement result) { + if (result != null) { + uploadMarked(); + } else { + updateNotification(getErrorMessage()); + uploadFailed(); + } + } + }; + + @SuppressWarnings("serial") + HashMap<String, String> map = new HashMap<String, String>() { + { + put("sid", m_sessionId); + put("op", "updateArticle"); + put("article_ids", ids); + put("mode", "0"); + put("field", "2"); + } + }; + + req.execute(map); + } else { + uploadMarked(); + } + } + + private enum ModifiedCriteria { + READ, MARKED, PUBLISHED + }; + + private String getModifiedIds(ModifiedCriteria criteria) { + + String criteriaStr = ""; + + switch (criteria) { + case READ: + criteriaStr = "unread = 0"; + break; + case MARKED: + criteriaStr = "marked = 1"; + break; + case PUBLISHED: + criteriaStr = "published = 1"; + break; + } + + Cursor c = getReadableDb().query("articles", null, + "modified = 1 AND " + criteriaStr, null, null, null, null); + + String tmp = ""; + + while (c.moveToNext()) { + tmp += c.getInt(0) + ","; + } + + tmp = tmp.replaceAll(",$", ""); + + c.close(); + + return tmp; + } + + private void uploadMarked() { + Log.d(TAG, "syncing modified offline data... (marked)"); + + final String ids = getModifiedIds(ModifiedCriteria.MARKED); + + if (ids.length() > 0) { + ApiRequest req = new ApiRequest(getApplicationContext()) { + @Override + protected void onPostExecute(JsonElement result) { + if (result != null) { + uploadPublished(); + } else { + updateNotification(getErrorMessage()); + uploadFailed(); + } + } + }; + + @SuppressWarnings("serial") + HashMap<String, String> map = new HashMap<String, String>() { + { + put("sid", m_sessionId); + put("op", "updateArticle"); + put("article_ids", ids); + put("mode", "1"); + put("field", "0"); + } + }; + + req.execute(map); + } else { + uploadPublished(); + } + } + + private void uploadFailed() { + m_readableDb.close(); + m_writableDb.close(); + + // TODO send notification to activity? + + m_uploadInProgress = false; + } + + private void uploadSuccess() { + getWritableDb().execSQL("UPDATE articles SET modified = 0"); + + Intent intent = new Intent(); + intent.setAction(INTENT_ACTION_SUCCESS); + intent.addCategory(Intent.CATEGORY_DEFAULT); + sendBroadcast(intent); + + m_readableDb.close(); + m_writableDb.close(); + + m_uploadInProgress = false; + + m_nmgr.cancel(NOTIFY_UPLOADING); + } + + private void uploadPublished() { + Log.d(TAG, "syncing modified offline data... (published)"); + + final String ids = getModifiedIds(ModifiedCriteria.MARKED); + + if (ids.length() > 0) { + ApiRequest req = new ApiRequest(getApplicationContext()) { + @Override + protected void onPostExecute(JsonElement result) { + if (result != null) { + uploadSuccess(); + } else { + updateNotification(getErrorMessage()); + uploadFailed(); + } + } + }; + + @SuppressWarnings("serial") + HashMap<String, String> map = new HashMap<String, String>() { + { + put("sid", m_sessionId); + put("op", "updateArticle"); + put("article_ids", ids); + put("mode", "1"); + put("field", "1"); + } + }; + + req.execute(map); + } else { + uploadSuccess(); + } + } + + + @Override + protected void onHandleIntent(Intent intent) { + try { + if (getWritableDb().isDbLockedByCurrentThread() || getWritableDb().isDbLockedByOtherThreads()) { + return; + } + + m_sessionId = intent.getStringExtra("sessionId"); + + if (!m_uploadInProgress) { + m_uploadInProgress = true; + + updateNotification(R.string.notify_uploading_sending_data); + + uploadRead(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + +} |