diff options
13 files changed, 328 insertions, 432 deletions
diff --git a/org.fox.ttrss/org.fox.ttrss.iml b/org.fox.ttrss/org.fox.ttrss.iml index f473df1f..be2e9277 100755 --- a/org.fox.ttrss/org.fox.ttrss.iml +++ b/org.fox.ttrss/org.fox.ttrss.iml @@ -12,10 +12,12 @@ <option name="SELECTED_TEST_ARTIFACT" value="_android_test_" /> <option name="ASSEMBLE_TASK_NAME" value="assembleDebug" /> <option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" /> - <option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" /> <option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugTest" /> <option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileDebugTestSources" /> - <option name="TEST_SOURCE_GEN_TASK_NAME" value="generateDebugTestSources" /> + <afterSyncTasks> + <task>generateDebugSources</task> + <task>generateDebugTestSources</task> + </afterSyncTasks> <option name="ALLOW_USER_CONFIGURATION" value="false" /> <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" /> <option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" /> @@ -24,7 +26,7 @@ </configuration> </facet> </component> - <component name="NewModuleRootManager" inherit-compiler-output="false"> + <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false"> <output url="file://$MODULE_DIR$/build/intermediates/classes/debug" /> <output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" /> <exclude-output /> diff --git a/org.fox.ttrss/src/main/AndroidManifest.xml b/org.fox.ttrss/src/main/AndroidManifest.xml index e87d2ade..0838d385 100755 --- a/org.fox.ttrss/src/main/AndroidManifest.xml +++ b/org.fox.ttrss/src/main/AndroidManifest.xml @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.fox.ttrss" - android:versionCode="369" - android:versionName="1.142" > + android:versionCode="373" + android:versionName="1.146" > <uses-sdk android:minSdkVersion="15" diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/ApiRequest.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/ApiRequest.java index e603b989..03a2769f 100644 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/ApiRequest.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/ApiRequest.java @@ -51,20 +51,21 @@ public class ApiRequest extends AsyncTask<HashMap<String,String>, Integer, JsonE protected boolean m_canUseProgress = false; protected Context m_context; private SharedPreferences m_prefs; - + protected String m_lastErrorMessage; + protected ApiError m_lastError; public ApiRequest(Context context) { m_context = context; m_prefs = PreferenceManager.getDefaultSharedPreferences(m_context); - + m_api = m_prefs.getString("ttrss_url", "").trim(); m_transportDebugging = m_prefs.getBoolean("transport_debugging", false); m_lastError = ApiError.NO_ERROR; - + } - + @SuppressLint("NewApi") @SuppressWarnings("unchecked") public void execute(HashMap<String,String> map) { @@ -73,7 +74,7 @@ public class ApiRequest extends AsyncTask<HashMap<String,String>, Integer, JsonE else super.execute(map); } - + public int getErrorMessage() { switch (m_lastError) { case NO_ERROR: @@ -117,7 +118,7 @@ public class ApiRequest extends AsyncTask<HashMap<String,String>, Integer, JsonE return R.string.error_unknown; } } - + @Override protected JsonElement doInBackground(HashMap<String, String>... params) { @@ -125,12 +126,12 @@ public class ApiRequest extends AsyncTask<HashMap<String,String>, Integer, JsonE m_lastError = ApiError.NETWORK_UNAVAILABLE; return null; } - + Gson gson = new Gson(); - + String requestStr = gson.toJson(new HashMap<String,String>(params[0])); byte[] postData = null; - + try { postData = requestStr.getBytes("UTF-8"); } catch (UnsupportedEncodingException e) { @@ -138,50 +139,50 @@ public class ApiRequest extends AsyncTask<HashMap<String,String>, Integer, JsonE e.printStackTrace(); return null; } - + /* disableConnectionReuseIfNecessary(); */ - + if (m_transportDebugging) Log.d(TAG, ">>> (" + requestStr + ") " + m_api); - + /* ApiRequest.trustAllHosts(m_prefs.getBoolean("ssl_trust_any", false), - m_prefs.getBoolean("ssl_trust_any_host", false)); */ - + m_prefs.getBoolean("ssl_trust_any_host", false)); */ + URL url; - + try { - url = new URL(m_api + "/api/"); + url = new URL(m_api + "/api/"); } catch (Exception e) { m_lastError = ApiError.INVALID_URL; e.printStackTrace(); return null; } - - try { + + try { HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - + String httpLogin = m_prefs.getString("http_login", "").trim(); String httpPassword = m_prefs.getString("http_password", "").trim(); - + if (httpLogin.length() > 0) { if (m_transportDebugging) Log.d(TAG, "Using HTTP Basic authentication."); - - conn.setRequestProperty("Authorization", "Basic " + - Base64.encodeToString((httpLogin + ":" + httpPassword).getBytes("UTF-8"), Base64.NO_WRAP)); + + conn.setRequestProperty("Authorization", "Basic " + + Base64.encodeToString((httpLogin + ":" + httpPassword).getBytes("UTF-8"), Base64.NO_WRAP)); } - - conn.setDoInput(true); - conn.setDoOutput(true); - conn.setUseCaches(false); - conn.setRequestMethod("POST"); + + conn.setDoInput(true); + conn.setDoOutput(true); + conn.setUseCaches(false); + conn.setRequestMethod("POST"); conn.setRequestProperty("Content-Length", Integer.toString(postData.length)); OutputStream out = conn.getOutputStream(); out.write(postData); out.close(); - + m_responseCode = conn.getResponseCode(); m_responseMessage = conn.getResponseMessage(); - + switch (m_responseCode) { case HttpURLConnection.HTTP_OK: StringBuffer response = new StringBuffer(); @@ -193,31 +194,31 @@ public class ApiRequest extends AsyncTask<HashMap<String,String>, Integer, JsonE int contentLength = conn.getHeaderFieldInt("Api-Content-Length", -1); m_canUseProgress = (contentLength != -1); - + while ((read = in.read(buf)) >= 0) { response.append(buf, 0, read); total += read; publishProgress(Integer.valueOf(total), Integer.valueOf(contentLength)); } - + if (m_transportDebugging) Log.d(TAG, "<<< " + response); - + JsonParser parser = new JsonParser(); - + JsonElement result = parser.parse(response.toString()); JsonObject resultObj = result.getAsJsonObject(); - + m_apiStatusCode = resultObj.get("status").getAsInt(); - + conn.disconnect(); - + switch (m_apiStatusCode) { case API_STATUS_OK: return result.getAsJsonObject().get("content"); case API_STATUS_ERR: JsonObject contentObj = resultObj.get("content").getAsJsonObject(); String error = contentObj.get("error").getAsString(); - + if (error.equals("LOGIN_ERROR")) { m_lastError = ApiError.LOGIN_FAILED; } else if (error.equals("API_DISABLED")) { @@ -231,7 +232,7 @@ public class ApiRequest extends AsyncTask<HashMap<String,String>, Integer, JsonE } else { Log.d(TAG, "Unknown API error: " + error); m_lastError = ApiError.API_UNKNOWN; - } + } } return null; @@ -252,27 +253,31 @@ public class ApiRequest extends AsyncTask<HashMap<String,String>, Integer, JsonE m_lastError = ApiError.HTTP_OTHER_ERROR; break; } - + conn.disconnect(); return null; } catch (javax.net.ssl.SSLPeerUnverifiedException e) { m_lastError = ApiError.SSL_REJECTED; + m_lastErrorMessage = e.getMessage(); e.printStackTrace(); } catch (IOException e) { m_lastError = ApiError.IO_ERROR; + m_lastErrorMessage = e.getMessage(); if (e.getMessage() != null) { if (e.getMessage().matches("Hostname [^ ]+ was not verified")) { m_lastError = ApiError.SSL_HOSTNAME_REJECTED; } } - + e.printStackTrace(); } catch (com.google.gson.JsonSyntaxException e) { m_lastError = ApiError.PARSE_ERROR; + m_lastErrorMessage = e.getMessage(); e.printStackTrace(); } catch (Exception e) { m_lastError = ApiError.OTHER_ERROR; + m_lastErrorMessage = e.getMessage(); e.printStackTrace(); } diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/FeedCategoriesFragment.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/FeedCategoriesFragment.java index 1ff6aa1d..02fd7985 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/FeedCategoriesFragment.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/FeedCategoriesFragment.java @@ -381,7 +381,13 @@ public class FeedCategoriesFragment extends BaseFeedlistFragment implements OnIt if (m_lastError == ApiError.LOGIN_FAILED) { m_activity.login(true); } else { - m_activity.toast(getErrorMessage()); + + if (m_lastErrorMessage != null) { + m_activity.toast(getString(getErrorMessage()) + "\n" + m_lastErrorMessage); + } else { + m_activity.toast(getErrorMessage()); + } + //m_activity.setLoadingStatus(getErrorMessage(), false); } } diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/FeedsFragment.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/FeedsFragment.java index 8bd241e6..41c0f69c 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/FeedsFragment.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/FeedsFragment.java @@ -570,7 +570,13 @@ public class FeedsFragment extends BaseFeedlistFragment implements OnItemClickLi if (m_lastError == ApiError.LOGIN_FAILED) { m_activity.login(true); } else { - m_activity.toast(getErrorMessage()); + + if (m_lastErrorMessage != null) { + m_activity.toast(getString(getErrorMessage()) + "\n" + m_lastErrorMessage); + } else { + m_activity.toast(getErrorMessage()); + } + //m_activity.setLoadingStatus(getErrorMessage(), false); } } diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/HeadlinesFragment.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/HeadlinesFragment.java index a562a33f..a7099ee3 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/HeadlinesFragment.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/HeadlinesFragment.java @@ -69,8 +69,6 @@ import org.fox.ttrss.types.ArticleList; import org.fox.ttrss.types.Feed; import org.fox.ttrss.util.HeadlinesRequest; import org.jsoup.Jsoup; -import org.jsoup.nodes.Element; -import org.jsoup.select.Elements; import java.text.DateFormat; import java.text.SimpleDateFormat; @@ -79,8 +77,6 @@ import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.TimeZone; -import java.util.regex.Matcher; -import java.util.regex.Pattern; public class HeadlinesFragment extends Fragment implements OnItemClickListener, OnScrollListener { public static enum ArticlesSelection { ALL, NONE, UNREAD } @@ -565,7 +561,13 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, if (m_lastError == ApiError.LOGIN_FAILED) { m_activity.login(true); } else { - m_activity.toast(getErrorMessage()); + + if (m_lastErrorMessage != null) { + m_activity.toast(getString(getErrorMessage()) + "\n" + m_lastErrorMessage); + } else { + m_activity.toast(getErrorMessage()); + } + //m_activity.setLoadingStatus(getErrorMessage(), false); } } @@ -688,7 +690,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, public ImageView textChecked; public View headlineHeader; public View topChangedMessage; - + public int position; public boolean flavorImageEmbedded; } @@ -776,30 +778,29 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, } } - private void updateTextCheckedState(final HeadlineViewHolder holder, Article item) { - String tmp = item.title.length() > 0 ? item.title.substring(0, 1).toUpperCase() : "?"; + private void updateTextCheckedState(final HeadlineViewHolder holder, final Article article, int position) { + String tmp = article.title.length() > 0 ? article.title.substring(0, 1).toUpperCase() : "?"; - if (item.selected) { + if (article.selected) { holder.textImage.setImageDrawable(m_drawableBuilder.build(" ", 0xff616161)); holder.textImage.setTag(null); holder.textChecked.setVisibility(View.VISIBLE); } else { - final Drawable textDrawable = m_drawableBuilder.build(tmp, m_colorGenerator.getColor(item.title)); + final Drawable textDrawable = m_drawableBuilder.build(tmp, m_colorGenerator.getColor(article.title)); - if (item.flavorImage == null) { + holder.textImage.setImageDrawable(textDrawable); + holder.textImage.setTag(null); + + //holder.textChecked.setVisibility(View.GONE); + + if (article.flavorImage == null) { holder.textImage.setImageDrawable(textDrawable); holder.textImage.setTag(null); } else { - String imgSrc = item.flavorImage.attr("src"); - - // retarded schema-less urls - if (imgSrc.indexOf("//") == 0) - imgSrc = "http:" + imgSrc; - - if (!imgSrc.equals(holder.textImage.getTag())) { + if (!article.flavorImageUri.equals(holder.textImage.getTag())) { - holder.textImage.setTag("LOADING:" + imgSrc); + final int loadingPosition = position; ImageAware imageAware = new ImageViewAware(holder.textImage, false); DisplayImageOptions options = new DisplayImageOptions.Builder() @@ -812,8 +813,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, .displayer(new RoundedBitmapDisplayer(100)) .build(); - final String finalImgSrc = imgSrc; - m_imageLoader.displayImage(imgSrc, imageAware, options, new ImageLoadingListener() { + m_imageLoader.displayImage(article.flavorImageUri, imageAware, options, new ImageLoadingListener() { @Override public void onLoadingStarted(String s, View view) { @@ -826,8 +826,8 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, @Override public void onLoadingComplete(String imageUri, View view, Bitmap bitmap) { - if (("LOADING:" + imageUri).equals(view.getTag()) && bitmap != null) { - holder.textImage.setTag(finalImgSrc); + if (loadingPosition == holder.position && bitmap != null) { + holder.textImage.setTag(article.flavorImageUri); if (bitmap.getWidth() < THUMB_IMG_MIN_SIZE || bitmap.getHeight() < THUMB_IMG_MIN_SIZE) { holder.textImage.setImageDrawable(textDrawable); @@ -842,7 +842,6 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, } ); - } } @@ -851,7 +850,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, } @Override - public View getView(int position, View convertView, ViewGroup parent) { + public View getView(final int position, View convertView, ViewGroup parent) { View v = convertView; @@ -917,6 +916,8 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, holder = (HeadlineViewHolder) v.getTag(); } + holder.position = position; + String articleContent = article.content != null ? article.content : ""; String articleContentReduced = articleContent.length() > CommonActivity.EXCERPT_MAX_QUERY_LENGTH ? @@ -944,34 +945,8 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, }); } - if (showFlavorImage && article.flavorImage == null) { - - Elements imgs = article.articleDoc.select("img"); - - for (Element tmp : imgs) { - try { - if (tmp.attr("src") != null && tmp.attr("src").indexOf("data:") == 0) { - continue; - } - - if (Integer.valueOf(tmp.attr("width")) > FLAVOR_IMG_MIN_SIZE && Integer.valueOf(tmp.attr("width")) > FLAVOR_IMG_MIN_SIZE) { - article.flavorImage = tmp; - break; - } - - } catch (NumberFormatException e) { - // - } - } - - if (article.flavorImage == null) - article.flavorImage = imgs.first(); - - article.flavorImageCount = imgs.size(); - } - if (holder.textImage != null) { - updateTextCheckedState(holder, article); + updateTextCheckedState(holder, article, position); holder.textImage.setOnClickListener(new OnClickListener() { @Override @@ -980,7 +955,7 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, article.selected = !article.selected; - updateTextCheckedState(holder, article); + updateTextCheckedState(holder, article, position); m_listener.onArticleListSelectionChange(getSelectedArticles()); @@ -990,30 +965,18 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, ViewCompat.setTransitionName(holder.textImage, "TRANSITION:ARTICLE_IMAGES_PAGER"); if (article.flavorImage != null) { - final String imgSrcFirst = article.flavorImage.attr("src"); holder.textImage.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { - Intent intent = new Intent(m_activity, ArticleImagesPagerActivity.class); - intent.putExtra("firstSrc", imgSrcFirst); - intent.putExtra("title", article.title); - intent.putExtra("content", article.content); - - ActivityOptionsCompat options = - ActivityOptionsCompat.makeSceneTransitionAnimation(m_activity, - holder.textImage, // The view which starts the transition - "TRANSITION:ARTICLE_IMAGES_PAGER" // The transitionName of the view we’re transitioning to - ); - ActivityCompat.startActivity(m_activity, intent, options.toBundle()); + openGalleryForType(article, holder, holder.textImage); return true; } }); } - } if (holder.titleView != null) { @@ -1145,340 +1108,87 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, } }); - boolean videoFound = false; - - if (showFlavorImage && article.articleDoc != null && holder.flavorVideoKindView != null) { - Element video = article.articleDoc.select("video").first(); - Element ytframe = article.articleDoc.select("iframe[src*=youtube.com/embed/]").first(); - - if (video != null) { - try { - Element source = video.select("source").first(); - - final String streamUri = source.attr("src"); - final String posterUri = video.attr("poster"); + if (article.flavorImageUri != null && holder.flavorImageView != null) { - if (streamUri.length() > 0 && posterUri.length() > 0) { + if (!article.flavorImageUri.equals(holder.flavorImageView.getTag())) { - if (!posterUri.equals(holder.flavorImageView.getTag())) { + //Log.d(TAG, "IMG: " + article.flavorImageUri + " STREAM: " + article.flavorStreamUri); - holder.flavorImageView.setTag("LOADING:" + posterUri); - ImageAware imageAware = new ImageViewAware(holder.flavorImageView, false); + ImageAware imageAware = new ImageViewAware(holder.flavorImageView, false); + final int loadingPosition = position; - m_imageLoader.displayImage(posterUri, imageAware, displayImageOptions, new ImageLoadingListener() { - @Override - public void onLoadingStarted(String s, View view) { - holder.flavorImageLoadingBar.setVisibility(View.VISIBLE); - holder.flavorImageLoadingBar.setIndeterminate(false); - holder.flavorImageLoadingBar.setProgress(0); - } + m_imageLoader.displayImage(article.flavorImageUri, imageAware, displayImageOptions, new ImageLoadingListener() { + @Override + public void onLoadingStarted(String s, View view) { + holder.flavorImageLoadingBar.setVisibility(View.VISIBLE); + holder.flavorImageLoadingBar.setIndeterminate(false); + holder.flavorImageLoadingBar.setProgress(0); + } - @Override - public void onLoadingFailed(String s, View view, FailReason failReason) { - holder.flavorImageLoadingBar.setVisibility(View.GONE); - } + @Override + public void onLoadingFailed(String s, View view, FailReason failReason) { + holder.flavorImageLoadingBar.setVisibility(View.GONE); + } - @Override - public void onLoadingComplete(String imageUri, View view, Bitmap bitmap) { - if (("LOADING:" + imageUri).equals(view.getTag()) && bitmap != null) { + @Override + public void onLoadingComplete(String imageUri, View view, Bitmap bitmap) { + if (loadingPosition == holder.position && bitmap != null) { - holder.flavorImageLoadingBar.setVisibility(View.GONE); - holder.flavorImageView.setTag(posterUri); - holder.flavorImageView.setVisibility(View.VISIBLE); - holder.flavorVideoKindView.setVisibility(View.VISIBLE); + holder.flavorImageLoadingBar.setVisibility(View.GONE); + holder.flavorImageView.setTag(article.flavorImageUri); - maybeRepositionFlavorImage(view, bitmap, holder); - } - } - - @Override - public void onLoadingCancelled(String s, View view) { - holder.flavorImageLoadingBar.setVisibility(View.GONE); - } - } - , new ImageLoadingProgressListener() { - @Override - public void onProgressUpdate(String s, View view, int current, int total) { - if (total != 0) { - int p = (int)((float)current/total*100); - - holder.flavorImageLoadingBar.setIndeterminate(false); - holder.flavorImageLoadingBar.setProgress(p); - } else { - holder.flavorImageLoadingBar.setIndeterminate(true); - } - } - }); + if (bitmap.getWidth() > FLAVOR_IMG_MIN_SIZE && bitmap.getHeight() > FLAVOR_IMG_MIN_SIZE) { + holder.flavorImageView.setVisibility(View.VISIBLE); - } else { - holder.flavorImageView.setVisibility(View.VISIBLE); - holder.flavorVideoKindView.setVisibility(View.VISIBLE); + maybeRepositionFlavorImage(view, bitmap, holder); + adjustVideoKindView(holder, article); - if (holder.flavorImageEmbedded) { - TypedValue tv = new TypedValue(); - if (m_activity.getTheme().resolveAttribute(R.attr.headlineHeaderBackground, tv, true)) { - holder.headlineHeader.setBackgroundColor(tv.data); - } + } else { + holder.flavorImageView.setImageDrawable(null); } - } - - videoFound = true; - - holder.flavorVideoKindView.setImageResource(R.drawable.ic_play_circle); - - //ViewCompat.setTransitionName(holder.flavorImageView, "TRANSITION:ARTICLE_VIDEO_PLAYER"); - - holder.flavorImageView.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - - Intent intent = new Intent(m_activity, VideoPlayerActivity.class); - intent.putExtra("streamUri", streamUri); - intent.putExtra("title", article.title); - - /*ActivityOptionsCompat options = - ActivityOptionsCompat.makeSceneTransitionAnimation(m_activity, - holder.flavorImageView, // The view which starts the transition - "TRANSITION:ARTICLE_VIDEO_PLAYER" // The transitionName of the view we’re transitioning to - ); - ActivityCompat.startActivity(m_activity, intent, options.toBundle());*/ - - startActivity(intent); - } - }); - - // ONCLICK open video player - } - } catch (Exception e) { - e.printStackTrace(); - videoFound = false; - } - } else if (ytframe != null) { - // thumb: http://img.youtube.com/vi/{VID}/mqdefault.jpg - String srcEmbed = ytframe.attr("src"); - - if (srcEmbed.length() > 0) { - Pattern pattern = Pattern.compile("/embed/([\\w-]+)"); - Matcher matcher = pattern.matcher(srcEmbed); - - if (matcher.find()) { - final String vid = matcher.group(1); - final String thumbUri = "http://img.youtube.com/vi/"+vid+"/mqdefault.jpg"; - final String videoUri = "https://youtu.be/" + vid; - - videoFound = true; - - holder.flavorVideoKindView.setImageResource(R.drawable.ic_youtube_play); - if (!thumbUri.equals(holder.flavorImageView.getTag())) { - holder.flavorImageView.setTag("LOADING:" + thumbUri); - - ImageAware imageAware = new ImageViewAware(holder.flavorImageView, false); - m_imageLoader.displayImage(thumbUri, imageAware, displayImageOptions, new ImageLoadingListener() { - @Override - public void onLoadingStarted(String s, View view) { - holder.flavorImageLoadingBar.setVisibility(View.VISIBLE); - holder.flavorImageLoadingBar.setIndeterminate(false); - holder.flavorImageLoadingBar.setProgress(0); - } - - @Override - public void onLoadingFailed(String s, View view, FailReason failReason) { - holder.flavorImageLoadingBar.setVisibility(View.GONE); - } - - @Override - public void onLoadingComplete(String imageUri, View view, Bitmap bitmap) { - if (("LOADING:" + imageUri).equals(view.getTag()) && bitmap != null) { - holder.flavorImageLoadingBar.setVisibility(View.GONE); - holder.flavorImageView.setTag(thumbUri); - holder.flavorImageView.setVisibility(View.VISIBLE); - holder.flavorVideoKindView.setVisibility(View.VISIBLE); - - maybeRepositionFlavorImage(view, bitmap, holder); - } - } - - @Override - public void onLoadingCancelled(String s, View view) { - holder.flavorImageLoadingBar.setVisibility(View.GONE); - } - } - , new ImageLoadingProgressListener() { - @Override - public void onProgressUpdate(String s, View view, int current, int total) { - if (total != 0) { - int p = (int)((float)current/total*100); - - holder.flavorImageLoadingBar.setIndeterminate(false); - holder.flavorImageLoadingBar.setProgress(p); - } else { - holder.flavorImageLoadingBar.setIndeterminate(true); - } - } - }); + @Override + public void onLoadingCancelled(String s, View view) { + holder.flavorImageLoadingBar.setVisibility(View.GONE); + } + }, new ImageLoadingProgressListener() { + @Override + public void onProgressUpdate(String s, View view, int current, int total) { + if (total != 0) { + int p = (int)((float)current/total*100); + + holder.flavorImageLoadingBar.setIndeterminate(false); + holder.flavorImageLoadingBar.setProgress(p); } else { - holder.flavorImageView.setVisibility(View.VISIBLE); - holder.flavorVideoKindView.setVisibility(View.VISIBLE); - - if (holder.flavorImageEmbedded) { - TypedValue tv = new TypedValue(); - if (m_activity.getTheme().resolveAttribute(R.attr.headlineHeaderBackground, tv, true)) { - holder.headlineHeader.setBackgroundColor(tv.data); - } - } - + holder.flavorImageLoadingBar.setIndeterminate(true); } + } + }); + } else { // already tagged + holder.flavorImageView.setVisibility(View.VISIBLE); - holder.flavorImageView.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - - if (m_youtubeInstalled) { - Intent intent = new Intent(m_activity, YoutubePlayerActivity.class); - intent.putExtra("streamUri", videoUri); - intent.putExtra("vid", vid); - intent.putExtra("title", article.title); - - startActivity(intent); - } else { - Intent intent = new Intent(Intent.ACTION_VIEW, - Uri.parse(videoUri)); - startActivity(intent); - } - } - }); + adjustVideoKindView(holder, article); + + if (holder.flavorImageEmbedded) { + TypedValue tv = new TypedValue(); + if (m_activity.getTheme().resolveAttribute(R.attr.headlineHeaderBackground, tv, true)) { + holder.headlineHeader.setBackgroundColor(tv.data); } } } - } - if (!videoFound && showFlavorImage && holder.flavorImageView != null) { - - if (article.articleDoc != null) { - - if (article.flavorImage != null) { - String imgSrc = article.flavorImage.attr("src"); - final String imgSrcFirst = imgSrc; - - // retarded schema-less urls - if (imgSrc.indexOf("//") == 0) - imgSrc = "http:" + imgSrc; - - ViewCompat.setTransitionName(holder.flavorImageView, "TRANSITION:ARTICLE_IMAGES_PAGER"); - - holder.flavorImageView.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - - Intent intent = new Intent(m_activity, ArticleImagesPagerActivity.class); - intent.putExtra("firstSrc", imgSrcFirst); - intent.putExtra("title", article.title); - intent.putExtra("content", article.content); - - ActivityOptionsCompat options = - ActivityOptionsCompat.makeSceneTransitionAnimation(m_activity, - holder.flavorImageView, // The view which starts the transition - "TRANSITION:ARTICLE_IMAGES_PAGER" // The transitionName of the view we’re transitioning to - ); - ActivityCompat.startActivity(m_activity, intent, options.toBundle()); - - //startActivityForResult(intent, 0); - } - }); - - if (!imgSrc.equals(holder.flavorImageView.getTag())) { - - holder.flavorImageView.setTag("LOADING:" + imgSrc); - ImageAware imageAware = new ImageViewAware(holder.flavorImageView, false); - - final String finalImgSrc = imgSrc; - m_imageLoader.displayImage(imgSrc, imageAware, displayImageOptions, new ImageLoadingListener() { - - @Override - public void onLoadingCancelled(String arg0, - View arg1) { - - // - } - - @Override - public void onLoadingComplete(String imageUri, - View view, Bitmap bitmap) { - - if (("LOADING:" + imageUri).equals(view.getTag()) && bitmap != null) { - - holder.flavorImageLoadingBar.setVisibility(View.GONE); - holder.flavorImageView.setTag(finalImgSrc); - - if (bitmap.getWidth() > FLAVOR_IMG_MIN_SIZE && bitmap.getHeight() > FLAVOR_IMG_MIN_SIZE) { - holder.flavorImageView.setVisibility(View.VISIBLE); - - if (article.flavorImageCount > 1) { - holder.flavorVideoKindView.setVisibility(View.VISIBLE); - holder.flavorVideoKindView.setImageResource(R.drawable.ic_image_album); - } - - maybeRepositionFlavorImage(view, bitmap, holder); - } else { - holder.flavorImageView.setImageDrawable(null); - } - } - } - - @Override - public void onLoadingFailed(String arg0, - View arg1, FailReason arg2) { - - holder.flavorImageLoadingBar.setVisibility(View.GONE); - holder.flavorImageView.setVisibility(View.GONE); - } - - @Override - public void onLoadingStarted(String arg0, - View arg1) { - holder.flavorImageLoadingBar.setVisibility(View.VISIBLE); - holder.flavorImageLoadingBar.setIndeterminate(false); - holder.flavorImageLoadingBar.setProgress(0); - } - - }, new ImageLoadingProgressListener() { - @Override - public void onProgressUpdate(String s, View view, int current, int total) { - if (total != 0) { - int p = (int)((float)current/total*100); - - holder.flavorImageLoadingBar.setIndeterminate(false); - holder.flavorImageLoadingBar.setProgress(p); - } else { - holder.flavorImageLoadingBar.setIndeterminate(true); - } - } - }); - - } else { - holder.flavorImageView.setVisibility(View.VISIBLE); + holder.flavorImageView.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { - if (article.flavorImageCount > 1) { - holder.flavorVideoKindView.setVisibility(View.VISIBLE); - holder.flavorVideoKindView.setImageResource(R.drawable.ic_image_album); - } + openGalleryForType(article, holder, null); - if (holder.flavorImageEmbedded) { - TypedValue tv = new TypedValue(); - if (m_activity.getTheme().resolveAttribute(R.attr.headlineHeaderBackground, tv, true)) { - holder.headlineHeader.setBackgroundColor(tv.data); - } - } - - } - } } - } + }); } String articleAuthor = article.author != null ? article.author : ""; @@ -1548,6 +1258,67 @@ public class HeadlinesFragment extends Fragment implements OnItemClickListener, return v; } + private void openGalleryForType(Article article, HeadlineViewHolder holder, View transitionView) { + if ("iframe".equals(article.flavorImage.tagName().toLowerCase())) { + + if (m_youtubeInstalled) { + Intent intent = new Intent(m_activity, YoutubePlayerActivity.class); + intent.putExtra("streamUri", article.flavorStreamUri); + intent.putExtra("vid", article.youtubeVid); + intent.putExtra("title", article.title); + + startActivity(intent); + } else { + Intent intent = new Intent(Intent.ACTION_VIEW, + Uri.parse(article.flavorStreamUri)); + startActivity(intent); + } + + } else if ("video".equals(article.flavorImage.tagName().toLowerCase())) { + + Intent intent = new Intent(m_activity, VideoPlayerActivity.class); + intent.putExtra("streamUri", article.flavorStreamUri); + intent.putExtra("title", article.title); + + startActivity(intent); + + } else { + + Intent intent = new Intent(m_activity, ArticleImagesPagerActivity.class); + + intent.putExtra("firstSrc", article.flavorImageUri); + intent.putExtra("title", article.title); + intent.putExtra("content", article.content); + + ActivityOptionsCompat options = + ActivityOptionsCompat.makeSceneTransitionAnimation(m_activity, + transitionView != null ? transitionView : holder.flavorImageView, // The view which starts the transition + "TRANSITION:ARTICLE_IMAGES_PAGER" // The transitionName of the view we’re transitioning to + ); + ActivityCompat.startActivity(m_activity, intent, options.toBundle()); + } + + } + + private void adjustVideoKindView(HeadlineViewHolder holder, Article article) { + if (article.flavorImage != null) { + if ("iframe".equals(article.flavorImage.tagName().toLowerCase())) { + holder.flavorVideoKindView.setImageResource(R.drawable.ic_youtube_play); + holder.flavorVideoKindView.setVisibility(View.VISIBLE); + } else if ("video".equals(article.flavorImage.tagName().toLowerCase())) { + holder.flavorVideoKindView.setImageResource(R.drawable.ic_play_circle); + holder.flavorVideoKindView.setVisibility(View.VISIBLE); + } else if (article.mediaList.size() > 1) { + holder.flavorVideoKindView.setImageResource(R.drawable.ic_image_album); + holder.flavorVideoKindView.setVisibility(View.VISIBLE); + } else { + holder.flavorVideoKindView.setVisibility(View.INVISIBLE); + } + } else { + holder.flavorVideoKindView.setVisibility(View.INVISIBLE); + } + } + public int pxToDp(int px) { DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics(); int dp = Math.round(px / (displayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT)); diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/OnlineActivity.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/OnlineActivity.java index 45fb1e13..5185ddc1 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/OnlineActivity.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/OnlineActivity.java @@ -1148,6 +1148,20 @@ public class OnlineActivity extends CommonActivity { } } + private void setLoadingStatus(String status, boolean showProgress) { + TextView tv = (TextView) findViewById(R.id.loading_message); + + if (tv != null) { + tv.setText(status); + } + + View loadingContainer = findViewById(R.id.loading_container); + + if (loadingContainer != null) { + loadingContainer.setVisibility(status.equals("") ? View.GONE : View.VISIBLE); + } + } + protected void logout() { setSessionId(null); @@ -1627,6 +1641,12 @@ public class OnlineActivity extends CommonActivity { // Unknown method means old tt-rss, in that case we assume API 0 and continue setLoadingStatus(getErrorMessage(), false); + + if (m_lastErrorMessage != null) { + setLoadingStatus(getString(getErrorMessage()) + "\n\n" + m_lastErrorMessage, false); + } else { + setLoadingStatus(getErrorMessage(), false); + } if (m_listener != null) { m_listener.OnLoginFailed(); @@ -1667,7 +1687,12 @@ public class OnlineActivity extends CommonActivity { } setSessionId(null); - setLoadingStatus(getErrorMessage(), false); + + if (m_lastErrorMessage != null) { + setLoadingStatus(getString(getErrorMessage()) + "\n\n" + m_lastErrorMessage, false); + } else { + setLoadingStatus(getErrorMessage(), false); + } loginFailure(); } diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/VideoPlayerActivity.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/VideoPlayerActivity.java index 48a0e9ff..92c63b48 100644 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/VideoPlayerActivity.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/VideoPlayerActivity.java @@ -143,7 +143,11 @@ public class VideoPlayerActivity extends CommonActivity { @Override
public void surfaceCreated(SurfaceHolder holder) {
mediaPlayer.setDisplay(holder);
- mediaPlayer.prepareAsync();
+ try {
+ mediaPlayer.prepareAsync();
+ } catch (IllegalStateException e) {
+ e.printStackTrace();
+ }
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
@@ -238,6 +242,7 @@ public class VideoPlayerActivity extends CommonActivity { if (m_streamUri != null) {
Intent intent = new Intent(Intent.ACTION_SEND);
+ intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_SUBJECT, m_streamUri);
intent.putExtra(Intent.EXTRA_TEXT, m_streamUri);
diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/YoutubePlayerActivity.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/YoutubePlayerActivity.java index e7312ffa..7f2c2d6f 100644 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/YoutubePlayerActivity.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/YoutubePlayerActivity.java @@ -116,6 +116,7 @@ public class YoutubePlayerActivity extends CommonActivity implements YouTubePlay if (m_streamUri != null) { Intent intent = new Intent(Intent.ACTION_SEND); + intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_SUBJECT, m_streamUri); intent.putExtra(Intent.EXTRA_TEXT, m_streamUri); diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/types/Article.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/types/Article.java index eb1fd409..fe875c87 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/types/Article.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/types/Article.java @@ -2,12 +2,16 @@ package org.fox.ttrss.types; import android.os.Parcel; import android.os.Parcelable; +import android.util.Log; +import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import java.util.ArrayList; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; // TODO: serialize Labels public class Article implements Parcelable { @@ -37,7 +41,14 @@ public class Article implements Parcelable { /* not serialized */ public Document articleDoc; public Element flavorImage; - public int flavorImageCount; + + public String flavorImageUri; + public String flavorStreamUri; + public String youtubeVid; + + //public int flavorImageCount; + + public List<Element> mediaList = new ArrayList<>(); public Article(Parcel in) { readFromParcel(in); @@ -46,7 +57,62 @@ public class Article implements Parcelable { public Article() { } - + + public void collectMediaInfo() { + articleDoc = Jsoup.parse(content); + + if (articleDoc != null) { + mediaList = articleDoc.select("img,video,iframe[src*=youtube.com/embed/]"); + + for (Element e : mediaList) { + if ("iframe".equals(e.tagName().toLowerCase())) { + flavorImage = e; + break; + } else if ("video".equals(e.tagName().toLowerCase())) { + flavorImage = e; + break; + } + } + + if (flavorImage == null) { + for (Element e : mediaList) { + flavorImage = e; + break; + } + } + + if (flavorImage != null) { + + if ("video".equals(flavorImage.tagName().toLowerCase())) { + Element source = flavorImage.select("source").first(); + flavorStreamUri = source.attr("src"); + + flavorImageUri = flavorImage.attr("poster"); + } else if ("iframe".equals(flavorImage.tagName().toLowerCase())) { + + String srcEmbed = flavorImage.attr("src"); + + if (srcEmbed.length() > 0) { + Pattern pattern = Pattern.compile("/embed/([\\w-]+)"); + Matcher matcher = pattern.matcher(srcEmbed); + + if (matcher.find()) { + youtubeVid = matcher.group(1); + + flavorImageUri = "https://img.youtube.com/vi/" + youtubeVid + "/mqdefault.jpg"; + flavorStreamUri = "https://youtu.be/" + youtubeVid; + } + } + } else { + flavorImageUri = flavorImage.attr("src"); + flavorStreamUri = null; + } + } + } + + Log.d("Article", "collectMediaInfo: " + flavorImage); + } + public Article(int id) { this.id = id; this.title = ""; diff --git a/org.fox.ttrss/src/main/java/org/fox/ttrss/util/HeadlinesRequest.java b/org.fox.ttrss/src/main/java/org/fox/ttrss/util/HeadlinesRequest.java index 505fbd3e..8581addc 100755 --- a/org.fox.ttrss/src/main/java/org/fox/ttrss/util/HeadlinesRequest.java +++ b/org.fox.ttrss/src/main/java/org/fox/ttrss/util/HeadlinesRequest.java @@ -93,8 +93,10 @@ public class HeadlinesRequest extends ApiRequest { } for (Article f : articles) - if (!m_articles.containsId(f.id)) + if (!m_articles.containsId(f.id)) { + f.collectMediaInfo(); m_articles.add(f); + } if (articles.size() == HEADLINES_REQUEST_SIZE) { Article placeholder = new Article(HeadlinesFragment.ARTICLE_SPECIAL_LOADMORE); @@ -118,7 +120,12 @@ public class HeadlinesRequest extends ApiRequest { if (m_lastError == ApiError.LOGIN_FAILED) { m_activity.login(); } else { - m_activity.toast(getErrorMessage()); + + if (m_lastErrorMessage != null) { + m_activity.toast(m_activity.getString(getErrorMessage()) + "\n" + m_lastErrorMessage); + } else { + m_activity.toast(getErrorMessage()); + } //m_activity.setLoadingStatus(getErrorMessage(), false); } } diff --git a/taskerlocaleapi/taskerlocaleapi.iml b/taskerlocaleapi/taskerlocaleapi.iml index ee1ca803..5dad5404 100755 --- a/taskerlocaleapi/taskerlocaleapi.iml +++ b/taskerlocaleapi/taskerlocaleapi.iml @@ -12,10 +12,12 @@ <option name="SELECTED_TEST_ARTIFACT" value="_android_test_" /> <option name="ASSEMBLE_TASK_NAME" value="assembleDebug" /> <option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" /> - <option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" /> <option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugTest" /> <option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileDebugTestSources" /> - <option name="TEST_SOURCE_GEN_TASK_NAME" value="generateDebugTestSources" /> + <afterSyncTasks> + <task>generateDebugSources</task> + <task>generateDebugTestSources</task> + </afterSyncTasks> <option name="ALLOW_USER_CONFIGURATION" value="false" /> <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" /> <option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" /> @@ -25,7 +27,7 @@ </configuration> </facet> </component> - <component name="NewModuleRootManager" inherit-compiler-output="false"> + <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_6" inherit-compiler-output="false"> <output url="file://$MODULE_DIR$/build/intermediates/classes/debug" /> <output-test url="file://$MODULE_DIR$/build/intermediates/classes/test/debug" /> <exclude-output /> diff --git a/tt-rss-android.iml b/tt-rss-android.iml index 5607cf83..58a44a3e 100644 --- a/tt-rss-android.iml +++ b/tt-rss-android.iml @@ -8,7 +8,7 @@ </configuration> </facet> </component> - <component name="NewModuleRootManager" inherit-compiler-output="true"> + <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_6" inherit-compiler-output="true"> <output url="file://$MODULE_DIR$/build/classes/main" /> <output-test url="file://$MODULE_DIR$/build/classes/test" /> <exclude-output /> |