Merge remote-tracking branch 'remotes/cemrich/refactoring-NewsDetailFragment'
# Conflicts: # News-Android-App/src/main/java/de/luhmer/owncloudnewsreader/NewsDetailFragment.java
This commit is contained in:
commit
64a73121f9
7 changed files with 398 additions and 375 deletions
|
@ -21,7 +21,6 @@
|
|||
|
||||
package de.luhmer.owncloudnewsreader;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
|
@ -30,11 +29,7 @@ import android.content.pm.ResolveInfo;
|
|||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.customtabs.CustomTabsCallback;
|
||||
import android.support.customtabs.CustomTabsClient;
|
||||
import android.support.customtabs.CustomTabsIntent;
|
||||
import android.support.customtabs.CustomTabsServiceConnection;
|
||||
import android.support.customtabs.CustomTabsSession;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentPagerAdapter;
|
||||
|
@ -59,7 +54,6 @@ import java.util.Set;
|
|||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import de.luhmer.owncloudnewsreader.chrometabs.CustomTabActivityManager;
|
||||
import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm;
|
||||
import de.luhmer.owncloudnewsreader.database.DatabaseConnectionOrm.SORT_DIRECTION;
|
||||
import de.luhmer.owncloudnewsreader.database.model.RssItem;
|
||||
|
@ -239,18 +233,9 @@ public class NewsDetailActivity extends PodcastFragmentActivity {
|
|||
{
|
||||
NewsDetailFragment ndf = getNewsDetailFragmentAtPosition(currentPosition);//(NewsDetailFragment) getSupportFragmentManager().findFragmentByTag("android:switcher:" + R.id.pager + ":" + currentPosition);
|
||||
|
||||
if(ndf != null && ndf.mWebView != null)
|
||||
{
|
||||
if (ndf.urls.size() > 1) {
|
||||
ndf.urls.remove(0);
|
||||
ndf.mWebView.loadUrl(ndf.urls.get(0));
|
||||
return true;
|
||||
} else if(ndf.urls.size() == 1) {
|
||||
ndf.urls.remove(0);
|
||||
ndf.startLoadRssItemToWebViewTask();
|
||||
Log.v(TAG, "Load rssitem to webview again");
|
||||
return true;
|
||||
}
|
||||
if(ndf != null && ndf.canNavigateBack()) {
|
||||
ndf.navigateBack();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,60 +22,46 @@
|
|||
package de.luhmer.owncloudnewsreader;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.customtabs.CustomTabsIntent;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.text.format.DateUtils;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.webkit.ConsoleMessage;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebResourceRequest;
|
||||
import android.webkit.WebBackForwardList;
|
||||
import android.webkit.WebHistoryItem;
|
||||
import android.webkit.WebSettings;
|
||||
import android.webkit.WebView;
|
||||
import android.webkit.WebViewClient;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
import com.nostra13.universalimageloader.cache.disc.DiskCache;
|
||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||
|
||||
import org.apache.commons.lang3.StringEscapeUtils;
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import de.luhmer.owncloudnewsreader.database.model.Feed;
|
||||
import de.luhmer.owncloudnewsreader.adapter.ProgressBarWebChromeClient;
|
||||
import de.luhmer.owncloudnewsreader.async_tasks.RssItemToHtmlTask;
|
||||
import de.luhmer.owncloudnewsreader.database.model.RssItem;
|
||||
import de.luhmer.owncloudnewsreader.helper.AsyncTaskHelper;
|
||||
import de.luhmer.owncloudnewsreader.helper.ColorHelper;
|
||||
import de.luhmer.owncloudnewsreader.helper.ImageHandler;
|
||||
import de.luhmer.owncloudnewsreader.helper.ThemeChooser;
|
||||
|
||||
public class NewsDetailFragment extends Fragment {
|
||||
public static final String ARG_SECTION_NUMBER = "ARG_SECTION_NUMBER";
|
||||
public class NewsDetailFragment extends Fragment implements RssItemToHtmlTask.Listener {
|
||||
|
||||
public static final String ARG_SECTION_NUMBER = "ARG_SECTION_NUMBER";
|
||||
private static final String RSS_ITEM_PAGE_URL = "about:blank";
|
||||
|
||||
public final String TAG = getClass().getCanonicalName();
|
||||
|
||||
|
@ -87,7 +73,6 @@ public class NewsDetailFragment extends Fragment {
|
|||
|
||||
|
||||
private int section_number;
|
||||
public List<String> urls = new ArrayList<>();
|
||||
protected String html;
|
||||
|
||||
|
||||
|
@ -136,11 +121,32 @@ public class NewsDetailFragment extends Fragment {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true when calls to NewsDetailFragment#navigateBack()
|
||||
* can be processed right now
|
||||
* @see NewsDetailFragment#navigateBack()
|
||||
*/
|
||||
public boolean canNavigateBack() {
|
||||
return !isCurrentPageRssItem();
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigates back to the last displayed page. Call NewsDetailFragment#canNavigateBack()
|
||||
* to check if back navigation is possible right now. Use e.g. for back button handling.
|
||||
* @see NewsDetailFragment#navigateBack()
|
||||
*/
|
||||
public void navigateBack() {
|
||||
if (isLastPageRssItem()) {
|
||||
mWebView.clearHistory();
|
||||
startLoadRssItemToWebViewTask();
|
||||
} else if (!isCurrentPageRssItem()){
|
||||
mWebView.goBack();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View rootView = inflater.inflate(R.layout.fragment_news_detail, container, false);
|
||||
View rootView = inflater.inflate(R.layout.fragment_news_detail, container, false);
|
||||
|
||||
section_number = (Integer) getArguments().get(ARG_SECTION_NUMBER);
|
||||
|
||||
|
@ -151,50 +157,34 @@ public class NewsDetailFragment extends Fragment {
|
|||
return rootView;
|
||||
}
|
||||
|
||||
public void startLoadRssItemToWebViewTask() {
|
||||
AsyncTaskHelper.StartAsyncTask(new LoadRssItemToWebViewAsyncTask());
|
||||
private void startLoadRssItemToWebViewTask() {
|
||||
mWebView.setVisibility(View.GONE);
|
||||
mProgressBarLoading.setVisibility(View.VISIBLE);
|
||||
|
||||
NewsDetailActivity ndActivity = ((NewsDetailActivity)getActivity());
|
||||
if(background_color != Integer.MIN_VALUE && ThemeChooser.isDarkTheme(ndActivity))
|
||||
{
|
||||
mWebView.setBackgroundColor(background_color);
|
||||
ndActivity.mViewPager.setBackgroundColor(background_color);
|
||||
}
|
||||
|
||||
init_webView();
|
||||
|
||||
RssItem rssItem = ndActivity.rssItems.get(section_number);
|
||||
|
||||
RssItemToHtmlTask task = new RssItemToHtmlTask(ndActivity, rssItem, this);
|
||||
AsyncTaskHelper.StartAsyncTask(task);
|
||||
}
|
||||
|
||||
private class LoadRssItemToWebViewAsyncTask extends AsyncTask<Void, Void, String> {
|
||||
@Override
|
||||
public void onRssItemParsed(String htmlPage) {
|
||||
mWebView.setVisibility(View.VISIBLE);
|
||||
mProgressBarLoading.setVisibility(View.GONE);
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
NewsDetailActivity ndActivity = ((NewsDetailActivity)getActivity());
|
||||
setSoftwareRenderModeForWebView(htmlPage, mWebView);
|
||||
|
||||
if(background_color != Integer.MIN_VALUE && ThemeChooser.isDarkTheme(ndActivity))
|
||||
{
|
||||
mWebView.setBackgroundColor(background_color);
|
||||
ndActivity.mViewPager.setBackgroundColor(background_color);
|
||||
}
|
||||
|
||||
init_webView();
|
||||
|
||||
mWebView.setVisibility(View.GONE);
|
||||
mProgressBarLoading.setVisibility(View.VISIBLE);
|
||||
|
||||
super.onPreExecute();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doInBackground(Void... voids) {
|
||||
NewsDetailActivity ndActivity = ((NewsDetailActivity)getActivity());
|
||||
|
||||
RssItem rssItem = ndActivity.rssItems.get(section_number);
|
||||
|
||||
return getHtmlPage(ndActivity, rssItem, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String htmlPage) {
|
||||
mWebView.setVisibility(View.VISIBLE);
|
||||
mProgressBarLoading.setVisibility(View.GONE);
|
||||
|
||||
SetSoftwareRenderModeForWebView(htmlPage, mWebView);
|
||||
|
||||
html = htmlPage;
|
||||
mWebView.loadDataWithBaseURL("file:///android_asset/", htmlPage, "text/html", "UTF-8", "");
|
||||
super.onPostExecute(htmlPage);
|
||||
}
|
||||
html = htmlPage;
|
||||
mWebView.loadDataWithBaseURL("file:///android_asset/", htmlPage, "text/html", "UTF-8", RSS_ITEM_PAGE_URL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -202,17 +192,14 @@ public class NewsDetailFragment extends Fragment {
|
|||
* @param htmlPage
|
||||
* @param webView
|
||||
*/
|
||||
public static void SetSoftwareRenderModeForWebView(String htmlPage, WebView webView) {
|
||||
private void setSoftwareRenderModeForWebView(String htmlPage, WebView webView) {
|
||||
if (htmlPage.contains(".gif")) {
|
||||
webView.setLayerType(WebView.LAYER_TYPE_SOFTWARE, null);
|
||||
Log.v("NewsDetailFragment", "Using LAYER_TYPE_SOFTWARE");
|
||||
} else {
|
||||
//webView.setLayerType(WebView.LAYER_TYPE_HARDWARE, null);
|
||||
//Log.v("NewsDetailFragment", "Using LAYER_TYPE_HARDWARE");
|
||||
|
||||
if(webView.getLayerType() == WebView.LAYER_TYPE_HARDWARE) {
|
||||
if (webView.getLayerType() == WebView.LAYER_TYPE_HARDWARE) {
|
||||
Log.v("NewsDetailFragment", "Using LAYER_TYPE_HARDWARE");
|
||||
} else if (webView.getLayerType() == WebView.LAYER_TYPE_SOFTWARE){
|
||||
} else if (webView.getLayerType() == WebView.LAYER_TYPE_SOFTWARE) {
|
||||
Log.v("NewsDetailFragment", "Using LAYER_TYPE_SOFTWARE");
|
||||
} else {
|
||||
Log.v("NewsDetailFragment", "Using LAYER_TYPE_DEFAULT");
|
||||
|
@ -240,35 +227,7 @@ public class NewsDetailFragment extends Fragment {
|
|||
|
||||
registerForContextMenu(mWebView);
|
||||
|
||||
mWebView.setWebChromeClient(new WebChromeClient() {
|
||||
@Override
|
||||
public boolean onConsoleMessage(ConsoleMessage cm) {
|
||||
Log.v(TAG, cm.message() + " at " + cm.sourceId() + ":" + cm.lineNumber());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(WebView view, int progress) {
|
||||
if (progress < 100 && mProgressbarWebView.getVisibility() == ProgressBar.GONE) {
|
||||
mProgressbarWebView.setVisibility(ProgressBar.VISIBLE);
|
||||
}
|
||||
mProgressbarWebView.setProgress(progress);
|
||||
if (progress == 100) {
|
||||
mProgressbarWebView.setVisibility(ProgressBar.GONE);
|
||||
|
||||
//The following three lines are a workaround for websites which don't use a background color
|
||||
int bgColor = ContextCompat.getColor(getContext(), R.color.slider_listview_text_color_dark_theme);
|
||||
NewsDetailActivity ndActivity = ((NewsDetailActivity) getActivity());
|
||||
mWebView.setBackgroundColor(bgColor);
|
||||
ndActivity.mViewPager.setBackgroundColor(bgColor);
|
||||
|
||||
|
||||
if (ThemeChooser.isDarkTheme(getActivity())) {
|
||||
mWebView.setBackgroundColor(ContextCompat.getColor(getContext(), android.R.color.transparent));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
mWebView.setWebChromeClient(new ProgressBarWebChromeClient(mProgressbarWebView));
|
||||
|
||||
|
||||
mWebView.setWebViewClient(new WebViewClient() {
|
||||
|
@ -286,19 +245,17 @@ public class NewsDetailFragment extends Fragment {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onPageStarted(WebView view, String url, Bitmap favicon) {
|
||||
if (changedUrl) {
|
||||
changedUrl = false;
|
||||
public void onPageFinished(WebView view, String url) {
|
||||
super.onPageFinished(view, url);
|
||||
|
||||
if (!url.equals("file:///android_asset/") && (urls.isEmpty() || !urls.get(0).equals(url))) {
|
||||
urls.add(0, url);
|
||||
|
||||
Log.v(TAG, "Page finished (added): " + url);
|
||||
}
|
||||
}
|
||||
|
||||
super.onPageStarted(view, url, favicon);
|
||||
// the following lines are a workaround for websites which don't use a background color
|
||||
NewsDetailActivity ndActivity = ((NewsDetailActivity) getActivity());
|
||||
int backgroundColor = ColorHelper.getColorFromAttribute(getContext(),
|
||||
R.attr.news_detail_background_color);
|
||||
mWebView.setBackgroundColor(backgroundColor);
|
||||
ndActivity.mViewPager.setBackgroundColor(backgroundColor);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
mWebView.setOnTouchListener(new View.OnTouchListener() {
|
||||
|
@ -314,265 +271,101 @@ public class NewsDetailFragment extends Fragment {
|
|||
});
|
||||
}
|
||||
|
||||
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
if (!(view instanceof WebView))
|
||||
return;
|
||||
|
||||
WebView.HitTestResult result = ((WebView) view).getHitTestResult();
|
||||
if (result == null)
|
||||
return;
|
||||
|
||||
int type = result.getType();
|
||||
Document htmlDoc = Jsoup.parse(html);
|
||||
FragmentTransaction ft = getFragmentManager().beginTransaction();
|
||||
String text;
|
||||
DialogFragment newFragment;
|
||||
|
||||
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
|
||||
if (v instanceof WebView) {
|
||||
WebView.HitTestResult result = ((WebView) v).getHitTestResult();
|
||||
if (result != null) {
|
||||
int type = result.getType();
|
||||
switch (type) {
|
||||
case WebView.HitTestResult.IMAGE_TYPE:
|
||||
case WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE:
|
||||
String imageUrl = result.getExtra();
|
||||
|
||||
Document htmldoc = Jsoup.parse(html);
|
||||
if (imageUrl.startsWith("http") || imageUrl.startsWith("file")) {
|
||||
URL mImageUrl;
|
||||
String imgtitle;
|
||||
String imgaltval;
|
||||
String imgsrcval;
|
||||
|
||||
FragmentTransaction ft = getFragmentManager().beginTransaction();
|
||||
imgsrcval = imageUrl.substring(imageUrl.lastIndexOf('/') + 1, imageUrl.length());
|
||||
Elements imgtag = htmlDoc.getElementsByAttributeValueContaining("src", imageUrl);
|
||||
|
||||
if (type == WebView.HitTestResult.IMAGE_TYPE || type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) {
|
||||
String imageUrl = result.getExtra();
|
||||
if (imageUrl.startsWith("http") || imageUrl.startsWith("file")) {
|
||||
|
||||
URL mImageUrl;
|
||||
String imgtitle;
|
||||
String imgaltval;
|
||||
String imgsrcval;
|
||||
|
||||
imgsrcval = imageUrl.substring(imageUrl.lastIndexOf('/') + 1, imageUrl.length());
|
||||
Elements imgtag = htmldoc.getElementsByAttributeValueContaining("src", imageUrl);
|
||||
|
||||
try {
|
||||
imgtitle = imgtag.first().attr("title");
|
||||
} catch (NullPointerException e) {
|
||||
imgtitle = "";
|
||||
}
|
||||
try {
|
||||
imgaltval = imgtag.first().attr("alt");
|
||||
} catch (NullPointerException e) {
|
||||
imgaltval = "";
|
||||
}
|
||||
try {
|
||||
mImageUrl = new URL(imageUrl);
|
||||
} catch (MalformedURLException e) {
|
||||
return;
|
||||
}
|
||||
|
||||
String title = imgsrcval;
|
||||
int titleIcon = android.R.drawable.ic_menu_gallery;
|
||||
String text = (imgtitle.isEmpty()) ? imgaltval : imgtitle;
|
||||
|
||||
// Create and show the dialog.
|
||||
DialogFragment newFragment =
|
||||
NewsDetailImageDialogFragment.newInstanceImage(title, titleIcon, text, mImageUrl);
|
||||
newFragment.show(ft, "menu_fragment_dialog");
|
||||
}
|
||||
}
|
||||
else if (type == WebView.HitTestResult.SRC_ANCHOR_TYPE) {
|
||||
String url = result.getExtra();
|
||||
URL mUrl;
|
||||
String text;
|
||||
try {
|
||||
Elements urltag = htmldoc.getElementsByAttributeValueContaining("href", url);
|
||||
text = urltag.text();
|
||||
mUrl = new URL(url);
|
||||
imgtitle = imgtag.first().attr("title");
|
||||
} catch (NullPointerException e) {
|
||||
imgtitle = "";
|
||||
}
|
||||
try {
|
||||
imgaltval = imgtag.first().attr("alt");
|
||||
} catch (NullPointerException e) {
|
||||
imgaltval = "";
|
||||
}
|
||||
try {
|
||||
mImageUrl = new URL(imageUrl);
|
||||
} catch (MalformedURLException e) {
|
||||
return;
|
||||
}
|
||||
|
||||
String title = imgsrcval;
|
||||
int titleIcon = android.R.drawable.ic_menu_gallery;
|
||||
text = (imgtitle.isEmpty()) ? imgaltval : imgtitle;
|
||||
|
||||
// Create and show the dialog.
|
||||
DialogFragment newFragment =
|
||||
NewsDetailImageDialogFragment.newInstanceUrl(text, mUrl.toString());
|
||||
newFragment = NewsDetailImageDialogFragment.newInstanceImage(title, titleIcon, text, mImageUrl);
|
||||
newFragment.show(ft, "menu_fragment_dialog");
|
||||
}
|
||||
//else if (type == WebView.HitTestResult.EMAIL_TYPE) { }
|
||||
//else if (type == WebView.HitTestResult.GEO_TYPE) { }
|
||||
//else if (type == WebView.HitTestResult.PHONE_TYPE) { }
|
||||
//else if (type == WebView.HitTestResult.EDIT_TEXT_TYPE) { }
|
||||
}
|
||||
break;
|
||||
|
||||
case WebView.HitTestResult.SRC_ANCHOR_TYPE:
|
||||
String url = result.getExtra();
|
||||
URL mUrl;
|
||||
try {
|
||||
Elements urltag = htmlDoc.getElementsByAttributeValueContaining("href", url);
|
||||
text = urltag.text();
|
||||
mUrl = new URL(url);
|
||||
} catch (MalformedURLException e) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create and show the dialog.
|
||||
newFragment = NewsDetailImageDialogFragment.newInstanceUrl(text, mUrl.toString());
|
||||
newFragment.show(ft, "menu_fragment_dialog");
|
||||
break;
|
||||
case WebView.HitTestResult.EMAIL_TYPE:
|
||||
case WebView.HitTestResult.GEO_TYPE:
|
||||
case WebView.HitTestResult.PHONE_TYPE:
|
||||
case WebView.HitTestResult.EDIT_TEXT_TYPE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@SuppressLint("SimpleDateFormat")
|
||||
public static String getHtmlPage(Context context, RssItem rssItem, boolean showHeader)
|
||||
{
|
||||
String feedTitle = "Undefined";
|
||||
String favIconUrl = null;
|
||||
|
||||
Feed feed = rssItem.getFeed();
|
||||
int[] colors = ColorHelper.getColorsFromAttributes(context,
|
||||
R.attr.dividerLineColor,
|
||||
R.attr.rssItemListBackground);
|
||||
int feedColor = colors[0];
|
||||
if(feed != null) {
|
||||
feedTitle = StringEscapeUtils.escapeHtml4(feed.getFeedTitle());
|
||||
favIconUrl = feed.getFaviconUrl();
|
||||
if(feed.getAvgColour() != null)
|
||||
feedColor = Integer.parseInt(feed.getAvgColour());
|
||||
}
|
||||
|
||||
if(favIconUrl != null)
|
||||
{
|
||||
DiskCache diskCache = ImageLoader.getInstance().getDiskCache();
|
||||
File file = diskCache.get(favIconUrl);
|
||||
if(file != null)
|
||||
favIconUrl = "file://" + file.getAbsolutePath();
|
||||
} else {
|
||||
favIconUrl = "file:///android_res/drawable/default_feed_icon_light.png";
|
||||
}
|
||||
|
||||
String body_id;
|
||||
if(ThemeChooser.isDarkTheme(context)) {
|
||||
body_id = "darkTheme";
|
||||
} else {
|
||||
body_id = "lightTheme";
|
||||
}
|
||||
|
||||
boolean isRightToLeft = context.getResources().getBoolean(R.bool.is_right_to_left);
|
||||
String rtlClass = isRightToLeft ? "rtl" : "";
|
||||
String borderSide = isRightToLeft ? "right" : "left";
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.append("<html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=0\" />");
|
||||
builder.append("<link rel=\"stylesheet\" type=\"text/css\" href=\"web.css\" />");
|
||||
builder.append("<style type=\"text/css\">");
|
||||
builder.append(String.format(
|
||||
"#top_section { border-%s: 4px solid %s; border-bottom: 1px solid %s; background: %s }",
|
||||
borderSide,
|
||||
ColorHelper.getCssColor(feedColor),
|
||||
ColorHelper.getCssColor(colors[0]),
|
||||
ColorHelper.getCssColor(colors[1]))
|
||||
);
|
||||
builder.append("</style>");
|
||||
builder.append(String.format("</head><body id=\"%s\" class=\"%s\">", body_id, rtlClass));
|
||||
|
||||
if(showHeader) {
|
||||
builder.append("<div id=\"top_section\">");
|
||||
builder.append("<div id=\"header\">");
|
||||
String title = StringEscapeUtils.escapeHtml4(rssItem.getTitle());
|
||||
String linkToFeed = StringEscapeUtils.escapeHtml4(rssItem.getLink());
|
||||
builder.append(String.format("<a href=\"%s\">%s</a>", linkToFeed, title));
|
||||
builder.append("</div>");
|
||||
|
||||
String authorOfArticle = StringEscapeUtils.escapeHtml4(rssItem.getAuthor());
|
||||
if (authorOfArticle != null)
|
||||
if (!authorOfArticle.trim().equals(""))
|
||||
feedTitle += " - " + authorOfArticle.trim();
|
||||
|
||||
builder.append("<div id=\"header_small_text\">");
|
||||
|
||||
builder.append("<div id=\"subscription\">");
|
||||
builder.append(String.format("<img id=\"imgFavicon\" src=\"%s\" />", favIconUrl));
|
||||
builder.append(feedTitle.trim());
|
||||
builder.append("</div>");
|
||||
|
||||
Date date = rssItem.getPubDate();
|
||||
if (date != null) {
|
||||
String dateString = (String) DateUtils.getRelativeTimeSpanString(date.getTime());
|
||||
builder.append("<div id=\"datetime\">");
|
||||
builder.append(dateString);
|
||||
builder.append("</div>");
|
||||
}
|
||||
|
||||
builder.append("</div>");
|
||||
|
||||
builder.append("</div>");
|
||||
}
|
||||
|
||||
String description = rssItem.getBody();
|
||||
description = getDescriptionWithCachedImages(description).trim();
|
||||
//StopWatch stopWatch = new StopWatch();
|
||||
// stopWatch.start();
|
||||
description = removePreloadAttributeFromVideos(description);
|
||||
//stopWatch.stop();
|
||||
//Log.d("NewsDetailFragment", "Time needed for removing preload attribute: " + stopWatch.toString() + " - " + feedTitle);
|
||||
|
||||
builder.append("<div id=\"content\">");
|
||||
builder.append(description);
|
||||
builder.append("</div>");
|
||||
|
||||
builder.append("</body></html>");
|
||||
|
||||
String htmlData = builder.toString().replaceAll("\"//", "\"https://");
|
||||
|
||||
return htmlData;
|
||||
}
|
||||
|
||||
|
||||
private static Pattern PATTERN_PRELOAD_VIDEOS = Pattern.compile("(<video[^>]*)(preload=\".*?\")");
|
||||
private static String removePreloadAttributeFromVideos(String text) {
|
||||
Matcher m = PATTERN_PRELOAD_VIDEOS.matcher(text);
|
||||
if(m.find()) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
do {
|
||||
//$1 represents the 1st group
|
||||
m.appendReplacement(sb, "$1" + "preload=\"none\"");
|
||||
} while (m.find());
|
||||
m.appendTail(sb);
|
||||
text = sb.toString();
|
||||
}
|
||||
return text;
|
||||
/**
|
||||
* @return true when the last page on the webview's history stack is
|
||||
* the original rss item page
|
||||
*/
|
||||
private boolean isLastPageRssItem() {
|
||||
WebBackForwardList list = mWebView.copyBackForwardList();
|
||||
WebHistoryItem lastItem = list.getItemAtIndex(list.getCurrentIndex() - 1);
|
||||
return lastItem != null && lastItem.getUrl().equals(RSS_ITEM_PAGE_URL);
|
||||
}
|
||||
|
||||
private static String getDescriptionWithCachedImages(String text)
|
||||
{
|
||||
List<String> links = ImageHandler.getImageLinksFromText(text);
|
||||
DiskCache diskCache = ImageLoader.getInstance().getDiskCache();
|
||||
|
||||
for(String link : links)
|
||||
{
|
||||
link = link.trim();
|
||||
try
|
||||
{
|
||||
File file = diskCache.get(link);
|
||||
if(file != null)
|
||||
text = text.replace(link, "file://" + file.getAbsolutePath());
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static String getTextFromAssets(String fileName, Context context) {
|
||||
InputStream input;
|
||||
try {
|
||||
input = context.getAssets().open(fileName);
|
||||
int size = input.available();
|
||||
byte[] buffer = new byte[size];
|
||||
input.read(buffer);
|
||||
input.close();
|
||||
|
||||
// byte buffer into a string
|
||||
return new String(buffer);
|
||||
} catch(Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return "";
|
||||
/**
|
||||
* @return true when the current page on the webview's history stack is
|
||||
* the original rss item page
|
||||
*/
|
||||
private boolean isCurrentPageRssItem() {
|
||||
String currentPageUrl = mWebView.copyBackForwardList().getCurrentItem().getOriginalUrl();
|
||||
return currentPageUrl.equals("data:text/html;charset=utf-8;base64,");
|
||||
//return currentPageUrl.equals(RSS_ITEM_PAGE_URL);
|
||||
}
|
||||
|
||||
private static String SearchString(String data, String startString, String endString)
|
||||
{
|
||||
int start = data.indexOf(startString) + startString.length();
|
||||
int end = data.indexOf(endString, start);
|
||||
if(start != (-1 + startString.length()) && end != -1)
|
||||
data = data.substring(start, end).trim();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private static String convertHexColorFrom3To6Characters(String color)
|
||||
{
|
||||
for(int i = 1; i < 6; i += 2)
|
||||
color = color.substring(0, i) + color.charAt(i) + color.substring(i);
|
||||
|
||||
return color;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -195,9 +195,9 @@ public class NewsDetailImageDialogFragment extends DialogFragment {
|
|||
|
||||
View v = inflater.inflate(R.layout.fragment_dialog_image, container, false);
|
||||
|
||||
TextView tvTitle = (TextView) v.findViewById(R.id.ic_menu_title);
|
||||
TextView tvText = (TextView) v.findViewById(R.id.ic_menu_item_text);
|
||||
ImageView imgTitle = (ImageView) v.findViewById(R.id.ic_menu_gallery);
|
||||
TextView tvTitle = v.findViewById(R.id.ic_menu_title);
|
||||
TextView tvText = v.findViewById(R.id.ic_menu_item_text);
|
||||
ImageView imgTitle = v.findViewById(R.id.ic_menu_gallery);
|
||||
|
||||
tvTitle.setText(mDialogTitle);
|
||||
tvText.setText(mDialogText);
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package de.luhmer.owncloudnewsreader.adapter;
|
||||
|
||||
import android.util.Log;
|
||||
import android.webkit.ConsoleMessage;
|
||||
import android.webkit.WebChromeClient;
|
||||
import android.webkit.WebView;
|
||||
import android.widget.ProgressBar;
|
||||
|
||||
/**
|
||||
* A very simple WebChromeClient which sets the status of a given
|
||||
* ProgressBar instance while loading. The ProgressBar instance will
|
||||
* only be visible during loading.
|
||||
*/
|
||||
public class ProgressBarWebChromeClient extends WebChromeClient {
|
||||
|
||||
public final String TAG = getClass().getCanonicalName();
|
||||
|
||||
private ProgressBar mProgressBar;
|
||||
|
||||
public ProgressBarWebChromeClient(ProgressBar progressBar) {
|
||||
mProgressBar = progressBar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onConsoleMessage(ConsoleMessage cm) {
|
||||
Log.v(TAG, cm.message() + " at " + cm.sourceId() + ":" + cm.lineNumber());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(WebView view, int progress) {
|
||||
mProgressBar.setProgress(progress);
|
||||
|
||||
if (progress < 100 && mProgressBar.getVisibility() == ProgressBar.GONE) {
|
||||
mProgressBar.setVisibility(ProgressBar.VISIBLE);
|
||||
} else if (progress == 100) {
|
||||
mProgressBar.setVisibility(ProgressBar.GONE);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,9 +26,9 @@ import org.greenrobot.eventbus.Subscribe;
|
|||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
import de.luhmer.owncloudnewsreader.NewsDetailFragment;
|
||||
import de.luhmer.owncloudnewsreader.R;
|
||||
import de.luhmer.owncloudnewsreader.SettingsActivity;
|
||||
import de.luhmer.owncloudnewsreader.async_tasks.RssItemToHtmlTask;
|
||||
import de.luhmer.owncloudnewsreader.database.model.RssItem;
|
||||
import de.luhmer.owncloudnewsreader.helper.ColorHelper;
|
||||
import de.luhmer.owncloudnewsreader.helper.FavIconHandler;
|
||||
|
@ -243,7 +243,7 @@ public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickL
|
|||
favIconHandler.loadFavIconForFeed(favIconUrl, imgViewFavIcon);
|
||||
|
||||
if(webView_body != null) {
|
||||
String htmlPage = NewsDetailFragment.getHtmlPage(itemView.getContext(),rssItem,false);
|
||||
String htmlPage = RssItemToHtmlTask.getHtmlPage(itemView.getContext(), rssItem, false);
|
||||
webView_body.loadDataWithBaseURL("file:///android_asset/", htmlPage, "text/html", "UTF-8", "");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,199 @@
|
|||
package de.luhmer.owncloudnewsreader.async_tasks;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.text.format.DateUtils;
|
||||
|
||||
import com.nostra13.universalimageloader.cache.disc.DiskCache;
|
||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||
|
||||
import org.apache.commons.lang3.StringEscapeUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import de.luhmer.owncloudnewsreader.R;
|
||||
import de.luhmer.owncloudnewsreader.database.model.Feed;
|
||||
import de.luhmer.owncloudnewsreader.database.model.RssItem;
|
||||
import de.luhmer.owncloudnewsreader.helper.ColorHelper;
|
||||
import de.luhmer.owncloudnewsreader.helper.ImageHandler;
|
||||
import de.luhmer.owncloudnewsreader.helper.ThemeChooser;
|
||||
|
||||
|
||||
public class RssItemToHtmlTask extends AsyncTask<Void, Void, String> {
|
||||
|
||||
public interface Listener {
|
||||
/**
|
||||
* The RSS item has successfully been parsed.
|
||||
* @param htmlPage RSS item as HTML string
|
||||
*/
|
||||
void onRssItemParsed(String htmlPage);
|
||||
}
|
||||
|
||||
|
||||
private Context mContext;
|
||||
private RssItem mRssItem;
|
||||
private Listener mListener;
|
||||
|
||||
|
||||
public RssItemToHtmlTask(Context context, RssItem rssItem, Listener listener) {
|
||||
this.mContext = context;
|
||||
this.mRssItem = rssItem;
|
||||
this.mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String doInBackground(Void... params) {
|
||||
return getHtmlPage(mContext, mRssItem, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(String htmlPage) {
|
||||
mListener.onRssItemParsed(htmlPage);
|
||||
super.onPostExecute(htmlPage);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param context
|
||||
* @param rssItem item to parse
|
||||
* @param showHeader true if a header with item title, feed title, etc. should be included
|
||||
* @return given RSS item as full HTML page
|
||||
*/
|
||||
public static String getHtmlPage(Context context, RssItem rssItem, boolean showHeader) {
|
||||
String feedTitle = "Undefined";
|
||||
String favIconUrl = null;
|
||||
|
||||
Feed feed = rssItem.getFeed();
|
||||
int[] colors = ColorHelper.getColorsFromAttributes(context,
|
||||
R.attr.dividerLineColor,
|
||||
R.attr.rssItemListBackground);
|
||||
|
||||
int feedColor = colors[0];
|
||||
if (feed != null) {
|
||||
feedTitle = StringEscapeUtils.escapeHtml4(feed.getFeedTitle());
|
||||
favIconUrl = feed.getFaviconUrl();
|
||||
if(feed.getAvgColour() != null) {
|
||||
feedColor = Integer.parseInt(feed.getAvgColour());
|
||||
}
|
||||
}
|
||||
|
||||
if (favIconUrl != null) {
|
||||
DiskCache diskCache = ImageLoader.getInstance().getDiskCache();
|
||||
File file = diskCache.get(favIconUrl);
|
||||
if(file != null) {
|
||||
favIconUrl = "file://" + file.getAbsolutePath();
|
||||
}
|
||||
} else {
|
||||
favIconUrl = "file:///android_res/drawable/default_feed_icon_light.png";
|
||||
}
|
||||
|
||||
String body_id;
|
||||
if (ThemeChooser.isDarkTheme(context)) {
|
||||
body_id = "darkTheme";
|
||||
} else {
|
||||
body_id = "lightTheme";
|
||||
}
|
||||
|
||||
boolean isRightToLeft = context.getResources().getBoolean(R.bool.is_right_to_left);
|
||||
String rtlClass = isRightToLeft ? "rtl" : "";
|
||||
String borderSide = isRightToLeft ? "right" : "left";
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
builder.append("<html><head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=0\" />");
|
||||
builder.append("<link rel=\"stylesheet\" type=\"text/css\" href=\"web.css\" />");
|
||||
builder.append("<style type=\"text/css\">");
|
||||
builder.append(String.format(
|
||||
"#top_section { border-%s: 4px solid %s; border-bottom: 1px solid %s; background: %s }",
|
||||
borderSide,
|
||||
ColorHelper.getCssColor(feedColor),
|
||||
ColorHelper.getCssColor(colors[0]),
|
||||
ColorHelper.getCssColor(colors[1]))
|
||||
);
|
||||
builder.append("</style>");
|
||||
builder.append(String.format("</head><body id=\"%s\" class=\"%s\">", body_id, rtlClass));
|
||||
|
||||
if (showHeader) {
|
||||
builder.append("<div id=\"top_section\">");
|
||||
builder.append("<div id=\"header\">");
|
||||
String title = StringEscapeUtils.escapeHtml4(rssItem.getTitle());
|
||||
String linkToFeed = StringEscapeUtils.escapeHtml4(rssItem.getLink());
|
||||
builder.append(String.format("<a href=\"%s\">%s</a>", linkToFeed, title));
|
||||
builder.append("</div>");
|
||||
|
||||
String authorOfArticle = StringEscapeUtils.escapeHtml4(rssItem.getAuthor());
|
||||
if (authorOfArticle != null)
|
||||
if (!authorOfArticle.trim().equals(""))
|
||||
feedTitle += " - " + authorOfArticle.trim();
|
||||
|
||||
builder.append("<div id=\"header_small_text\">");
|
||||
|
||||
builder.append("<div id=\"subscription\">");
|
||||
builder.append(String.format("<img id=\"imgFavicon\" src=\"%s\" />", favIconUrl));
|
||||
builder.append(feedTitle.trim());
|
||||
builder.append("</div>");
|
||||
|
||||
Date date = rssItem.getPubDate();
|
||||
if (date != null) {
|
||||
String dateString = (String) DateUtils.getRelativeTimeSpanString(date.getTime());
|
||||
builder.append("<div id=\"datetime\">");
|
||||
builder.append(dateString);
|
||||
builder.append("</div>");
|
||||
}
|
||||
|
||||
builder.append("</div>");
|
||||
|
||||
builder.append("</div>");
|
||||
}
|
||||
|
||||
String description = rssItem.getBody();
|
||||
|
||||
description = getDescriptionWithCachedImages(description).trim();
|
||||
description = removePreloadAttributeFromVideos(description);
|
||||
|
||||
builder.append("<div id=\"content\">");
|
||||
builder.append(description);
|
||||
builder.append("</div>");
|
||||
|
||||
builder.append("</body></html>");
|
||||
|
||||
return builder.toString().replaceAll("\"//", "\"https://");
|
||||
}
|
||||
|
||||
private static String getDescriptionWithCachedImages(String text) {
|
||||
List<String> links = ImageHandler.getImageLinksFromText(text);
|
||||
DiskCache diskCache = ImageLoader.getInstance().getDiskCache();
|
||||
|
||||
for(String link : links) {
|
||||
link = link.trim();
|
||||
try {
|
||||
File file = diskCache.get(link);
|
||||
if(file != null)
|
||||
text = text.replace(link, "file://" + file.getAbsolutePath());
|
||||
} catch(Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
private static Pattern PATTERN_PRELOAD_VIDEOS = Pattern.compile("(<video[^>]*)(preload=\".*?\")");
|
||||
private static String removePreloadAttributeFromVideos(String text) {
|
||||
Matcher m = PATTERN_PRELOAD_VIDEOS.matcher(text);
|
||||
if(m.find()) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
do {
|
||||
//$1 represents the 1st group
|
||||
m.appendReplacement(sb, "$1" + "preload=\"none\"");
|
||||
} while (m.find());
|
||||
m.appendTail(sb);
|
||||
text = sb.toString();
|
||||
}
|
||||
return text;
|
||||
}
|
||||
}
|
|
@ -22,6 +22,7 @@
|
|||
package de.luhmer.owncloudnewsreader.helper;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
|
||||
import com.nostra13.universalimageloader.utils.StorageUtils;
|
||||
|
||||
|
@ -87,4 +88,9 @@ public class FileUtils {
|
|||
{
|
||||
return getPath(context) + "/podcasts";
|
||||
}
|
||||
|
||||
public static boolean isExternalStorageWritable() {
|
||||
String state = Environment.getExternalStorageState();
|
||||
return Environment.MEDIA_MOUNTED.equals(state);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue