";
- }
- }
-
- private boolean showPhotoViewer(String imageUrl, View source, int startX, int startY) {
+ private boolean showPhotoViewer(String imageUrl, View sourceView, int startX, int startY) {
if (!isAdded() || TextUtils.isEmpty(imageUrl)) {
return false;
}
@@ -1042,13 +953,14 @@ private boolean showPhotoViewer(String imageUrl, View source, int startX, int st
return false;
}
+ String postContent = (mRenderer != null ? mRenderer.getRenderedHtml() : null);
boolean isPrivatePost = (mPost != null && mPost.isPrivate);
ReaderActivityLauncher.showReaderPhotoViewer(
getActivity(),
imageUrl,
- getPostContent(),
- source,
+ postContent,
+ sourceView,
isPrivatePost,
startX,
startY);
@@ -1056,134 +968,6 @@ private boolean showPhotoViewer(String imageUrl, View source, int startX, int st
return true;
}
- /*
- * returns the basic content of the post tweaked for use here
- */
- private String getPostContent() {
- if (mPost == null) {
- return "";
- } else if (mPost.hasText()) {
- // some content (such as Vimeo embeds) don't have "http:" before links, correct this here
- String content = mPost.getText().replace("src=\"//", "src=\"http://");
- // insert video div before content if this is a VideoPress post (video otherwise won't appear)
- if (mPost.isVideoPress) {
- content = makeVideoDiv(mPost.getFeaturedVideo(), mPost.getFeaturedImage()) + content;
- } else if (mPost.hasFeaturedImage() && !PhotonUtils.isMshotsUrl(mPost.getFeaturedImage())) {
- // if the post has a featured image other than an mshot that's not in the content,
- // add it to the content
- Uri uri = Uri.parse(mPost.getFeaturedImage());
- String path = StringUtils.notNullStr(uri.getLastPathSegment());
- if (!content.contains(path)) {
- AppLog.d(T.READER, "reader post detail > added featured image to content");
- content = String.format("
", mPost.getFeaturedImage())
- + content;
- }
- }
- return content;
- } else if (mPost.hasFeaturedImage()) {
- // some photo blogs have posts with empty content but still have a featured image, so
- // use the featured image as the content
- return String.format("
", mPost.getFeaturedImage());
- } else {
- return "";
- }
- }
-
- /*
- * returns the full content, including CSS, that will be shown in the WebView for this post
- */
- private String getPostContentForWebView(Context context) {
- if (mPost == null || context == null) {
- return "";
- }
-
- String content = getPostContent();
-
- StringBuilder sbHtml = new StringBuilder("");
-
- // title isn't strictly necessary, but source is invalid html5 without one
- sbHtml.append("Reader Post");
-
- // https://developers.google.com/chrome/mobile/docs/webview/pixelperfect
- sbHtml.append("");
-
- // use "Open Sans" Google font
- sbHtml.append("");
-
- sbHtml.append("")
- .append(content)
- .append("");
-
- return sbHtml.toString();
- }
-
/*
* called when the post doesn't exist in local db, need to get it from server
*/
@@ -1217,16 +1001,10 @@ private void postFailed() {
}
}
- /*
- * javascript should only be enabled for wp blogs (not external feeds)
- */
- private boolean canEnableJavaScript() {
- return (mPost != null && mPost.isWP());
- }
-
private void showPost() {
if (mIsPostTaskRunning) {
AppLog.w(T.READER, "reader post detail > show post task already running");
+ return;
}
new ShowPostTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
@@ -1250,8 +1028,6 @@ private class ShowPostTask extends AsyncTask {
WPNetworkImageView imgAvatar;
ViewGroup layoutDetailHeader;
- String postHtml;
-
@Override
protected void onPreExecute() {
mIsPostTaskRunning = true;
@@ -1288,8 +1064,6 @@ protected Boolean doInBackground(Void... params) {
layoutDetailHeader = (ViewGroup) container.findViewById(R.id.layout_detail_header);
- postHtml = getPostContentForWebView(container.getContext());
-
return true;
}
@@ -1306,17 +1080,15 @@ protected void onPostExecute(Boolean result) {
// the server if it hasn't already been requested
if (!mHasAlreadyRequestedPost) {
mHasAlreadyRequestedPost = true;
+ AppLog.i(T.READER, "reader post detail > post not found, requesting it");
requestPost();
}
return;
}
- // enable JavaScript in the webView if it's safe to do so
- mReaderWebView.getSettings().setJavaScriptEnabled(canEnableJavaScript());
-
- // IMPORTANT: use loadDataWithBaseURL() since loadData() may fail
- // https://code.google.com/p/android/issues/detail?id=4401
- mReaderWebView.loadDataWithBaseURL(null, postHtml, "text/html", "UTF-8", null);
+ // render the post in the webView
+ mRenderer = new ReaderPostRenderer(mReaderWebView, mPost);
+ mRenderer.beginRender();
txtTitle.setText(mPost.hasTitle() ? mPost.getTitle() : getString(R.string.reader_untitled_post));
@@ -1349,13 +1121,13 @@ public void onClick(View view) {
if (mPost.hasPostAvatar()) {
imgAvatar.setImageUrl(mPost.getPostAvatarForDisplay(
- mResourceVars.likeAvatarSize), WPNetworkImageView.ImageType.AVATAR);
+ mResourceVars.likeAvatarSizePx), WPNetworkImageView.ImageType.AVATAR);
imgAvatar.setVisibility(View.VISIBLE);
} else {
imgAvatar.setVisibility(View.GONE);
}
- // hide blog name, avatar & follow button if this fragment was shown from blog preview
+ // hide header if this fragment was shown from blog preview
if (isBlogPreview()) {
layoutDetailHeader.setVisibility(View.GONE);
}
@@ -1432,7 +1204,6 @@ public void onClick(View view) {
}
}
-
/*
* called by the web view when the content finishes loading - likes & comments aren't displayed
* until this is triggered, to avoid having them appear before the webView content
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListActivity.java
index 641140877d03..2d0884d392c6 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListActivity.java
+++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListActivity.java
@@ -17,7 +17,6 @@
import org.wordpress.android.datasets.ReaderTagTable;
import org.wordpress.android.models.ReaderTag;
import org.wordpress.android.models.ReaderTagType;
-import org.wordpress.android.util.NetworkUtils;
import org.wordpress.android.ui.WPActionBarActivity;
import org.wordpress.android.ui.accounts.WPComLoginActivity;
import org.wordpress.android.ui.prefs.AppPrefs;
@@ -30,6 +29,7 @@
import org.wordpress.android.ui.reader.services.ReaderUpdateService.UpdateTask;
import org.wordpress.android.util.AppLog;
import org.wordpress.android.util.AppLog.T;
+import org.wordpress.android.util.NetworkUtils;
import org.wordpress.android.util.StringUtils;
import java.util.EnumSet;
@@ -412,6 +412,11 @@ public void onReceive(Context context, Intent intent) {
} else if (listFragment.getPostListType() == ReaderTypes.ReaderPostListType.TAG_FOLLOWED) {
// list fragment is viewing followed tags, tell it to refresh the list of tags
listFragment.refreshTags();
+ // update the current tag if the list fragment is empty - this will happen if
+ // the tag table was previously empty (ie: first run)
+ if (listFragment.isPostAdapterEmpty()) {
+ listFragment.updateCurrentTag();
+ }
}
} else if (action.equals(ReaderUpdateService.ACTION_FOLLOWED_BLOGS_CHANGED)) {
// followed blogs have changed, so remove posts in blogs that are
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java
index d85df3f9af96..832605d939c3 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java
+++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostListFragment.java
@@ -872,6 +872,10 @@ public void onActionResult(boolean succeeded) {
ReaderPostActions.requestPostsForBlog(mCurrentBlogId, mCurrentBlogUrl, updateAction, listener);
}
+ void updateCurrentTag() {
+ updatePostsWithTag(getCurrentTag(), RequestDataAction.LOAD_NEWER, ReaderTypes.RefreshType.AUTOMATIC);
+ }
+
/*
* get latest posts for this tag from the server
*/
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostPagerActivity.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostPagerActivity.java
index 6d883f454118..7d2f500dfa7a 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostPagerActivity.java
+++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostPagerActivity.java
@@ -25,7 +25,6 @@
import org.wordpress.android.models.ReaderPost;
import org.wordpress.android.models.ReaderPostList;
import org.wordpress.android.models.ReaderTag;
-import org.wordpress.android.util.NetworkUtils;
import org.wordpress.android.ui.reader.ReaderAnim.AnimationEndListener;
import org.wordpress.android.ui.reader.ReaderAnim.Duration;
import org.wordpress.android.ui.reader.ReaderPostPagerEndFragment.EndFragmentType;
@@ -40,6 +39,7 @@
import org.wordpress.android.ui.reader.models.ReaderBlogIdPostIdList;
import org.wordpress.android.ui.reader.utils.ReaderUtils;
import org.wordpress.android.util.AppLog;
+import org.wordpress.android.util.NetworkUtils;
import org.wordpress.android.util.ToastUtils;
import javax.annotation.Nonnull;
@@ -232,15 +232,12 @@ private void loadPosts(final long blogId,
new Thread() {
@Override
public void run() {
- final ReaderPostList postList;
+ final ReaderBlogIdPostIdList idList;
if (mIsSinglePostView) {
- ReaderPost post = ReaderPostTable.getPost(blogId, postId);
- if (post == null) {
- return;
- }
- postList = new ReaderPostList();
- postList.add(post);
+ idList = new ReaderBlogIdPostIdList();
+ idList.add(new ReaderBlogIdPostId(blogId, postId));
} else {
+ final ReaderPostList postList;
int maxPosts = ReaderConstants.READER_MAX_POSTS_TO_DISPLAY;
switch (getPostListType()) {
case TAG_FOLLOWED:
@@ -253,22 +250,22 @@ public void run() {
default:
return;
}
+ idList = postList.getBlogIdPostIdList();
}
- final ReaderBlogIdPostIdList ids = postList.getBlogIdPostIdList();
final int currentPosition = mViewPager.getCurrentItem();
final int newPosition;
if (gotoNext) {
- newPosition = ids.indexOf(blogId, postId) + 1;
+ newPosition = idList.indexOf(blogId, postId) + 1;
} else {
- newPosition = ids.indexOf(blogId, postId);
+ newPosition = idList.indexOf(blogId, postId);
}
runOnUiThread(new Runnable() {
@Override
public void run() {
mPagerAdapter = new PostPagerAdapter(getFragmentManager());
- mPagerAdapter.showPosts(ids);
+ mPagerAdapter.showPosts(idList);
mViewPager.setAdapter(mPagerAdapter);
if (mPagerAdapter.isValidPosition(newPosition)) {
mViewPager.setCurrentItem(newPosition);
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java
new file mode 100644
index 000000000000..f7c41302226e
--- /dev/null
+++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderPostRenderer.java
@@ -0,0 +1,427 @@
+package org.wordpress.android.ui.reader;
+
+import android.annotation.SuppressLint;
+import android.net.Uri;
+import android.os.Handler;
+import android.text.TextUtils;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.wordpress.android.WordPress;
+import org.wordpress.android.models.ReaderPost;
+import org.wordpress.android.ui.reader.utils.ReaderImageScanner;
+import org.wordpress.android.ui.reader.utils.ReaderUtils;
+import org.wordpress.android.util.AppLog;
+import org.wordpress.android.util.DisplayUtils;
+import org.wordpress.android.util.JSONUtil;
+import org.wordpress.android.util.PhotonUtils;
+import org.wordpress.android.util.StringUtils;
+import org.wordpress.android.util.UrlUtils;
+
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.Iterator;
+
+/**
+ * generates and displays the HTML for post detail content - main purpose is to assign the
+ * height/width attributes on image tags to (1) avoid the webView resizing as images are
+ * loaded, and (2) avoid requesting images at a size larger than the display
+ *
+ * important to note that displayed images rely on dp rather than px sizes due to the
+ * fact that WebView "converts CSS pixel values to density-independent pixel values"
+ * http://developer.android.com/guide/webapps/targeting.html
+ */
+class ReaderPostRenderer {
+
+ private final ReaderResourceVars mResourceVars;
+ private final ReaderPost mPost;
+ private final int mMinFullSizeWidthDp;
+ private final int mMinMidSizeWidthDp;
+ private final WeakReference mWeakWebView;
+
+ private StringBuilder mRenderBuilder;
+ private String mRenderedHtml;
+ private ImageSizeMap mAttachmentSizes;
+
+ @SuppressLint("SetJavaScriptEnabled")
+ ReaderPostRenderer(ReaderWebView webView, ReaderPost post) {
+ if (webView == null) {
+ throw new IllegalArgumentException("ReaderPostRenderer requires a webView");
+ }
+ if (post == null) {
+ throw new IllegalArgumentException("ReaderPostRenderer requires a post");
+ }
+
+ mPost = post;
+ mWeakWebView = new WeakReference(webView);
+ mResourceVars = new ReaderResourceVars(webView.getContext());
+
+ mMinFullSizeWidthDp = pxToDp(mResourceVars.fullSizeImageWidthPx / 3);
+ mMinMidSizeWidthDp = mMinFullSizeWidthDp / 2;
+
+ // enable JavaScript in the webView if it's safe to do so, otherwise videos
+ // and other embedded content won't work
+ webView.getSettings().setJavaScriptEnabled(canEnableJavaScript());
+ }
+
+ void beginRender() {
+ mRenderBuilder = new StringBuilder(getPostContent());
+
+ // start image scanner to find images so we can replace them with ones that have h/w set
+ final Handler handler = new Handler();
+ new Thread() {
+ @Override
+ public void run() {
+ ReaderImageScanner.ImageScanListener imageListener = new ReaderImageScanner.ImageScanListener() {
+ @Override
+ public void onImageFound(String imageTag, String imageUrl, int start, int end) {
+ replaceImageTag(imageTag, imageUrl);
+ }
+
+ @Override
+ public void onScanCompleted() {
+ final String htmlContent = formatPostContentForWebView(mRenderBuilder.toString());
+ mRenderBuilder = null;
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ renderHtmlContent(htmlContent);
+ }
+ });
+ }
+ };
+ ReaderImageScanner scanner = new ReaderImageScanner(mRenderBuilder.toString(), mPost.isPrivate);
+ scanner.beginScan(imageListener);
+ }
+ }.start();
+ }
+
+ /*
+ * called once the content is ready to be rendered in the webView
+ */
+ private void renderHtmlContent(final String htmlContent) {
+ mRenderedHtml = htmlContent;
+
+ // make sure webView is still valid (containing fragment may have been detached)
+ ReaderWebView webView = mWeakWebView.get();
+ if (webView == null) {
+ AppLog.w(AppLog.T.READER, "reader renderer > null webView");
+ return;
+ }
+
+ // IMPORTANT: use loadDataWithBaseURL() since loadData() may fail
+ // https://code.google.com/p/android/issues/detail?id=4401
+ // also important to use null as the baseUrl since onPageFinished
+ // doesn't appear to fire when it's set to an actual url
+ webView.loadDataWithBaseURL(null, htmlContent, "text/html", "UTF-8", null);
+ }
+
+ /*
+ * called when image scanner finds an image, tries to replace the image tag with one that
+ * has height & width attributes set correctly for the current display, if that fails
+ * replaces it with one that has our 'size-none' class
+ */
+ private void replaceImageTag(final String imageTag, final String imageUrl) {
+ ImageSize origSize = getImageSize(imageTag, imageUrl);
+ boolean hasWidth = (origSize != null && origSize.width > 0);
+ boolean isFullSize = hasWidth && (origSize.width >= mMinFullSizeWidthDp);
+ boolean isMidSize = hasWidth
+ && (origSize.width >= mMinMidSizeWidthDp)
+ && (origSize.width < mMinFullSizeWidthDp);
+
+ final String newImageTag;
+ if (isFullSize) {
+ newImageTag = makeFullSizeImageTag(imageUrl, origSize.width, origSize.height);
+ } else if (isMidSize) {
+ newImageTag = makeImageTag(imageUrl, origSize.width, origSize.height, "size-medium");
+ } else if (hasWidth) {
+ newImageTag = makeImageTag(imageUrl, origSize.width, origSize.height, "size-none");
+ } else {
+ newImageTag = "";
+ }
+
+ int start = mRenderBuilder.indexOf(imageTag);
+ if (start == -1) {
+ AppLog.w(AppLog.T.READER, "reader renderer > image not found in builder");
+ return;
+ }
+
+ mRenderBuilder.replace(start, start + imageTag.length(), newImageTag);
+ }
+
+ private String makeImageTag(final String imageUrl, int width, int height, final String imageClass) {
+ String newImageUrl = ReaderUtils.getResizedImageUrl(imageUrl, width, height, mPost.isPrivate);
+ if (height > 0) {
+ return new StringBuilder("")
+ .toString();
+ } else {
+ return new StringBuilder("")
+ .toString();
+ }
+ }
+
+ private String makeFullSizeImageTag(final String imageUrl, int width, int height) {
+ int newWidth;
+ int newHeight;
+ if (width > 0 && height > 0) {
+ if (height > width) {
+ newHeight = mResourceVars.fullSizeImageWidthPx;
+ float ratio = ((float) width / (float) height);
+ newWidth = (int) (newHeight * ratio);
+ } else {
+ float ratio = ((float) height / (float) width);
+ newWidth = mResourceVars.fullSizeImageWidthPx;
+ newHeight = (int) (newWidth * ratio);
+ }
+ } else {
+ newWidth = mResourceVars.fullSizeImageWidthPx;
+ newHeight = 0;
+ }
+
+ return makeImageTag(imageUrl, newWidth, newHeight, "size-full");
+ }
+
+ /*
+ * returns true if the post has a featured image and there are no images in the
+ * post's content - when this is the case, the featured image is inserted at
+ * the top of the content
+ */
+ private boolean shouldAddFeaturedImage() {
+ return mPost.hasFeaturedImage()
+ && !mPost.getText().contains(" added featured image");
+ content = getFeaturedImageHtml() + content;
+ }
+ return content;
+ }
+
+ /*
+ * returns the HTML that was last rendered, will be null prior to rendering
+ */
+ String getRenderedHtml() {
+ return mRenderedHtml;
+ }
+
+ /*
+ * returns the HTML to use when inserting a featured image into the rendered content
+ */
+ private String getFeaturedImageHtml() {
+ String imageUrl = ReaderUtils.getResizedImageUrl(
+ mPost.getFeaturedImage(),
+ mResourceVars.fullSizeImageWidthPx,
+ mResourceVars.featuredImageHeightPx,
+ mPost.isPrivate);
+
+ return "";
+ }
+
+ /*
+ * returns the full content, including CSS, that will be shown in the WebView for this post
+ */
+ private String formatPostContentForWebView(final String content) {
+ StringBuilder sbHtml = new StringBuilder("");
+
+ // title isn't necessary, but it's invalid html5 without one
+ sbHtml.append("Reader Post")
+
+ // https://developers.google.com/chrome/mobile/docs/webview/pixelperfect
+ .append("")
+
+ // use "Open Sans" Google font
+ .append("")
+
+ .append("")
+ .append("")
+ .append(content)
+ .append("");
+
+ return sbHtml.toString();
+ }
+
+ private ImageSize getImageSize(final String imageTag, final String imageUrl) {
+ ImageSize size = getImageSizeFromAttachments(imageUrl);
+ if (size == null && imageUrl.contains("?")) {
+ size = getImageSizeFromQueryParams(imageUrl);
+ }
+ if (size == null && imageTag.contains("width=")) {
+ size = getImageSizeFromAttributes(imageTag);
+ }
+ return size;
+ }
+
+ private ImageSize getImageSizeFromAttachments(final String imageUrl) {
+ if (mAttachmentSizes == null) {
+ mAttachmentSizes = new ImageSizeMap(mPost.getAttachmentsJson());
+ }
+ return mAttachmentSizes.getAttachmentSize(imageUrl);
+ }
+
+ private ImageSize getImageSizeFromQueryParams(final String imageUrl) {
+ if (imageUrl.contains("w=")) {
+ Uri uri = Uri.parse(imageUrl.replace("&", "&"));
+ return new ImageSize(
+ StringUtils.stringToInt(uri.getQueryParameter("w")),
+ StringUtils.stringToInt(uri.getQueryParameter("h")));
+ } else if (imageUrl.contains("resize=")) {
+ Uri uri = Uri.parse(imageUrl.replace("&", "&"));
+ String param = uri.getQueryParameter("resize");
+ if (param != null) {
+ String[] sizes = param.split(",");
+ if (sizes.length == 2) {
+ return new ImageSize(
+ StringUtils.stringToInt(sizes[0]),
+ StringUtils.stringToInt(sizes[1]));
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private ImageSize getImageSizeFromAttributes(final String imageTag) {
+ return new ImageSize(
+ ReaderImageScanner.getWidthAttrValue(imageTag),
+ ReaderImageScanner.getHeightAttrValue(imageTag));
+ }
+
+ private int pxToDp(int px) {
+ if (px == 0) {
+ return 0;
+ }
+ return DisplayUtils.pxToDp(WordPress.getContext(), px);
+ }
+
+ /*
+ * javascript should only be enabled for wp blogs (not external feeds)
+ */
+ private boolean canEnableJavaScript() {
+ return mPost.isWP();
+ }
+
+ /*
+ * hash map of sizes of attachments in the current post for quick lookup - created from
+ * the json "attachments" section of the post endpoints
+ */
+ class ImageSizeMap extends HashMap {
+ ImageSizeMap(String jsonString) {
+ if (TextUtils.isEmpty(jsonString)) {
+ return;
+ }
+
+ try {
+ JSONObject json = new JSONObject(jsonString);
+ Iterator it = json.keys();
+ if (!it.hasNext()) {
+ return;
+ }
+
+ while (it.hasNext()) {
+ JSONObject jsonAttach = json.optJSONObject(it.next());
+ if (jsonAttach != null && JSONUtil.getString(jsonAttach, "mime_type").startsWith("image")) {
+ String normUrl = UrlUtils.normalizeUrl(UrlUtils.removeQuery(JSONUtil.getString(json, "URL")));
+ int width = jsonAttach.optInt("width");
+ int height = jsonAttach.optInt("height");
+ this.put(normUrl, new ImageSize(width, height));
+ }
+ }
+ } catch (JSONException e) {
+ AppLog.e(AppLog.T.READER, e);
+ }
+ }
+
+ ImageSize getAttachmentSize(final String imageUrl) {
+ if (imageUrl == null) {
+ return null;
+ } else {
+ return super.get(UrlUtils.normalizeUrl(UrlUtils.removeQuery(imageUrl)));
+ }
+ }
+ }
+
+ static class ImageSize {
+ final int width;
+ final int height;
+ ImageSize(int width, int height) {
+ this.width = width;
+ this.height = height;
+ }
+ }
+}
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderResourceVars.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderResourceVars.java
new file mode 100644
index 000000000000..03ac68be85b4
--- /dev/null
+++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/ReaderResourceVars.java
@@ -0,0 +1,75 @@
+package org.wordpress.android.ui.reader;
+
+import android.content.Context;
+import android.content.res.Resources;
+
+import org.wordpress.android.R;
+import org.wordpress.android.ui.WPActionBarActivity;
+import org.wordpress.android.util.DisplayUtils;
+import org.wordpress.android.util.HtmlUtils;
+
+/*
+ * class which holds all resource-based variables used when rendering post detail
+ */
+class ReaderResourceVars {
+ final int displayWidthPx;
+ final int actionBarHeightPx;
+ final int likeAvatarSizePx;
+
+ final int marginLargePx;
+ final int marginSmallPx;
+ final int marginExtraSmallPx;
+ final int listMarginWidthPx;
+
+ final int fullSizeImageWidthPx;
+ final int featuredImageHeightPx;
+
+ final int videoWidthPx;
+ final int videoHeightPx;
+
+ final int colorGreyExtraLight;
+ final int mediumAnimTime;
+
+ final String linkColorStr;
+ final String greyMediumDarkStr;
+ final String greyLightStr;
+ final String greyExtraLightStr;
+
+ ReaderResourceVars(Context context) {
+ Resources resources = context.getResources();
+
+ displayWidthPx = DisplayUtils.getDisplayPixelWidth(context);
+ actionBarHeightPx = DisplayUtils.getActionBarHeight(context);
+ likeAvatarSizePx = resources.getDimensionPixelSize(R.dimen.avatar_sz_small);
+ featuredImageHeightPx = resources.getDimensionPixelSize(R.dimen.reader_featured_image_height);
+
+ marginLargePx = resources.getDimensionPixelSize(R.dimen.margin_large);
+ marginSmallPx = resources.getDimensionPixelSize(R.dimen.margin_small);
+ marginExtraSmallPx = resources.getDimensionPixelSize(R.dimen.margin_extra_small);
+ listMarginWidthPx = resources.getDimensionPixelOffset(R.dimen.reader_list_margin);
+
+ colorGreyExtraLight = resources.getColor(R.color.grey_extra_light);
+ mediumAnimTime = resources.getInteger(android.R.integer.config_mediumAnimTime);
+
+ linkColorStr = HtmlUtils.colorResToHtmlColor(context, R.color.reader_hyperlink);
+ greyMediumDarkStr = HtmlUtils.colorResToHtmlColor(context, R.color.grey_medium_dark);
+ greyLightStr = HtmlUtils.colorResToHtmlColor(context, R.color.grey_light);
+ greyExtraLightStr = HtmlUtils.colorResToHtmlColor(context, R.color.grey_extra_light);
+
+ // full-size image width must take list margin and padding into account
+ int listPadding = resources.getDimensionPixelOffset(R.dimen.margin_large);
+ int imageWidth = displayWidthPx - (listMarginWidthPx * 2) - (listPadding * 2);
+ boolean hasStaticMenuDrawer =
+ (context instanceof WPActionBarActivity)
+ && (((WPActionBarActivity) context).isStaticMenuDrawer());
+ if (hasStaticMenuDrawer) {
+ int drawerWidth = resources.getDimensionPixelOffset(R.dimen.menu_drawer_width);
+ imageWidth -= drawerWidth;
+ }
+ fullSizeImageWidthPx = imageWidth;
+
+ // 16:9 ratio (YouTube standard)
+ videoWidthPx = fullSizeImageWidthPx - (marginLargePx * 2);
+ videoHeightPx = (int) (videoWidthPx * 0.5625f);
+ }
+}
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/reader/utils/ReaderImageScanner.java b/WordPress/src/main/java/org/wordpress/android/ui/reader/utils/ReaderImageScanner.java
index 3549e6f2930d..08173de03623 100644
--- a/WordPress/src/main/java/org/wordpress/android/ui/reader/utils/ReaderImageScanner.java
+++ b/WordPress/src/main/java/org/wordpress/android/ui/reader/utils/ReaderImageScanner.java
@@ -1,6 +1,7 @@
package org.wordpress.android.ui.reader.utils;
import android.net.Uri;
+import android.text.TextUtils;
import org.wordpress.android.ui.reader.models.ReaderImageList;
import org.wordpress.android.util.PhotonUtils;
@@ -12,13 +13,18 @@
public class ReaderImageScanner {
+ public static interface ImageScanListener {
+ public void onImageFound(String imageTag, String imageUrl, int start, int end);
+ public void onScanCompleted();
+ }
private final String mContent;
private final boolean mIsPrivate;
+ private final boolean mContentContainsImages;
private static final int MIN_FEATURED_IMAGE_WIDTH = 500;
// regex for matching img tags in html content
private static final Pattern IMG_TAG_PATTERN = Pattern.compile(
- "",
+ "",
Pattern.DOTALL| Pattern.CASE_INSENSITIVE);
// regex for matching width attributes in tags
@@ -26,6 +32,11 @@ public class ReaderImageScanner {
"width\\s*=\\s*(?:'|\")(.*?)(?:'|\")",
Pattern.DOTALL|Pattern.CASE_INSENSITIVE);
+ // regex for matching height attributes in tags
+ private static final Pattern HEIGHT_ATTR_PATTERN = Pattern.compile(
+ "height\\s*=\\s*(?:'|\")(.*?)(?:'|\")",
+ Pattern.DOTALL|Pattern.CASE_INSENSITIVE);
+
// regex for matching src attributes in tags
private static final Pattern SRC_ATTR_PATTERN = Pattern.compile(
"src\\s*=\\s*(?:'|\")(.*?)(?:'|\")",
@@ -34,15 +45,41 @@ public class ReaderImageScanner {
public ReaderImageScanner(String contentOfPost, boolean isPrivate) {
mContent = contentOfPost;
mIsPrivate = isPrivate;
+ mContentContainsImages = mContent != null && mContent.contains(" 0 && height > 0) {
- query = String.format("?w=%d&h=%d", width, height);
+ query = "?w=" + width + "&h=" + height;
} else if (width > 0) {
- query = String.format("?w=%d", width);
+ query = "?w=" + width;
} else if (height > 0) {
- query = String.format("?h=%d", height);
+ query = "?h=" + height;
} else {
query = "";
}
diff --git a/WordPress/src/main/res/layout/reader_listitem_post_detail.xml b/WordPress/src/main/res/layout/reader_listitem_post_detail.xml
index 3642f6314220..e346246e84d9 100644
--- a/WordPress/src/main/res/layout/reader_listitem_post_detail.xml
+++ b/WordPress/src/main/res/layout/reader_listitem_post_detail.xml
@@ -40,7 +40,7 @@
android:layout_marginBottom="@dimen/margin_small"
android:ellipsize="end"
android:maxLines="2"
- android:textColor="@color/reader_hyperlink"
+ android:textColor="@color/grey_dark"
android:textSize="@dimen/text_sz_medium"
tools:text="text_blog_name" />
diff --git a/WordPress/src/main/res/values/dimens.xml b/WordPress/src/main/res/values/dimens.xml
index 943037c2ca23..7fee4b237e47 100644
--- a/WordPress/src/main/res/values/dimens.xml
+++ b/WordPress/src/main/res/values/dimens.xml
@@ -68,7 +68,6 @@
340dp@dimen/reader_featured_image_height_default
- 48dp12dp@dimen/margin_large
diff --git a/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/PhotonUtils.java b/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/PhotonUtils.java
index 497d756ee377..bf275e56abdc 100644
--- a/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/PhotonUtils.java
+++ b/libs/utils/WordPressUtils/src/main/java/org/wordpress/android/util/PhotonUtils.java
@@ -24,7 +24,7 @@ public static String fixAvatar(final String imageUrl, int avatarSz) {
return getPhotonImageUrl(imageUrl, avatarSz, avatarSz);
// remove all other params, then add query string for size and "mystery man" default
- return UrlUtils.removeQuery(imageUrl) + String.format("?s=%d&d=mm", avatarSz);
+ return UrlUtils.removeQuery(imageUrl) + "?s=" + avatarSz + "&d=mm";
}
/*
@@ -64,18 +64,18 @@ public static String getPhotonImageUrl(String imageUrl, int width, int height) {
// see http://wp.tutsplus.com/tutorials/how-to-generate-website-screenshots-for-your-wordpress-site/
// ex: http://s.wordpress.com/mshots/v1/http%3A%2F%2Fnickbradbury.com?w=600
if (isMshotsUrl(imageUrl)) {
- return imageUrl + String.format("?w=%d&h=%d", width, height);
+ return imageUrl + "?w=" + width + "&h=" + height;
}
// if both width & height are passed use the "resize" param, use only "w" or "h" if just
// one of them is set, otherwise no query string
final String query;
if (width > 0 && height > 0) {
- query = String.format("?resize=%d,%d", width, height);
+ query = "?resize=" + width + "," + height;
} else if (width > 0) {
- query = String.format("?w=%d", width);
+ query = "?w=" + width;
} else if (height > 0) {
- query = String.format("?h=%d", height);
+ query = "?h=" + height;
} else {
query = "";
}