From 4eac5b73bb4e3d91794a688d7e760e1f6e629c88 Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Mon, 17 Sep 2012 16:28:32 +0400 Subject: implement core offline functions --- src/org/fox/ttrss/ArticleEventListener.java | 9 - src/org/fox/ttrss/ArticleFragment.java | 8 +- src/org/fox/ttrss/FeedsActivity.java | 2 +- src/org/fox/ttrss/FeedsEventListener.java | 5 - src/org/fox/ttrss/HeadlinesActivity.java | 2 +- src/org/fox/ttrss/OnlineActivity.java | 309 ++++++++++- src/org/fox/ttrss/offline/OfflineActivity.java | 192 +++++++ .../ttrss/offline/OfflineArticleEventListener.java | 5 + .../fox/ttrss/offline/OfflineArticleFragment.java | 269 ++++++++++ src/org/fox/ttrss/offline/OfflineArticlePager.java | 150 ++++++ .../fox/ttrss/offline/OfflineDownloadService.java | 452 ++++++++++++++++ .../offline/OfflineFeedCategoriesFragment.java | 307 +++++++++++ .../fox/ttrss/offline/OfflineFeedsActivity.java | 261 +++++++++ .../fox/ttrss/offline/OfflineFeedsFragment.java | 331 ++++++++++++ .../offline/OfflineHeadlinesEventListener.java | 17 + .../ttrss/offline/OfflineHeadlinesFragment.java | 585 +++++++++++++++++++++ .../fox/ttrss/offline/OfflineUploadService.java | 264 ++++++++++ src/org/fox/ttrss/util/ImageCacheService.java | 208 ++++++++ 18 files changed, 3339 insertions(+), 37 deletions(-) delete mode 100644 src/org/fox/ttrss/ArticleEventListener.java delete mode 100644 src/org/fox/ttrss/FeedsEventListener.java create mode 100644 src/org/fox/ttrss/offline/OfflineActivity.java create mode 100644 src/org/fox/ttrss/offline/OfflineArticleEventListener.java create mode 100644 src/org/fox/ttrss/offline/OfflineArticleFragment.java create mode 100644 src/org/fox/ttrss/offline/OfflineArticlePager.java create mode 100644 src/org/fox/ttrss/offline/OfflineDownloadService.java create mode 100644 src/org/fox/ttrss/offline/OfflineFeedCategoriesFragment.java create mode 100644 src/org/fox/ttrss/offline/OfflineFeedsActivity.java create mode 100644 src/org/fox/ttrss/offline/OfflineFeedsFragment.java create mode 100644 src/org/fox/ttrss/offline/OfflineHeadlinesEventListener.java create mode 100644 src/org/fox/ttrss/offline/OfflineHeadlinesFragment.java create mode 100644 src/org/fox/ttrss/offline/OfflineUploadService.java create mode 100644 src/org/fox/ttrss/util/ImageCacheService.java (limited to 'src') diff --git a/src/org/fox/ttrss/ArticleEventListener.java b/src/org/fox/ttrss/ArticleEventListener.java deleted file mode 100644 index 688c10f1..00000000 --- a/src/org/fox/ttrss/ArticleEventListener.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.fox.ttrss; - -public interface ArticleEventListener { - - void copyToClipboard(String content_url); - - boolean isSmallScreen(); - -} diff --git a/src/org/fox/ttrss/ArticleFragment.java b/src/org/fox/ttrss/ArticleFragment.java index 586fb10b..10b87c25 100644 --- a/src/org/fox/ttrss/ArticleFragment.java +++ b/src/org/fox/ttrss/ArticleFragment.java @@ -47,7 +47,7 @@ public class ArticleFragment extends Fragment { private SharedPreferences m_prefs; private Article m_article; - private ArticleEventListener m_onlineServices; + private OnlineActivity m_activity; //private Article m_nextArticle; //private Article m_prevArticle; @@ -251,7 +251,7 @@ public class ArticleFragment extends Fragment { Attachment attachment = (Attachment) spinner.getSelectedItem(); if (attachment != null) { - m_onlineServices.copyToClipboard(attachment.content_url); + m_activity.copyToClipboard(attachment.content_url); } } }); @@ -268,7 +268,7 @@ public class ArticleFragment extends Fragment { e.printStackTrace(); } - if (m_onlineServices.isSmallScreen()) + if (m_activity.isSmallScreen()) web.setOnTouchListener(m_gestureListener); } @@ -321,7 +321,7 @@ public class ArticleFragment extends Fragment { super.onAttach(activity); m_prefs = PreferenceManager.getDefaultSharedPreferences(getActivity().getApplicationContext()); - m_onlineServices = (ArticleEventListener)activity; + m_activity = (OnlineActivity)activity; //m_article = m_onlineServices.getSelectedArticle(); } diff --git a/src/org/fox/ttrss/FeedsActivity.java b/src/org/fox/ttrss/FeedsActivity.java index 72ca5bff..a03f6270 100644 --- a/src/org/fox/ttrss/FeedsActivity.java +++ b/src/org/fox/ttrss/FeedsActivity.java @@ -21,7 +21,7 @@ import android.view.View; import android.view.Window; import android.widget.ShareActionProvider; -public class FeedsActivity extends OnlineActivity implements HeadlinesEventListener, ArticleEventListener { +public class FeedsActivity extends OnlineActivity implements HeadlinesEventListener { private final String TAG = this.getClass().getSimpleName(); protected SharedPreferences m_prefs; diff --git a/src/org/fox/ttrss/FeedsEventListener.java b/src/org/fox/ttrss/FeedsEventListener.java deleted file mode 100644 index 8e6b7bce..00000000 --- a/src/org/fox/ttrss/FeedsEventListener.java +++ /dev/null @@ -1,5 +0,0 @@ -package org.fox.ttrss; - -public interface FeedsEventListener { - -} diff --git a/src/org/fox/ttrss/HeadlinesActivity.java b/src/org/fox/ttrss/HeadlinesActivity.java index 2d7a6a3a..b4672f6a 100644 --- a/src/org/fox/ttrss/HeadlinesActivity.java +++ b/src/org/fox/ttrss/HeadlinesActivity.java @@ -18,7 +18,7 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -public class HeadlinesActivity extends OnlineActivity implements HeadlinesEventListener, ArticleEventListener { +public class HeadlinesActivity extends OnlineActivity implements HeadlinesEventListener { private final String TAG = this.getClass().getSimpleName(); protected SharedPreferences m_prefs; diff --git a/src/org/fox/ttrss/OnlineActivity.java b/src/org/fox/ttrss/OnlineActivity.java index b91a398a..6c65c43b 100644 --- a/src/org/fox/ttrss/OnlineActivity.java +++ b/src/org/fox/ttrss/OnlineActivity.java @@ -4,6 +4,9 @@ import java.lang.reflect.Type; import java.util.HashMap; import java.util.List; +import org.fox.ttrss.offline.OfflineActivity; +import org.fox.ttrss.offline.OfflineDownloadService; +import org.fox.ttrss.offline.OfflineUploadService; import org.fox.ttrss.types.Article; import org.fox.ttrss.types.ArticleList; import org.fox.ttrss.types.Feed; @@ -16,12 +19,15 @@ import com.google.gson.reflect.TypeToken; import android.app.AlertDialog; import android.app.Dialog; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.DialogInterface.OnClickListener; import android.content.DialogInterface.OnMultiChoiceClickListener; +import android.database.Cursor; import android.os.Bundle; import android.preference.PreferenceManager; import android.support.v4.app.FragmentTransaction; @@ -46,10 +52,29 @@ public class OnlineActivity extends CommonActivity { protected boolean m_unreadOnly = true; protected boolean m_unreadArticlesOnly = true; + protected int m_offlineModeStatus = 0; private ActionMode m_headlinesActionMode; private HeadlinesActionModeCallback m_headlinesActionModeCallback; + private BroadcastReceiver m_broadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context content, Intent intent) { + + if (intent.getAction().equals(OfflineDownloadService.INTENT_ACTION_SUCCESS)) { + + m_offlineModeStatus = 2; + + switchOffline(); + + } else if (intent.getAction().equals(OfflineUploadService.INTENT_ACTION_SUCCESS)) { + Log.d(TAG, "offline upload service reports success"); + toast(R.string.offline_sync_success); + } + } + }; + + private class HeadlinesActionModeCallback implements ActionMode.Callback { @Override @@ -106,31 +131,246 @@ public class OnlineActivity extends CommonActivity { setProgressBarIndeterminateVisibility(false); - if (getIntent().getExtras() != null) { - Intent i = getIntent(); - - m_sessionId = i.getStringExtra("sessionId"); - m_apiLevel = i.getIntExtra("apiLevel", -1); - } +// SharedPreferences localPrefs = getSharedPreferences("localprefs", Context.MODE_PRIVATE); + + SharedPreferences localPrefs = getSharedPreferences("localprefs", Context.MODE_PRIVATE); - if (savedInstanceState != null) { - m_sessionId = savedInstanceState.getString("sessionId"); - m_apiLevel = savedInstanceState.getInt("apiLevel"); + boolean isOffline = localPrefs.getBoolean("offline_mode_active", false); + + Log.d(TAG, "m_isOffline=" + isOffline); + + setContentView(R.layout.online); + + if (isOffline) { + switchOfflineSuccess(); + } else { + + if (getIntent().getExtras() != null) { + Intent i = getIntent(); + + m_sessionId = i.getStringExtra("sessionId"); + m_apiLevel = i.getIntExtra("apiLevel", -1); + } - m_unreadOnly = savedInstanceState.getBoolean("unreadOnly"); - m_unreadArticlesOnly = savedInstanceState.getBoolean("unreadArticlesOnly"); + if (savedInstanceState != null) { + m_sessionId = savedInstanceState.getString("sessionId"); + m_apiLevel = savedInstanceState.getInt("apiLevel"); + m_unreadOnly = savedInstanceState.getBoolean("unreadOnly"); + m_unreadArticlesOnly = savedInstanceState.getBoolean("unreadArticlesOnly"); + m_offlineModeStatus = savedInstanceState.getInt("offlineModeStatus"); + } + + if (!isCompatMode()) { + m_headlinesActionModeCallback = new HeadlinesActionModeCallback(); + } + + Log.d(TAG, "m_sessionId=" + m_sessionId); + Log.d(TAG, "m_apiLevel=" + m_apiLevel); } + } + + private void switchOffline() { + if (m_offlineModeStatus == 2) { + + AlertDialog.Builder builder = new AlertDialog.Builder( + OnlineActivity.this) + .setMessage(R.string.dialog_offline_success) + .setPositiveButton(R.string.dialog_offline_go, + new Dialog.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + + m_offlineModeStatus = 0; + + SharedPreferences localPrefs = getSharedPreferences("localprefs", Context.MODE_PRIVATE); + SharedPreferences.Editor editor = localPrefs.edit(); + editor.putBoolean("offline_mode_active", true); + editor.commit(); + + Intent offline = new Intent( + OnlineActivity.this, + OfflineActivity.class); + offline.putExtra("initial", true); + startActivity(offline); + finish(); + } + }) + .setNegativeButton(R.string.dialog_cancel, + new Dialog.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + + m_offlineModeStatus = 0; + + } + }); + + AlertDialog dlg = builder.create(); + dlg.show(); + + } else if (m_offlineModeStatus == 0) { - if (!isCompatMode()) { - m_headlinesActionModeCallback = new HeadlinesActionModeCallback(); + AlertDialog.Builder builder = new AlertDialog.Builder(this) + .setMessage(R.string.dialog_offline_switch_prompt) + .setPositiveButton(R.string.dialog_offline_go, + new Dialog.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + + if (m_sessionId != null) { + Log.d(TAG, "offline: starting"); + + m_offlineModeStatus = 1; + + Intent intent = new Intent( + OnlineActivity.this, + OfflineDownloadService.class); + intent.putExtra("sessionId", m_sessionId); + + startService(intent); + } + } + }) + .setNegativeButton(R.string.dialog_cancel, + new Dialog.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + // + } + }); + + AlertDialog dlg = builder.create(); + dlg.show(); + } else if (m_offlineModeStatus == 1) { + cancelOfflineSync(); + } + } + + private boolean hasPendingOfflineData() { + try { + Cursor c = getReadableDb().query("articles", + new String[] { "COUNT(*)" }, "modified = 1", null, null, null, + null); + if (c.moveToFirst()) { + int modified = c.getInt(0); + c.close(); + + return modified > 0; + } + } catch (IllegalStateException e) { + // db is closed? ugh } + + return false; + } + + private boolean hasOfflineData() { + try { + Cursor c = getReadableDb().query("articles", + new String[] { "COUNT(*)" }, null, null, null, null, null); + if (c.moveToFirst()) { + int modified = c.getInt(0); + c.close(); + + return modified > 0; + } + } catch (IllegalStateException e) { + // db is closed? + } + + return false; + } + + @Override + public void onPause() { + super.onPause(); + + unregisterReceiver(m_broadcastReceiver); + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + private void syncOfflineData() { + Log.d(TAG, "offlineSync: starting"); - Log.d(TAG, "m_sessionId=" + m_sessionId); - Log.d(TAG, "m_apiLevel=" + m_apiLevel); + Intent intent = new Intent( + OnlineActivity.this, + OfflineUploadService.class); - setContentView(R.layout.online); + intent.putExtra("sessionId", m_sessionId); + + startService(intent); + } + + private void cancelOfflineSync() { + AlertDialog.Builder builder = new AlertDialog.Builder(this) + .setMessage(R.string.dialog_offline_sync_in_progress) + .setNegativeButton(R.string.dialog_offline_sync_stop, + new Dialog.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + + if (m_sessionId != null) { + Log.d(TAG, "offline: stopping"); + + m_offlineModeStatus = 0; + + Intent intent = new Intent( + OnlineActivity.this, + OfflineDownloadService.class); + + stopService(intent); + + dialog.dismiss(); + + restart(); + } + } + }) + .setPositiveButton(R.string.dialog_offline_sync_continue, + new Dialog.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + + dialog.dismiss(); + + restart(); + } + }); + + AlertDialog dlg = builder.create(); + dlg.show(); } + + public void restart() { + Intent refresh = new Intent(OnlineActivity.this, OnlineActivity.class); + refresh.putExtra("sessionId", m_sessionId); + refresh.putExtra("apiLevel", m_apiLevel); + startActivity(refresh); + finish(); + } + + private void switchOfflineSuccess() { + logout(); + // setLoadingStatus(R.string.blank, false); + + SharedPreferences.Editor editor = m_prefs.edit(); + editor.putBoolean("offline_mode_active", true); + editor.commit(); + + Intent offline = new Intent(OnlineActivity.this, OfflineActivity.class); + offline.putExtra("initial", true); + offline.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); + + startActivityForResult(offline, 0); + finish(); + + } + public void login() { if (m_prefs.getString("ttrss_url", "").trim().length() == 0) { @@ -186,6 +426,9 @@ public class OnlineActivity extends CommonActivity { intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); startActivityForResult(intent, 0); + + if (hasPendingOfflineData()) + syncOfflineData(); finish(); } @@ -203,7 +446,7 @@ public class OnlineActivity extends CommonActivity { login(); return true; case R.id.go_offline: - // FIXME go offline + switchOffline(); return true; case R.id.article_set_note: if (ap != null && ap.getSelectedArticle() != null) { @@ -538,6 +781,30 @@ public class OnlineActivity extends CommonActivity { protected void loginFailure() { m_sessionId = null; initMenu(); + + if (hasOfflineData()) { + + AlertDialog.Builder builder = new AlertDialog.Builder( + OnlineActivity.this) + .setMessage(R.string.dialog_offline_prompt) + .setPositiveButton(R.string.dialog_offline_go, + new Dialog.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + switchOfflineSuccess(); + } + }) + .setNegativeButton(R.string.dialog_cancel, + new Dialog.OnClickListener() { + public void onClick(DialogInterface dialog, + int which) { + // + } + }); + + AlertDialog dlg = builder.create(); + dlg.show(); + } } public boolean getUnreadArticlesOnly() { @@ -556,12 +823,20 @@ public class OnlineActivity extends CommonActivity { out.putInt("apiLevel", m_apiLevel); out.putBoolean("unreadOnly", m_unreadOnly); out.putBoolean("unreadArticlesOnly", m_unreadArticlesOnly); + out.putInt("offlineModeStatus", m_offlineModeStatus); } @Override public void onResume() { super.onResume(); + IntentFilter filter = new IntentFilter(); + filter.addAction(OfflineDownloadService.INTENT_ACTION_SUCCESS); + filter.addAction(OfflineUploadService.INTENT_ACTION_SUCCESS); + filter.addCategory(Intent.CATEGORY_DEFAULT); + + registerReceiver(m_broadcastReceiver, filter); + if (m_sessionId == null) { login(); } else { diff --git a/src/org/fox/ttrss/offline/OfflineActivity.java b/src/org/fox/ttrss/offline/OfflineActivity.java new file mode 100644 index 00000000..7fb8c1a9 --- /dev/null +++ b/src/org/fox/ttrss/offline/OfflineActivity.java @@ -0,0 +1,192 @@ +package org.fox.ttrss.offline; + +import org.fox.ttrss.CommonActivity; +import org.fox.ttrss.R; + +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.database.Cursor; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.provider.BaseColumns; +import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; + +public class OfflineActivity extends CommonActivity { + private final String TAG = this.getClass().getSimpleName(); + + protected SharedPreferences m_prefs; + protected Menu m_menu; + protected boolean m_unreadOnly; + + @Override + public void onCreate(Bundle savedInstanceState) { + m_prefs = PreferenceManager + .getDefaultSharedPreferences(getApplicationContext()); + + if (m_prefs.getString("theme", "THEME_DARK").equals("THEME_DARK")) { + setTheme(R.style.DarkTheme); + } else { + setTheme(R.style.LightTheme); + } + + super.onCreate(savedInstanceState); + + setContentView(R.layout.online); + + 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_unreadOnly = savedInstanceState.getBoolean("unreadOnly"); + } + } + + @Override + public void onSaveInstanceState(Bundle out) { + super.onSaveInstanceState(out); + + out.putBoolean("unreadOnly", m_unreadOnly); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.go_online: + switchOnline(); + 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; + } + + public boolean getUnreadOnly() { + return m_unreadOnly; + } + + 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); + } + } + + 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; + } + + 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) { + 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; + } + + 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.id.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; + } + +} diff --git a/src/org/fox/ttrss/offline/OfflineArticleEventListener.java b/src/org/fox/ttrss/offline/OfflineArticleEventListener.java new file mode 100644 index 00000000..35b9de28 --- /dev/null +++ b/src/org/fox/ttrss/offline/OfflineArticleEventListener.java @@ -0,0 +1,5 @@ +package org.fox.ttrss.offline; + +public interface OfflineArticleEventListener { + +} diff --git a/src/org/fox/ttrss/offline/OfflineArticleFragment.java b/src/org/fox/ttrss/offline/OfflineArticleFragment.java new file mode 100644 index 00000000..266c89b2 --- /dev/null +++ b/src/org/fox/ttrss/offline/OfflineArticleFragment.java @@ -0,0 +1,269 @@ +package org.fox.ttrss.offline; + +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.fox.ttrss.OnlineActivity; +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.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.text.Html; +import android.text.method.LinkMovementMethod; +import android.util.Log; +import android.util.TypedValue; +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.webkit.WebSettings; +import android.webkit.WebView; +import android.webkit.WebSettings.LayoutAlgorithm; +import android.widget.TextView; +import android.widget.AdapterView.AdapterContextMenuInfo; + +public class OfflineArticleFragment extends Fragment { + @SuppressWarnings("unused") + 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; + + 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); + + } + + @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")); + + title.setMovementMethod(LinkMovementMethod.getInstance()); + title.setText(Html.fromHtml("" + titleStr + "")); + registerForContextMenu(title); + } + + WebView web = (WebView)view.findViewById(R.id.content); + + if (web != null) { + + String content; + String cssOverride = ""; + + WebSettings ws = web.getSettings(); + ws.setSupportZoom(true); + ws.setBuiltInZoomControls(true); + + 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}"; + //view.setBackgroundColor(android.R.color.black); + web.setBackgroundColor(getResources().getColor(android.R.color.transparent)); + } else { + cssOverride = ""; + } + + 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(url)) { + img.attr("src", "file://" + ImageCacheService.getCacheFileName(url)); + } + } + } + + // thanks webview for crashing on