From ced80be1aea975b59db5a0e6dd14acb054e7910e Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Sun, 16 Sep 2012 13:25:28 +0400 Subject: initial --- AndroidManifest.xml | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) (limited to 'AndroidManifest.xml') diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 94bfd20c..e4e00753 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="100" + android:versionName="0.8.0" > - - - - @@ -40,6 +32,21 @@ android:label="@string/preferences" > + + + + + + + + + -- cgit v1.2.3-54-g00ecf From 306a0bf4c9c0c3a8db719d6bd6211aa5f6355c0c Mon Sep 17 00:00:00 2001 From: Andrew Dolgov Date: Sun, 16 Sep 2012 21:59:03 +0400 Subject: implement application singleton to store retrieved headlines activities --- AndroidManifest.xml | 1 + src/org/fox/ttrss/ArticlePager.java | 7 +++++-- src/org/fox/ttrss/FeedsActivity.java | 2 +- src/org/fox/ttrss/HeadlinesActivity.java | 13 ++++--------- src/org/fox/ttrss/HeadlinesFragment.java | 21 +++++++++++---------- src/org/fox/ttrss/TinyApplication.java | 25 +++++++++++++++++++++++++ src/org/fox/ttrss/types/Feed.java | 7 +++++++ 7 files changed, 54 insertions(+), 22 deletions(-) create mode 100644 src/org/fox/ttrss/TinyApplication.java (limited to 'AndroidManifest.xml') diff --git a/AndroidManifest.xml b/AndroidManifest.xml index e4e00753..1d48a3be 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -13,6 +13,7 @@ alist = i.getParcelableArrayListExtra("articles"); - ArticleList articles = new ArticleList(); - - for (Article a : alist) - articles.add(a); - - HeadlinesFragment hf = new HeadlinesFragment(feed, activeArticle, articles); - ArticlePager af = new ArticlePager(hf.getArticleById(article.id), hf.getAllArticles()); + HeadlinesFragment hf = new HeadlinesFragment(feed, activeArticle); + ArticlePager af = new ArticlePager(hf.getArticleById(article.id)); FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); @@ -147,7 +141,7 @@ private final String TAG = this.getClass().getSimpleName(); HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); - Fragment frag = new ArticlePager(article, hf.getAllArticles()); + Fragment frag = new ArticlePager(article); ft.replace(R.id.article_fragment, frag, FRAG_ARTICLE); //ft.addToBackStack(null); @@ -156,6 +150,7 @@ private final String TAG = this.getClass().getSimpleName(); } else { HeadlinesFragment hf = (HeadlinesFragment) getSupportFragmentManager().findFragmentByTag(FRAG_HEADLINES); if (hf != null) hf.setActiveArticle(article); + initMenu(); } } diff --git a/src/org/fox/ttrss/HeadlinesFragment.java b/src/org/fox/ttrss/HeadlinesFragment.java index 32b27331..8b087fa8 100644 --- a/src/org/fox/ttrss/HeadlinesFragment.java +++ b/src/org/fox/ttrss/HeadlinesFragment.java @@ -71,12 +71,11 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, private boolean m_canLoadMore = false; private boolean m_combinedMode = true; private String m_searchQuery = ""; - private boolean m_noRefresh = false; private SharedPreferences m_prefs; private ArticleListAdapter m_adapter; - private ArticleList m_articles = new ArticleList(); + private ArticleList m_articles = TinyApplication.getInstance().m_articles; private ArticleList m_selectedArticles = new ArticleList(); private HeadlinesEventListener m_listener; @@ -98,11 +97,9 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, m_feed = feed; } - public HeadlinesFragment(Feed feed, Article activeArticle, ArticleList articles) { + public HeadlinesFragment(Feed feed, Article activeArticle) { m_feed = feed; m_activeArticle = activeArticle; - m_articles = articles; - m_noRefresh = true; } public HeadlinesFragment() { @@ -268,7 +265,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, if (savedInstanceState != null) { m_feed = savedInstanceState.getParcelable("feed"); - m_articles = savedInstanceState.getParcelable("articles"); + //m_articles = savedInstanceState.getParcelable("articles"); m_activeArticle = savedInstanceState.getParcelable("activeArticle"); m_selectedArticles = savedInstanceState.getParcelable("selectedArticles"); m_canLoadMore = savedInstanceState.getBoolean("canLoadMore"); @@ -297,10 +294,10 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, @Override public void onResume() { super.onResume(); - - if (!m_noRefresh) { + + if (m_articles.size() == 0 || !m_feed.equals(TinyApplication.getInstance().m_feed)) { refresh(false); - m_noRefresh = false; + TinyApplication.getInstance().m_feed = m_feed; } m_activity.initMenu(); @@ -349,6 +346,10 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, final boolean isCat = m_feed.is_cat; int skip = 0; + if (!m_feed.equals(TinyApplication.getInstance())) { + append = false; + } + if (append) { for (Article a : m_articles) { if (a.unread) ++skip; @@ -393,7 +394,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, super.onSaveInstanceState(out); out.putParcelable("feed", m_feed); - out.putParcelable("articles", m_articles); + //out.putParcelable("articles", m_articles); out.putParcelable("activeArticle", m_activeArticle); out.putParcelable("selectedArticles", m_selectedArticles); out.putBoolean("canLoadMore", m_canLoadMore); diff --git a/src/org/fox/ttrss/TinyApplication.java b/src/org/fox/ttrss/TinyApplication.java new file mode 100644 index 00000000..135de75f --- /dev/null +++ b/src/org/fox/ttrss/TinyApplication.java @@ -0,0 +1,25 @@ +package org.fox.ttrss; + +import org.fox.ttrss.types.Article; +import org.fox.ttrss.types.ArticleList; +import org.fox.ttrss.types.Feed; + +import android.app.Application; + +public class TinyApplication extends Application { + private static TinyApplication m_singleton; + + public ArticleList m_articles = new ArticleList(); + public Feed m_feed; + public Article m_selectedArticle; + + public static TinyApplication getInstance(){ + return m_singleton; + } + + @Override + public final void onCreate() { + super.onCreate(); + m_singleton = this; + } +} diff --git a/src/org/fox/ttrss/types/Feed.java b/src/org/fox/ttrss/types/Feed.java index 91d12308..5227468f 100644 --- a/src/org/fox/ttrss/types/Feed.java +++ b/src/org/fox/ttrss/types/Feed.java @@ -28,6 +28,13 @@ public class Feed implements Comparable, Parcelable { } + public boolean equals(Feed feed) { + if (feed == this) + return true; + + return feed.id == this.id && (this.title == null || this.title.equals(feed.title)) && this.is_cat == feed.is_cat; + } + @Override public int compareTo(Feed feed) { if (feed.unread != this.unread) -- cgit v1.2.3-54-g00ecf 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 --- AndroidManifest.xml | 15 + 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 ++++++++ 19 files changed, 3354 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 'AndroidManifest.xml') diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 1d48a3be..5b17ba4f 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -47,6 +47,21 @@ android:name=".ArticleActivity" android:label="@string/app_name" > + + + + + + + + + 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